2017-09-18 4 views
2

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.

Répondre

2
  1. L'annulation est un bon moyen de résoudre vos problèmes de mémoire. Vous pourriez envisager d'annuler dans onStop, puisque vous avez configuré une nouvelle tâche dans onStart. Vous pouvez combiner ceci avec l'annulation de la commande progressDialog dans onStop, puisque vous annulez la tâche.

  2. Si vous annulez la tâche, vous ne provoquerez pas de fuite de mémoire. Si vous ne le faites pas, vous risquez de provoquer une fuite de mémoire temporaire. Vous pourriez par exemple résoudre cela en construisant le nouveau fichier Java avec context.getApplicationContext() au lieu de getContext normal/this (Activity). Ensuite, il ne sera pas lié à l'activité mais à l'application (l'application survit au changement d'orientation). Vous ne pourrez cependant pas accéder au dialogue dans onPostExecute(). Au lieu de cela, vous pouvez utiliser un rappel à un écouteur si vous le souhaitez. Faites que l'activité implémente l'écouteur (et détachez-la onStop). Mais l'annulation est également une bonne approche.

+0

Merci pour votre réponse! Mais je n'ai pas compris, pourquoi vaut-il mieux annuler une requête dans onStop()? – user3533397

+0

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