2012-08-24 24 views
9

He visto algunas preguntas casi idénticas a las mías, pero no pude encontrar una respuesta completa que satisfaga todas mis dudas ... así que aquí estoy ... Supongamos que tienes una actividad con una clase interna que amplía la clase AsyncTask de esta manera:¿Qué le sucede a una AsyncTask cuando se detiene/destruye la actividad de inicio mientras aún está en ejecución?

public class MyActivity extends Activity {    
    private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { 
     protected Bitmap doInBackground(String... urls) { 
      return DownloadImage(urls[0]); 
     } 
     protected void onPostExecute(Bitmap result) { 
      ImageView img = (ImageView) findViewById(R.id.img); 
      img.setImageBitmap(result); 
     } 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     new DownloadImageTask().execute("http://mysite.com/image.png") 
    } 
} 

Supongamos que la actividad está en pausa o destruido (tal vez los dos casos son diferentes), mientras que el DownloadImageTask todavía se está ejecutando en segundo plano .. entonces, los métodos 's la DownloadImageTask que se ejecutan en el subproceso de interfaz de usuario de la actividad puede activarse y el DownloadImageTask puede intentar acceder a los métodos de Activity (es una clase interna, por lo que puede acceder a los métodos y variables de instancia de la clase externa) con una Actividad pausada o destruida, como la llamada a findViewByID en el siguiente ejemplo ... ¿qué pasa entonces? ¿Silenciosamente falla? ¿Produce alguna excepción? ¿Se notificará al usuario que algo salió mal?

Si deberíamos tener cuidado de que el hilo de inicio (la Actividad en este caso) todavía está vivo cuando se invocan los métodos de ejecución en la interfaz de usuario, ¿cómo podemos lograr eso desde el AsyncTask?

Lo siento si encuentra esto como una pregunta duplicado, pero tal vez esta pregunta es un poco más articulada y alguien puede responder con mayor detalle

+1

Cuando ejecutó este código, ¿silenció silenciosamente, produjo alguna excepción o notificó al usuario que algo salió mal? – CommonsWare

+0

Aún no he ejecutado un código así, lo haré en los próximos días. Me lo pregunté antes de continuar con la implementación de mi aplicación. Actualizaré esta publicación tan pronto como pueda ejecutar una prueba.Gracias @CommonsWare –

+1

Mi punto es que el comportamiento no está documentado, particularmente dado el hecho de que no estamos viendo nada más en la actividad. 'findViewById()' puede devolver 'null' para' R.id.img', o puede que no. Y ese comportamiento podría variar de un dispositivo a otro, según la versión del sistema operativo Android, las modificaciones del fabricante del dispositivo y las modificaciones del ROM. – CommonsWare

Respuesta

3

Considere esta tarea (donde R.id.test se refiere a una Ver válido en el diseño de mi actividad):

public class LongTaskTest extends AsyncTask<Void, Void, Void>{ 
    private WeakReference<Activity> mActivity; 
    public LongTaskTest(Activity a){ 
     mActivity = new WeakReference<Activity>(a); 
    } 
    @Override protected Void doInBackground(Void... params) { 
     LogUtil.d("LongTaskTest.doInBackground()"); 
     SystemClock.sleep(5*60*1000); 
     LogUtil.d("mActivity.get()==null " + (mActivity.get()==null)); 
     LogUtil.d("mActivity.get().findViewById(R.id.frame)==null " + (mActivity.get().findViewById(R.id.test)==null)); 
     return null; 
    } 
} 

Si me quedo esta tarea desde onCreate de una actividad de este modo:

public class Main extends Activity { 
    @Override 
    public void onCreate(Bundle state) { 
     super.onCreate(state); 
     setContentView(R.layout.testlayout); 
     new LongTaskTest(this).execute(); 
     finish(); 
    } 
} 

No importa el tiempo que duermo el fondo hilo, mi registro siempre muestra:

LongTaskTest.doInBackground() 
mActivity.get()==null false 
mActivity.get().findViewById(R.id.frame)==null false 

Lo que quiere decir que la actividad y sus puntos de vista parecen mantenerse con vida (incluso si expido manualmente a través de los GC DDMS). Si tuviera más tiempo me vería en un volcado de memoria, pero por lo demás no se sabe muy bien por qué este es el caso ... pero en respuesta a sus preguntas se observe que:

  • lo hace silenciosamente fallar? No
  • ¿Existe alguna excepción? No
  • ¿Se notificará al usuario que algo salió mal? No
+0

La actividad todavía puede estar allí porque su clase interna tiene una referencia a ella, pero ¿qué hay de las vistas y variables de instancia en él? – user412759

+0

Es por eso que utilicé una WeakReference to Activity ... para asegurarme de que mi clase interna no fuera la razón por la cual la actividad se mantenía viva. En cuanto a las vistas y las variables de instancia, mi clase interna no tiene ninguna excepto la WeakReference to Activity. ¿A menos que quieras decir algo más? más en WeakReference: http://developer.android.com/reference/java/lang/ref/WeakReference.html – newbyca

+3

@newbyca Si, de hecho, 'LongTaskTest' es una clase interna, entonces tiene una referencia implícita a la actividad que se está olvidando, conviértalo en una clase anidada estática: http://stackoverflow.com/questions/70324/java-inner-class-and-static-nested-class – MattJenko

2

El doInBackground() seguirá funcionando incluso si su actividad se destruye (i, e su hilo principal se destruye) porque el método doInBackground() se ejecuta en el subproceso del trabajador/fondo. Habrá un "problema" al ejecutar el método onPostExecute() ya que se ejecuta en el subproceso principal/IU y es posible que experimente la ejecución de datos no relacionados, pero no se mostrará ninguna excepción al usuario. Por lo tanto, siempre es mejor cancelar su AsyncTask cuando se destruye su actividad ya que no hay ninguna razón para ejecutar AsyncTask cuando la Actividad ya no está presente. Utilice el servicio de Android si desea descargar algo continuamente de la red, incluso cuando su componente/actividad se destruya. Gracias.

Cuestiones relacionadas