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.