Cara menggunakan kelas AsyncTask bagian dalam statis
Untuk mencegah kebocoran, Anda dapat membuat kelas dalam statis. Masalahnya adalah Anda tidak lagi memiliki akses ke tampilan UI variabel aktivitas atau anggota. Anda dapat mengirimkan referensi ke Context
tetapi kemudian Anda menjalankan risiko yang sama dari kebocoran memori. (Android tidak dapat mengumpulkan sampah Aktivitas setelah ditutup jika kelas AsyncTask memiliki referensi yang kuat untuk itu.) Solusinya adalah membuat referensi yang lemah ke Aktivitas (atau apa pun yang Context
Anda butuhkan).
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;
}
}
}
Catatan
- Sejauh yang saya tahu, bahaya kebocoran memori jenis ini selalu benar, tetapi saya hanya mulai melihat peringatan di Android Studio 3.0. Banyak
AsyncTask
tutorial utama di luar sana yang masih belum menanganinya (lihat di sini , di sini , di sini , dan di sini ).
- Anda juga akan mengikuti prosedur serupa jika Anda
AsyncTask
kelas atas. Kelas dalam statis pada dasarnya sama dengan kelas tingkat atas di Jawa.
Jika Anda tidak membutuhkan Kegiatan itu sendiri tetapi tetap menginginkan Konteks (misalnya, untuk menampilkan a Toast
), Anda dapat meneruskan referensi ke konteks aplikasi. Dalam hal ini AsyncTask
konstruktor akan terlihat seperti ini:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- Ada beberapa argumen di luar sana untuk mengabaikan peringatan ini dan hanya menggunakan kelas non-statis. Lagipula, AsyncTask dimaksudkan untuk berumur sangat pendek (beberapa detik paling lama), dan itu akan merilis referensi ke Aktivitas ketika selesai. Lihat ini dan ini .
- Artikel yang luar biasa: Cara Membocorkan Konteks: Penangan & Kelas Dalam
Kotlin
Di Kotlin, jangan memasukkan inner
kata kunci untuk kelas dalam. Ini menjadikannya statis secara default.
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
}
}
}