Pregunta

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

poner un ejemplo sencillo, una actividad con una AsyncTask. La tarea en el fondo no hace nada espectacular, sólo se duerme durante 8 segundos.

Al final de la AsyncTask en el onPostExecute () método que estoy sólo la creación de un estado de visibilidad botón para View.VISIBLE, sólo para verificar mis resultados.

Ahora, esto funciona muy bien hasta que el usuario decide cambiar su orientación celulares mientras se está trabajando el AsyncTask (dentro de la segunda ventana 8 del sueño).

Me entender el ciclo de vida de la actividad Android y sé que la actividad se destruye y se recrea.

Aquí es donde viene el problema. El AsyncTask se refiere a un botón y al parecer mantiene una referencia al contexto en el que comenzó la AsyncTask en el primer lugar.

Yo esperaría, que este contexto de edad (ya que el usuario provocó un cambio de orientación) para convertirse ya sea nula y la AsyncTask para lanzar una NPE para la referencia al botón que está tratando de hacer visible.

En lugar de ello, sin NPE es lanzada, la AsyncTask piensa que la referencia botón no es nulo, lo establece en visible. ¿El resultado? Nada de lo que está sucediendo en la pantalla!

Actualización: I han abordado esto manteniendo un WeakReference a la actividad y de conmutación cuando un cambio de configuración sucede. 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);
        }
    }
}

Trate de ejecutarlo y mientras el AsyncTask está trabajando el cambio de su orientación móviles.

¿Fue útil?

Solución

AsyncTask no está diseñado para ser reutilizado una vez que la actividad ha sido derribado y se reinicia. El objeto interno Handler se vuelve rancio, al igual que lo indicado. En el ejemplo estantes por Romain individuo, cancele cualquier simples actualmente en ejecución de AsyncTask y reinicia los nuevos post-orientación cambio.

Es posible mano de la rosca a la nueva actividad, pero se añade una gran cantidad de fontanería. No hay una forma generalmente aceptada de hacer esto, pero se puede leer acerca de mi método aquí: http://foo.jasonhudgins.com/2010/03/simple-progressbar-tutorial.html

Otros consejos

Si sólo necesita un contexto y no va a usar para la interfaz de usuario Usted puede simplemente pasar el Application Context a su AsyncTask.You a menudo necesitan el contexto de los recursos del sistema, por ejemplo.

No trate de actualizar la interfaz de usuario de un AsyncTask y tratar de evitar la manipulación de la configuración cambia a sí mismo, ya que puede causar problemas. Con el fin de actualizar la interfaz de usuario podría registrar un receptor de radiodifusión y enviar un Broadcast.

También debe tener la AsyncTask como una clase pública independiente de la actividad como se mencionó anteriormente, hace que las pruebas mucho más fácil. Por desgracia la programación Android menudo refuerza las malas prácticas y los ejemplos oficiales no están ayudando.

Este es el tipo de cosa que me lleva a mi siempre impiden la actividad de la destrucción / recreada en el cambio de orientación.

Para hacerlo añadir esto a su etiqueta de <Activity> en el archivo de manifiesto:

android:configChanges="orientation|keyboardHidden" 

Y anulación onConfigurationChanged en su clase de actividad:

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

Para evitar esto se puede utilizar el Givin respuesta aquí: https://stackoverflow.com/a/2124731/327011

Pero si usted necesita para destruir la actividad (diferentes diseños para vertical y horizontal) puede hacer que el AsyncTask una clase pública (Lea aquí por qué no debería ser privada Android: recomendaciones AsyncTask:? clase privada o pública clase) y luego crear un setActivity método para establecer la referencia a la actual siempre que la actividad se destruye / creado.

Se puede ver un ejemplo aquí: Android AsyncTask en la clase externa

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top