Zápis reagujících aplikací
Jedním z klíčů, které udržují grafické uživatelské rozhraní, je spuštění dlouhotrvajících úloh ve vlákně na pozadí, aby grafické uživatelské rozhraní nebylo blokované. Řekněme, že chceme vypočítat hodnotu, která se zobrazí uživateli, ale tato hodnota trvá 5 sekund, než se vypočítá:
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";
}
}
Tato akce bude fungovat, ale aplikace bude během výpočtu hodnoty "zablokovat" po dobu 5 sekund. Během této doby aplikace nebude reagovat na interakci s uživatelem. Chcete-li se tomuto problému vyhnout, chceme provést 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";
}
}
Nyní vypočítáme hodnotu v vlákně na pozadí, aby náš grafický objekt GUI během výpočtu zůstával reagovat. Když se ale provede výpočet, dojde k chybě naší aplikace, ale v protokolu dojde k chybě:
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 ()
Důvodem je, že je nutné 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 podprocesu, což způsobí selhání aplikace. Musíme vypočítat naši hodnotu ve vlákně na pozadí, ale potom provést naši aktualizaci ve vlákně GUI, 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ůstává po komplei a po dokončení výpočtu správně aktualizováno.
Poznámka: Tato technika se nepoužívá jenom pro výpočet nákladných hodnot. Dá se použít pro libovolnou dlouhodobě běžící úlohu, kterou je možné provést na pozadí, jako je například volání webové služby nebo stahování internetových dat.