共用方式為


撰寫回應式應用程式

維護回應式 GUI 的其中一個金鑰是在背景線程上執行長時間執行的工作,因此 GUI 不會遭到封鎖。 假設我們想要計算要向使用者顯示的值,但該值需要 5 秒才能計算:

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

這會正常運作,但應用程式會在計算值時「停止回應」5 秒。 在此期間,應用程式不會回應任何用戶互動。 為了解決這個問題,我們想要在背景線程上執行計算:

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

現在,我們會計算背景線程上的值,讓 GUI 在計算期間保持回應。 不過,當計算完成時,我們的應用程式會當機,並將它留在記錄檔中:

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

這是因為您必須從 GUI 線程更新 GUI。 我們的程式代碼會從 ThreadPool 線程更新 GUI,導致應用程式當機。 我們需要在背景線程上計算我們的值,但在 GUI 線程上執行更新,這會使用 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");
    }
}

此程式代碼如預期般運作。 一旦計算完成,此 GUI 會保持回應並正確更新。

請注意,這項技術不只是用於計算昂貴的值。 它可用於可在背景中完成的任何長時間執行工作,例如 Web 服務呼叫或下載因特網數據。