Psaní responzivních aplikací
Jedním z klíčů pro udržování responzivního grafického uživatelského rozhraní je provádění dlouhotrvajících úloh ve vlákně na pozadí, aby grafické uživatelské rozhraní nebylo blokováno. Řekněme, že chceme vypočítat hodnotu, která se má uživateli zobrazit, ale výpočet této hodnoty trvá 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";
}
}
Bude to fungovat, ale aplikace během výpočtu hodnoty přestane reagovat po dobu 5 sekund. Během této doby nebude aplikace reagovat na žádnou interakci uživatele. Abychom to mohli obejít, chceme provádět výpočty na vlákně na pozadí:
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";
}
}
Teď vypočítáme hodnotu ve vlákně na pozadí, takže naše grafické uživatelské rozhraní zůstane během výpočtu responzivní. Po dokončení výpočtu se ale naše aplikace chybově ukončí a zůstane v protokolu:
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 ()
Je to proto, že musíte aktualizovat grafické uživatelské rozhraní z vlákna grafického uživatelského rozhraní. Náš kód aktualizuje grafické uživatelské rozhraní z vlákna ThreadPool, což způsobuje chybové ukončení aplikace. Musíme vypočítat naši hodnotu ve vlákně na pozadí, ale pak provést aktualizaci ve vlákně grafického uživatelského rozhraní, které se zpracovává pomocí 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");
}
}
Tento kód funguje podle očekávání. Toto grafické uživatelské rozhraní zůstane responzivní a po kompilaci výpočtu se správně aktualizuje.
Všimněte si, že tato technika se nepoužívá jenom k výpočtu nákladné hodnoty. Dá se použít pro všechny dlouhotrvající úlohy, které je možné provádět na pozadí, jako je volání webové služby nebo stahování dat z internetu.