J'ai travaillé avec AsyncTasks dans Android et je suis confronté à un problème.
Prenons un exemple simple, une activité avec une AsyncTask. La tâche en arrière-plan ne fait rien de spectaculaire, elle se contente de dormir pendant 8 secondes.
À la fin de l'AsyncTask, dans la méthode onPostExecute(), je ne fais que définir l'état de visibilité d'un bouton sur View.VISIBLE, uniquement pour vérifier mes résultats.
Cela fonctionne très bien jusqu'à ce que l'utilisateur décide de changer l'orientation de son téléphone pendant que l'AsyncTask fonctionne (dans la fenêtre de sommeil de 8 secondes).
Je comprends le cycle de vie des activités Android et je sais que l'activité est détruite et recréée.
C'est là que le problème se pose. L'AsyncTask fait référence à un bouton et détient apparemment une référence au contexte qui a lancé l'AsyncTask en premier lieu.
Je m'attendrais à ce que cet ancien contexte (puisque l'utilisateur a provoqué un changement d'orientation) devienne nul et que l'AsyncTask lance un NPE pour la référence au bouton qu'il essaie de rendre visible.
Au lieu de cela, aucun NPE n'est déclenché, l'AsyncTask pense que la référence du bouton n'est pas nulle, et la rend visible. Le résultat ? Rien ne se passe à l'écran !
Mise à jour : J'ai abordé ce problème en gardant un WeakReference
à l'activité et à la commutation lorsqu'un changement de configuration se produit. Cette méthode est lourde.
Voici le code :
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);
}
}
}
Essayez de l'exécuter et pendant que l'AsyncTask fonctionne, changez l'orientation de votre téléphone.