Comment utiliser un statique à l'intérieur de la classe AsyncTask
Pour éviter les fuites, vous pouvez le faire de l'intérieur de la classe statique. Le problème avec cela, cependant, est que vous n'avez plus accès à l'Activité de l'INTERFACE utilisateur de points de vue ou des variables membres. Vous pouvez passer d'une référence à l' Context
mais vous courez le risque d'une fuite de mémoire. (Android ne peut pas collecter les ordures de l'Activité après la fermeture si la classe AsyncTask a une référence forte pour elle.) La solution est de faire une référence faible de l'Activité (ou de ce qu' Context
vous avez besoin).
public class MyActivity extends AppCompatActivity {
int mSomeMemberVariable = 123;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// start the AsyncTask, passing the Activity context
// in to a custom constructor
new MyTask(this).execute();
}
private static class MyTask extends AsyncTask<Void, Void, String> {
private WeakReference<MyActivity> activityReference;
// only retain a weak reference to the activity
MyTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
@Override
protected String doInBackground(Void... params) {
// do some long running task...
return "task finished";
}
@Override
protected void onPostExecute(String result) {
// get a reference to the activity if it is still there
MyActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
// modify the activity's UI
TextView textView = activity.findViewById(R.id.textview);
textView.setText(result);
// access Activity member variables
activity.mSomeMemberVariable = 321;
}
}
}
Notes
- Autant que je sache, ce type de fuite de mémoire danger a toujours été vrai, mais j'ai seulement commencé à voir la mise en garde dans Android Studio 3.0. Beaucoup des principaux
AsyncTask
tutoriaux-il encore ne pas traiter avec elle (voir ici, ici, ici, et ici).
- Vous aussi suivez une procédure similaire si votre
AsyncTask
étaient d'un haut niveau de classe. Un statique à l'intérieur de la classe de base est le même comme un haut-niveau de la classe en Java.
-
Si vous n'avez pas besoin de l'Activité elle-même, mais veulent toujours le Contexte (par exemple, pour afficher un Toast
), vous pouvez passer une référence pour le contexte de l'application. Dans ce cas, l' AsyncTask
constructeur devrait ressembler à ceci:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- Il y a quelques arguments pour ignorer cet avertissement et simplement à l'aide de la non-statique de la classe. Après tout, l'AsyncTask est destiné à être de très courte durée (quelques secondes à la plus longue), et qu'il publiera sa référence à l'Activité lorsqu'il a terminé de toute façon. Voir ce et ce.
- Excellent article: Comment Fuite Contexte: en effet, les Gestionnaires d' & Inner Classes
Kotlin
Dans Kotlin juste de ne pas inclure l' inner
mot-clé à l'intérieur de la classe. De ce fait, il statique par défaut.
Je ne suis pas trop bon à Kotlin encore, afin de corriger mon code ci-dessous si cela peut être amélioré:
class MyActivity : AppCompatActivity() {
internal var mSomeMemberVariable = 123
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start the AsyncTask, passing the Activity context
// in to a custom constructor
MyTask(this).execute()
}
private class MyTask
internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {
private val activityReference: WeakReference<MyActivity> = WeakReference(context)
override fun doInBackground(vararg params: Void): String {
// do some long running task...
return "task finished"
}
override fun onPostExecute(result: String) {
// get a reference to the activity if it is still there
val activity = activityReference.get()
if (activity == null || activity.isFinishing) return
// modify the activity's UI
val textView = activity.findViewById(R.id.textview)
textView.setText(result)
// access Activity member variables
activity.mSomeMemberVariable = 321
}
}
}