Escritura de aplicaciones con capacidad de respuesta
Una de las claves para mantener una GUI con capacidad de respuesta es realizar tareas de ejecución larga en un subproceso en segundo plano para que la GUI no se bloquee. Supongamos que queremos calcular un valor para mostrarlo al usuario, pero ese valor tarda 5 segundos en calcularse:
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";
}
}
Esto funcionará, pero la aplicación se "desancha" durante 5 segundos mientras se calcula el valor. Durante este tiempo, la aplicación no responderá a ninguna interacción del usuario. Para evitarlo, queremos realizar nuestros cálculos en un subproceso en segundo plano:
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";
}
}
Ahora calculamos el valor en un subproceso en segundo plano para que nuestra GUI permanezca respondiendo durante el cálculo. Sin embargo, cuando se realiza el cálculo, la aplicación se bloquea, dejando esto en el registro:
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 ()
Esto se debe a que debe actualizar la GUI desde el subproceso de gui. Nuestro código actualiza la GUI desde el subproceso ThreadPool, lo que hace que la aplicación se bloquea. Es necesario calcular nuestro valor en el subproceso en segundo plano, pero luego realizar la actualización en el subproceso de gui, que se controla con 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");
}
}
Este código funciona según lo previsto. Esta GUI sigue respondiendo y se actualiza correctamente una vez que el cálculo es completo.
Tenga en cuenta que esta técnica no solo se usa para calcular un valor costoso. Se puede usar para cualquier tarea de ejecución larga que se pueda realizar en segundo plano, como una llamada de servicio web o la descarga de datos de Internet.