Schreiben von reaktionsfähigen Anwendungen

Einer der Schlüssel zum Verwalten einer reaktionsfähigen GUI besteht darin, Aufgaben mit langer Ausführungsdauer in einem Hintergrundthread auszuführen, damit die GUI nicht blockiert wird. Angenommen, wir möchten einen Wert berechnen, der für den Benutzer angezeigt werden soll, aber für diesen Wert dauert die Berechnung 5 Sekunden:

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";
    }
}

Dies funktioniert, aber die Anwendung "hängt" 5 Sekunden lang, während der Wert berechnet wird. Während dieser Zeit reagiert die App nicht auf Benutzerinteraktionen. Um dies zu umgehen, möchten wir unsere Berechnungen in einem Hintergrundthread ausführen:

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";
    }
}

Jetzt berechnen wir den Wert in einem Hintergrundthread, sodass unsere GUI während der Berechnung reaktionsfähig bleibt. Wenn die Berechnung jedoch abgeschlossen ist, stürzt unsere App ab, und dies bleibt im Protokoll:

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 ()

Dies liegt daran, dass Sie die GUI aus dem GUI-Thread aktualisieren müssen. Unser Code aktualisiert die GUI aus dem ThreadPool-Thread, sodass die App abstürzt. Wir müssen unseren Wert für den Hintergrundthread berechnen, aber dann unsere Aktualisierung für den GUI-Thread durchführen, der mit Activity.RunOnUIThread behandelt wird:

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");
    }
}

Dieser Code funktioniert wie erwartet. Diese GUI bleibt reaktionsfähig und wird ordnungsgemäß aktualisiert, sobald die Berechnung erstellt wurde.

Beachten Sie, dass diese Technik nicht nur zum Berechnen eines teuren Werts verwendet wird. Es kann für alle Aufgaben mit langer Ausführungsdauer verwendet werden, die im Hintergrund ausgeführt werden können, z. B. für einen Webdienstaufruf oder das Herunterladen von Internetdaten.