O que acontece com um AsyncTask quando a atividade de lançamento é interrompida / destruída enquanto ainda está em execução?

9

Eu já vi algumas perguntas quase idênticas às minhas, mas não consegui encontrar uma resposta completa que satisfizesse todas as minhas dúvidas ... então aqui estou ... Suponha que você tenha uma atividade com uma classe interna que estenda o AsyncTask class assim:

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")
    }
}

Suponha que a atividade esteja pausada ou destruída (talvez os dois casos sejam diferentes) enquanto o DownloadImageTask ainda estiver em execução em segundo plano. Em seguida, os métodos do DownloadImageTask executados no thread da interface do usuário da atividade podem ser acionados e o DownloadImageTask pode tentar acessar os métodos do Activity (é uma classe interna, para acessar os métodos e variáveis de instâncias da classe externa) com uma Activity pausada ou destruída, como a chamada para findViewByID no exemplo abaixo .. O que acontece depois? Isso silenciosamente falha? Produz alguma exceção? O usuário será notificado de que algo deu errado?

Se devemos tomar cuidado para que o encadeamento de ativação (a Atividade, neste caso) ainda esteja ativo quando os métodos de execução na interface do usuário sejam invocados, como podemos realizá-lo a partir do AsyncTask ?

Sinto muito se você achar isso como uma pergunta duplicada, mas talvez essa pergunta seja um pouco mais articulada e alguém possa responder com mais detalhes

    
por Gianni Costanzi 24.08.2012 в 23:41
fonte

2 respostas

3

Considere esta Tarefa (onde o R.id.test se refere a uma visão válida no layout da minha atividade):

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;
    }
}

Se eu executar essa tarefa a partir do onCreate de uma Activity da seguinte forma:

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

Não importa quanto tempo durmo o segmento de plano de fundo, meu log sempre mostra:

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

O que significa que a atividade e suas visualizações parecem permanecer ativas (mesmo que eu emita manualmente os GCs via DDMS). Se eu tivesse mais tempo, eu olharia para um despejo de memória, mas, caso contrário, eu realmente não sei por que este é o caso ... mas em resposta às suas perguntas parece que:

  • Isso falha silenciosamente? Não
  • Produz alguma exceção? Não
  • O usuário será notificado de que algo deu errado? Não
por newbyca 04.09.2012 / 18:10
fonte
2

O doInBackground () continuará funcionando mesmo que sua Activity seja destruída (pois seu thread principal é destruído) porque o método doInBackground () é executado no thread do worker / background. Haverá um 'problema' ao executar o método onPostExecute () enquanto ele é executado no thread principal / UI e você pode encontrar dados não relacionados, mas não haverá nenhuma exceção mostrada ao usuário. Assim, é sempre melhor cancelar seu AsyncTask quando sua atividade é destruída, pois não há razão para executar o AsyncTask quando a Activity não está mais presente. Use o serviço android se você deseja continuamente fazer o download de algo da rede, mesmo quando seu componente / atividade é destruído. Obrigado.

    
por Kaveesh Kanwal 18.04.2015 / 12:21
fonte