Statik iç AsyncTask sınıfı nasıl kullanılır
Sızıntıları önlemek için iç sınıfı statik hale getirebilirsiniz. Bununla birlikte sorun, artık Etkinliğin kullanıcı arabirimi görünümlerine veya üye değişkenlerine erişiminizin olmamasıdır. Bir referans gönderebilirsiniz, Context
ancak daha sonra aynı bellek sızıntısı riski taşırsınız. (AsyncTask sınıfının güçlü bir referansı varsa, Android, Etkinliği kapattıktan sonra çöp toplayamaz.) Çözüm, Etkinliğe (veya Context
ihtiyacınız olan her şeye) zayıf bir referans yapmaktır .
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;
}
}
}
notlar
- Bildiğim kadarıyla, bu tür bellek sızıntısı tehlikesi her zaman doğruydu, ancak yalnızca Android Studio 3.0'da uyarıyı görmeye başladım.
AsyncTask
Dışarıdaki ana öğreticilerin çoğu hala bununla ilgilenmiyor ( buraya , buraya , buraya ve buraya bakın ).
AsyncTask
Üst düzey bir sınıf olsaydınız da benzer bir prosedür izlerdiniz. Statik bir iç sınıf temelde Java'daki bir üst düzey sınıfla aynıdır.
Etkinliğin kendisine ihtiyacınız yoksa, ancak Bağlamın (örneğin, a görüntülemesini Toast
) istiyorsanız, uygulama bağlamına bir referans iletebilirsiniz. Bu durumda AsyncTask
kurucu şöyle görünecektir:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- Bu uyarıyı yok saymak ve yalnızca statik olmayan sınıfı kullanmak için bazı argümanlar var. Sonuçta, AsyncTask'ın çok kısa ömürlü olması (en uzun sürede birkaç saniye) olması amaçlanmıştır ve yine de bittiğinde Faaliyete olan referansını serbest bırakacaktır. Bkz bu ve bu .
- Mükemmel makale: Bağlam Nasıl Sızılır: İşleyiciler ve İç Sınıflar
Kotlin
Kotlin'de sadece iç sınıf için inner
anahtar kelime eklemeyin . Bu, varsayılan olarak statik hale getirir.
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
}
}
}