Pisanie dynamicznych aplikacji
Jednym z kluczy do obsługi dynamicznego graficznego interfejsu użytkownika jest wykonywanie długotrwałych zadań w wątku w tle, dzięki czemu graficzny interfejs użytkownika nie zostanie zablokowany. Załóżmy, że chcemy obliczyć wartość wyświetlaną użytkownikowi, ale obliczenie tej wartości trwa 5 sekund:
public class ThreadDemo : Activity
{
TextView textview;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Create a new TextView and set it as our view
textview = new TextView (this);
textview.Text = "Working..";
SetContentView (textview);
SlowMethod ();
}
private void SlowMethod ()
{
Thread.Sleep (5000);
textview.Text = "Method Complete";
}
}
Będzie to działać, ale aplikacja będzie "zawieszać się" przez 5 sekund podczas obliczania wartości. W tym czasie aplikacja nie będzie reagować na żadną interakcję użytkownika. Aby obejść ten temat, chcemy wykonać obliczenia w wątku w tle:
public class ThreadDemo : Activity
{
TextView textview;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Create a new TextView and set it as our view
textview = new TextView (this);
textview.Text = "Working..";
SetContentView (textview);
ThreadPool.QueueUserWorkItem (o => SlowMethod ());
}
private void SlowMethod ()
{
Thread.Sleep (5000);
textview.Text = "Method Complete";
}
}
Teraz obliczamy wartość wątku w tle, aby nasz graficzny interfejs użytkownika odpowiadał podczas obliczeń. Jednak po zakończeniu obliczeń nasza aplikacja ulega awarii, pozostawiając ją w dzienniku:
E/mono (11207): EXCEPTION handling: Android.Util.AndroidRuntimeException: Exception of type 'Android.Util.AndroidRuntimeException' was thrown.
E/mono (11207):
E/mono (11207): Unhandled Exception: Android.Util.AndroidRuntimeException: Exception of type 'Android.Util.AndroidRuntimeException' was thrown.
E/mono (11207): at Android.Runtime.JNIEnv.CallVoidMethod (IntPtr jobject, IntPtr jmethod, Android.Runtime.JValue[] parms)
E/mono (11207): at Android.Widget.TextView.set_Text (IEnumerable`1 value)
E/mono (11207): at MonoDroidDebugging.Activity1.SlowMethod ()
Dzieje się tak, ponieważ należy zaktualizować graficzny interfejs użytkownika z wątku graficznego interfejsu użytkownika. Nasz kod aktualizuje graficzny interfejs użytkownika z wątku ThreadPool, powodując awarię aplikacji. Musimy obliczyć naszą wartość w wątku w tle, ale następnie wykonać aktualizację wątku graficznego interfejsu użytkownika, który jest obsługiwany za pomocą elementu Activity.RunOnUIThread:
public class ThreadDemo : Activity
{
TextView textview;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Create a new TextView and set it as our view
textview = new TextView (this);
textview.Text = "Working..";
SetContentView (textview);
ThreadPool.QueueUserWorkItem (o => SlowMethod ());
}
private void SlowMethod ()
{
Thread.Sleep (5000);
RunOnUiThread (() => textview.Text = "Method Complete");
}
}
Ten kod działa zgodnie z oczekiwaniami. Ten graficzny interfejs użytkownika pozostaje dynamiczny i jest prawidłowo aktualizowany po zakończeniu obliczeń.
Należy pamiętać, że ta technika nie jest po prostu używana do obliczania kosztownej wartości. Można go używać w przypadku dowolnego długotrwałego zadania, które można wykonać w tle, na przykład wywołania usługi internetowej lub pobierania danych internetowych.