J'ai lu quelques questions ici, quelques articles dans Internet, mais la question sur les fuites de mémoire dans AsyncTask n'est pas claire pour moi. S'il vous plaît, pouvez-vous me donner un conseil?
Examinons quelques-unes des situations:
1) AsyncTask est une classe interne
Je vous écris MyAsyncTask pour le téléchargement de petites données à partir du serveur (< 1 Ko) dans le code MyActivity (pas de classe statique). Il va stocker une référence implicite à l'instance MyActivity. Et si je vais démarrer MyAsyncTask.execute(), l'instance de MyActivity ne peut pas être récupérée, tant que cette tâche AsyncTask ne sera pas terminée. Donc, si je vais faire pivoter l'écran pendant l'exécution d'AsyncTask, alors l'ancienne instance MyActivity sera en mémoire - et c'est une fuite de mémoire. Ce que j'ai décidé de faire: en raison de la taille de mes données à télécharger, j'annulerai mon AsyncTask dans la méthode onDestroy() dans MyActivity. De cette façon, j'ai un tel code de MyActivity:
Android asyncTask mémoire fuit
public class MyActivity extends Activity {
//views and constants
private MyAsyncTask air;
private ProgressDialog progressDialog;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.account_info_layout);
progressDialog = new ProgressDialog(this);
//findViewById, etc.
}
@Override
protected void onStart() {
super.onStart();
air = new MyAsyncTask();
air.execute();
}
@Override
protected void onDestroy() {
if (air.getStatus() == AsyncTask.Status.RUNNING) {
air.cancel(true);
}
air = null;
super.onDestroy();
}
class MyAsyncTask extends AsyncTask<Void, Void, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
UserData.refreshTimer();
if (!progressDialog.isShowing())
progressDialog.show();
}
@Override
protected String doInBackground(Void... params) {
//GET request
return result;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//handle results
progressDialog.dismiss();
}
}
}
Donc, si mon exemple d'activité est détruite, j'annuler ma tâche async, et de créer nouvelle instance dans onStart(). Va-t-il produire des fuites de mémoire, ou peut-il produire IllegalArgumentException/NullPointerException à cause de l'instance de ProgressDialog? Je suppose que cela ne produira aucune exception, car si j'annule le AsyncTask, onPostExecute() ne sera pas appelé.
2) AsyncTask dans son propre fichier
Le cas suivant est quand j'écris MyAsyncTask dans un autre fichier, et passe dans l'instance constructeur de contexte. Est-ce qu'une telle approche produira des fuites de mémoire, si je stocke Context comme WeakReference? Et est-ce une bonne idée d'annuler AsyncTask dans la méthode onDestroy() en appelant Activity pour éviter IllegalArgumentException/NullPointerException pendant la méthode onPostExecute()? Ou, autre moyen d'éviter ces exceptions est de vérifier ma variable Context pour null.
Autres approches: J'ai entendu parler de la bibliothèque Otto, sur l'utilisation des fragments conservés, mais maintenant je veux comprendre ces questions. Si quelqu'un sait - s'il vous plaît, répondez.
Merci pour votre réponse! Mais je n'ai pas compris, pourquoi vaut-il mieux annuler une requête dans onStop()? – user3533397
Principalement parce qu'il reflète avec onStart. Votre flux pourrait être onCreate - onStart - onStop - onStart - onStop - onDestroy = vous auriez démarré deux tâches et annulé seulement une fuite de mémoire = là encore. – Frank