Je reçois un avertissement dans mon code qui dit:
Cette classe AsyncTask doit être statique ou des fuites peuvent se produire (android.os.AsyncTask anonyme)
L'avertissement complet est:
Cette classe AsyncTask doit être statique ou des fuites peuvent se produire (android.os.AsyncTask anonyme) Un champ statique fuira les contextes. Les classes internes non statiques ont une référence implicite à leur classe externe. Si cette classe externe est par exemple un fragment ou une activité, cette référence signifie que le gestionnaire / chargeur / tâche de longue durée contiendra une référence à l'activité qui l'empêche de récupérer les ordures. De même, les références de champ directes aux activités et aux fragments de ces instances plus longues peuvent provoquer des fuites. Les classes ViewModel ne doivent jamais pointer vers des vues ou des contextes non liés à une application.
Voici mon code:
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
Comment puis-je corriger cela?
la source
myActivity.getApplication()
dans le constructeur privé pour le Singleton, afin d'initialiser les classes RoomDB et autres classes). Mes ViewModels obtiennent l'instance Singleton comme référence privée pour effectuer certaines opérations sur la base de données. Ainsi, les ViewModels importent le package Singleton, ainsi que l'android.app.Application
un d'eux mêmeandroid.app.Activity
. Puisque "the Singleton" n'a pas besoin d'importer ces ViewModels pour fonctionner, même ainsi, des fuites de mémoire peuvent-elles se produire?Réponses:
Les classes internes non statiques contiennent une référence à la classe conteneur. Lorsque vous déclarez en
AsyncTask
tant que classe interne, elle peut vivre plus longtemps que laActivity
classe conteneur . Cela est dû à la référence implicite à la classe conteneur. Cela empêchera l'activité d'être récupérée, d'où la fuite de mémoire.Pour résoudre votre problème, utilisez une classe imbriquée statique au lieu d'une classe anonyme, locale et interne ou utilisez une classe de niveau supérieur.
la source
Comment utiliser une classe AsyncTask interne statique
Pour éviter les fuites, vous pouvez rendre la classe interne statique. Le problème avec cela, cependant, est que vous n'avez plus accès aux vues de l'interface utilisateur de l'activité ou aux variables membres. Vous pouvez transmettre une référence à la
Context
mais vous courez alors le même risque de fuite de mémoire. (Android ne peut pas ramasser l'activité après sa fermeture si la classe AsyncTask a une référence forte à elle.) La solution est de faire une référence faible à l'activité (ou toutContext
ce dont vous avez besoin).Remarques
AsyncTask
didacticiels principaux ne sont toujours pas traités (voir ici , ici , ici et ici ).AsyncTask
étiez une classe de niveau supérieur. Une classe interne statique est fondamentalement la même qu'une classe de niveau supérieur en Java.Si vous n'avez pas besoin de l'activité elle-même mais souhaitez toujours le contexte (par exemple, pour afficher un
Toast
), vous pouvez passer une référence au contexte de l'application. Dans ce cas, leAsyncTask
constructeur ressemblerait à ceci:Kotlin
Dans Kotlin, n'incluez
inner
simplement pas le mot - clé pour la classe interne. Cela le rend statique par défaut.la source
onPostExecute
nouveau ma méthode dans le code ci-dessus. Vous pouvez voir que j'ai mis à jour l'interface utilisateurTextView
là-bas. Utilisez simplementactivity.findViewById
pour obtenir une référence à l'élément de l'interface utilisateur que vous devez mettre à jour.activity.isFinishing()
chèque et éventuellement le remplacer par unfragment.isRemoving()
chèque. Cependant, je n'ai pas beaucoup travaillé avec des fragments récemment.AsyncTask
constructeur vous passez une référence à votre classe externe. EtdoInBackground()
vous pouvez obtenir une référence à la classe externe avecMyOuterClass ref = classReference.get()
. Vérifieznull
. (2)onPostExecute()
Vous ne mettez à jour l'interface utilisateur qu'avec les résultats de la tâche en arrière-plan. C'est comme chaque fois que vous mettez à jour l'interface utilisateur. La vérificationactivity.isFinishing()
consiste simplement à s'assurer que l'activité n'a pas encore commencé à se terminer, auquel cas il serait inutile de mettre à jour l'interface utilisateur.Cette
AsyncTask
classe doit être statique ou des fuites peuvent se produire carActivity
est détruit,AsyncTask
(les deuxstatic
ounon-static
) toujours en cours d'exécutionnon-static
(AsyncTask
), elle fera référence à la classe externe (Activity
).Garbage Collected
il le libérera. Si un objet n'est pas utilisé etGarbage Collected
ne peut pas le libérer => fuite de mémoire=> Si
AsyncTask
c'est le casnon-static
,Activity
ne déclenchera pas l'événement il est détruit => fuiteSolution pour mettre à jour l'interface utilisateur après avoir fait AsyncTask en tant que classe statique sans fuite
1) Utilisez
WeakReference
comme @Suragch réponse2) Envoyez et supprimez la
Activity
référence à (de)AsyncTask
la source
onDestroy()
n'est pas garanti d'être appelé à chaque fois