studio programacion herramientas fundamentos con avanzado aplicaciones android multithreading android-asynctask android-context

programacion - Comportamiento de contexto Android AsyncTask



manual de android en pdf (4)

He estado trabajando con AsyncTasks en Android y estoy lidiando con un problema.

Tome un ejemplo simple, una Actividad con una AsyncTask. La tarea en el fondo no hace nada espectacular, simplemente duerme durante 8 segundos.

Al final de AsyncTask en el método onPostExecute () solo estoy configurando el estado de visibilidad de un botón en View.VISIBLE, solo para verificar mis resultados.

Ahora, esto funciona de maravilla hasta que el usuario decida cambiar la orientación de su teléfono mientras está funcionando la AsyncTask (dentro de la ventana de espera de 8 segundos).

Entiendo el ciclo de vida de la actividad de Android y sé que la actividad se destruye y se vuelve a crear.

Aquí es donde aparece el problema. AsyncTask se refiere a un botón y aparentemente contiene una referencia al contexto que inició la AsyncTask en primer lugar.

Esperaría que este contexto anterior (ya que el usuario causó un cambio de orientación) se vuelva nulo y AsyncTask arroje un NPE para la referencia al botón que está tratando de hacer visible.

En su lugar, no se lanza ningún NPE, AsyncTask piensa que la referencia del botón no es nula, lo establece en visible. ¿El resultado? ¡No pasa nada en la pantalla!

Actualización: He abordado esto manteniendo una WeakReference a la actividad y cambiando cuando ocurre un cambio de configuración. Esto es engorroso.

Aquí está el código:

public class Main extends Activity { private Button mButton = null; private Button mTestButton = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mButton = (Button) findViewById(R.id.btnStart); mButton.setOnClickListener(new OnClickListener () { @Override public void onClick(View v) { new taskDoSomething().execute(0l); } }); mTestButton = (Button) findViewById(R.id.btnTest); } private class TaskDoSomething extends AsyncTask<Long, Integer, Integer> { @Override protected Integer doInBackground(Long... params) { Log.i("LOGGER", "Starting..."); try { Thread.sleep(8000); } catch (InterruptedException e) { e.printStackTrace(); } return 0; } @Override protected void onPostExecute(Integer result) { Log.i("LOGGER", "...Done"); mTestButton.setVisibility(View.VISIBLE); } } }

Intente ejecutarlo y mientras el AsyncTask está funcionando cambie la orientación de su teléfono.


AsyncTask no está diseñado para ser reutilizado una vez que una Actividad ha sido demolida y reiniciada. El objeto Handler interno se vuelve obsoleto, tal como lo indicó. En el ejemplo de Shelves de Romain Guy, él simplemente cancela cualquier AsyncTask actualmente en ejecución y luego reinicia los cambios de posorientación nuevos.

Es posible transferir el hilo a la nueva actividad, pero agrega mucha plomería. No existe una forma generalmente aceptada de hacerlo, pero puedes leer sobre mi método aquí: http://foo.jasonhudgins.com/2010/03/simple-progressbar-tutorial.html


Este es el tipo de cosas que me llevan a evitar siempre que mi Actividad sea destruida / recreada en el cambio de orientación.

Para hacerlo, agregue esto a su etiqueta <Activity> en su archivo de manifiesto:

android:configChanges="orientation|keyboardHidden"

Y anula onConfigurationChanged en tu clase de actividad:

@Override public void onConfigurationChanged(final Configuration newConfig) { // Ignore orientation change to keep activity from restarting super.onConfigurationChanged(newConfig); }


Para evitar esto, puede usar la respuesta dada aquí: https://.com/a/2124731/327011

Pero si necesita destruir la actividad (diferentes diseños para retrato y paisaje) puede hacer que AsyncTask sea una clase pública (Lea aquí por qué no debería ser Android privado : recomendaciones de AsyncTask: ¿clase privada o clase pública? ) Y luego cree una método setActivity para establecer la referencia a la actividad actual cada vez que se destruye / crea.

Puede ver un ejemplo aquí: Android AsyncTask en clase externa


Si solo necesita un contexto y no lo va a usar para cosas ui, simplemente puede pasar el ApplicationContext a su AsyncTask. A menudo necesita el contexto para los recursos del sistema, por ejemplo.

No intente actualizar la interfaz de usuario desde una AsyncTask y trate de evitar el manejo de los cambios de configuración, ya que puede complicarse. Para actualizar la interfaz de usuario, puede registrar un receptor de difusión y enviar una transmisión.

También debe tener AsyncTask como una clase pública separada de la actividad mencionada anteriormente, hace que las pruebas sean mucho más fáciles. Lamentablemente, la programación de Android a menudo refuerza las malas prácticas y los ejemplos oficiales no ayudan.