Actualizar la interfaz de usuario desde el hilo

Quiero actualizar mi UI desde un subproceso que actualiza una barra de progreso. Lamentablemente, al actualizar el dibujable de la barra de progreso del “ejecutable”, la barra de progreso desaparece. ¡Cambiar el onCreate() de onCreate() en onCreate() en el otro lado funciona!

¿Alguna sugerencia?

 public void onCreate(Bundle savedInstanceState) { res = getResources(); super.onCreate(savedInstanceState); setContentView(R.layout.gameone); pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); //**Works**/ handler.postDelayed(runnable, 1); } private Runnable runnable = new Runnable() { public void run() { runOnUiThread(new Runnable() { public void run() { //* The Complete ProgressBar does not appear**/ pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); } }); } } 

Debería hacer esto con la ayuda de AsyncTask (un hilo de fondo inteligente) y ProgressDialog

AsyncTask permite el uso adecuado y fácil del subproceso de interfaz de usuario. Esta clase permite realizar operaciones en segundo plano y publicar resultados en el subproceso de la interfaz de usuario sin tener que manipular subprocesos y / o controladores.

Una tarea asíncrona se define mediante un cálculo que se ejecuta en un subproceso en segundo plano y cuyo resultado se publica en el subproceso de la interfaz de usuario. Una tarea asincrónica está definida por 3 tipos generics, llamados Params, Progress y Result, y 4 pasos, llamados begin, doInBackground, processProgress y end.

Los 4 pasos

Cuando se ejecuta una tarea asíncrona, la tarea pasa por 4 pasos:

onPreExecute() , invocado en el subproceso de la interfaz de usuario inmediatamente después de que se ejecuta la tarea. Este paso se usa normalmente para configurar la tarea, por ejemplo, al mostrar una barra de progreso en la interfaz de usuario.

doInBackground(Params...) , invocado en el hilo de fondo inmediatamente después de onPreExecute () termina de ejecutarse. Este paso se usa para realizar un cálculo de fondo que puede llevar mucho tiempo. Los parámetros de la tarea asíncrona se pasan a este paso. El resultado del cálculo debe ser devuelto por este paso y será devuelto al último paso. Este paso también puede usar publishProgress (Progress …) para publicar una o más unidades de progreso. Estos valores se publican en el subproceso UI, en el paso onProgressUpdate (Progreso …).

onProgressUpdate(Progress...) , invocado en el hilo de UI después de una llamada a publishProgress (Progress …). El momento de la ejecución no está definido. Este método se usa para mostrar cualquier forma de progreso en la interfaz de usuario mientras el cálculo de fondo aún se está ejecutando. Por ejemplo, se puede usar para animar una barra de progreso o mostrar registros en un campo de texto.

onPostExecute(Result) , invocado en el hilo de la interfaz de usuario una vez que finaliza el cálculo de fondo. El resultado del cálculo de fondo se pasa a este paso como un parámetro. Enhebrar las reglas

Hay algunas reglas de enhebrado que se deben seguir para que esta clase funcione correctamente:

La instancia de la tarea debe crearse en el hilo de la interfaz de usuario. execute (Params …) debe invocarse en el subproceso UI. No invoque onPreExecute (), onPostExecute (Result), doInBackground (Params …), onProgressUpdate (Progress …) manualmente. La tarea se puede ejecutar solo una vez (se lanzará una excepción si se intenta una segunda ejecución).

Código de ejemplo
Lo que hace el adaptador en este ejemplo no es importante, es más importante entender que debe usar AsyncTask para mostrar un diálogo para el progreso.

 private class PrepareAdapter1 extends AsyncTask { ProgressDialog dialog; @Override protected void onPreExecute() { dialog = new ProgressDialog(viewContacts.this); dialog.setMessage(getString(R.string.please_wait_while_loading)); dialog.setIndeterminate(true); dialog.setCancelable(false); dialog.show(); } /* (non-Javadoc) * @see android.os.AsyncTask#doInBackground(Params[]) */ @Override protected ContactsListCursorAdapter doInBackground(Void... params) { cur1 = objItem.getContacts(); startManagingCursor(cur1); adapter1 = new ContactsListCursorAdapter (viewContacts.this, R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {}); return adapter1; } protected void onPostExecute(ContactsListCursorAdapter result) { list.setAdapter(result); dialog.dismiss(); } } 

La solución más simple que he visto para proporcionar una ejecución corta al hilo de la interfaz de usuario es a través del método post () de una vista. Esto es necesario ya que los métodos de IU no son reentrantes. El método para esto es:

 package android.view; public class View; public boolean post(Runnable action); 

El método post () corresponde a SwingUtilities.invokeLater (). Desafortunadamente, no encontré nada simple que se corresponda con SwingUtilities.invokeAndWait (), pero uno puede construir el más reciente basado en el primero con un monitor y un indicador.

Entonces, lo que ahorras con esto es crear un controlador. Simplemente necesita encontrar su vista y luego publicarla en ella. Puede encontrar su vista a través de findViewById () si tiende a trabajar con recursos id-ed. El código resultante es muy simple:

 /* inside your non-UI thread */ view.post(new Runnable() { public void run() { /* the desired UI update */ } }); } 

Nota: Comparado con SwingUtilities.invokeLater (), el método View.post () devuelve un valor booleano, que indica si la vista tiene una cola de eventos asociada. Desde que utilicé el invokeLater () resp. publicar () de todos modos solo para disparar y olvidar, no verifiqué el valor del resultado. Básicamente, debe llamar a la publicación () solo después de haber llamado a AttachedToWindow () en la vista.

Atentamente

Si usa Handler (veo que lo hace y espero que haya creado su instancia en el hilo de UI), entonces no use runOnUiThread() dentro de su runnable . runOnUiThread() se usa cuando se hace smth desde un hilo que no sea UI, sin embargo, Handler ya ejecutará su runnable en el hilo de UI.

Intenta hacer algo así:

 private Handler mHandler = new Handler(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gameone); res = getResources(); // pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); **//Works** mHandler.postDelayed(runnable, 1); } private Runnable runnable = new Runnable() { public void run() { pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); pB.invalidate(); // maybe this will even not needed - try to comment out } }; 

Use la clase AsyncTask (en lugar de Runnable). Tiene un método llamado onProgressUpdate que puede afectar a la interfaz de usuario (se invoca en el hilo de la interfaz de usuario).

Necesita crear un Handler en el hilo de la interfaz de usuario y luego usarlo para publicar o enviar un mensaje de su otro hilo para actualizar la interfaz de usuario

Si no te gusta AsyncTask, puedes usar el patrón de observador . En ese ejemplo, use ResponseHandler como una clase interna en su actividad y luego tenga un mensaje de cadena que establecerá el porcentaje de barras de progreso … Debería asegurarse de que cualquier alteración en la UI se realice dentro del ResponseHandler para evitar congelar el UI, entonces su hilo de trabajo (EventSource en el ejemplo) puede realizar las tareas requeridas.

Yo usaría el AsyncTask aunque, sin embargo, el patrón del observador puede ser bueno por razones de personalización, además es más fácil de entender. Además, no estoy seguro si esta forma es ampliamente aceptada o funcionará al 100%. Estoy descargando y el complemento de Android ahora para probarlo

Según lo recomendado por la documentación oficial, puede usar AsyncTask para manejar elementos de trabajo de menos de 5 ms de duración . Si su tarea toma más tiempo, busque otras alternativas.

HandlerThread es una alternativa a Thread o AsyncTask . Si necesita actualizar la interfaz de usuario desde HandlerThread , publique un mensaje en UI Thread Looper y UI Thread Handler puede manejar actualizaciones de UI.

Código de ejemplo:

Android: brindis en un hilo