एक स्थिर आंतरिक AsyncTask वर्ग का उपयोग कैसे करें
लीक को रोकने के लिए, आप आंतरिक वर्ग को स्थिर बना सकते हैं। हालांकि, इसके साथ समस्या यह है कि अब आपके पास गतिविधि के UI विचारों या सदस्य चर तक पहुंच नहीं है। आप एक संदर्भ में पास कर सकते हैं, Context
लेकिन फिर आप मेमोरी रिसाव के समान जोखिम को चलाते हैं। (यदि AsyncTask वर्ग के पास इसका एक मजबूत संदर्भ है, तो इसे बंद करने के बाद Android गतिविधि को एकत्र नहीं कर सकता।) समाधान गतिविधि (या जो भी Context
आपको आवश्यक है) के लिए एक कमजोर संदर्भ बनाने के लिए है ।
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;
}
}
}
टिप्पणियाँ
- जहां तक मुझे पता है, इस प्रकार का मेमोरी लीक खतरा हमेशा सच रहा है, लेकिन मैंने केवल एंड्रॉइड स्टूडियो 3.0 में चेतावनी देखना शुरू किया। बहुत सारे मुख्य
AsyncTask
ट्यूटोरियल अभी भी इससे नहीं निपटते हैं ( यहां देखें , यहां , यहां और यहां देखें )।
- यदि आप
AsyncTask
एक शीर्ष स्तर के वर्ग थे, तो आप भी इसी तरह की प्रक्रिया का पालन करेंगे । एक स्थिर आंतरिक वर्ग मूल रूप से जावा में शीर्ष स्तर के वर्ग के समान है।
यदि आपको स्वयं गतिविधि की आवश्यकता नहीं है, लेकिन फिर भी संदर्भ (उदाहरण के लिए Toast
) प्रदर्शित करना चाहते हैं , तो आप ऐप संदर्भ के संदर्भ में पास कर सकते हैं। इस मामले में AsyncTask
निर्माणकर्ता इस तरह दिखेगा:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- इस चेतावनी को अनदेखा करने और गैर-स्थिर वर्ग का उपयोग करने के लिए कुछ तर्क दिए गए हैं। आखिरकार, AsyncTask को बहुत कम समय तक रहने का इरादा है (सबसे लंबे समय में एक युगल सेकंड), और यह गतिविधि के संदर्भ को तब जारी करेगा जब यह किसी भी तरह खत्म हो जाएगा। यह और यह देखें ।
- उत्कृष्ट लेख: कैसे एक संदर्भ लीक करने के लिए: हैंडलर और इनर क्लासेस
Kotlin
कोटलिन में केवल आंतरिक वर्ग के लिए कीवर्ड शामिल नहीं हैinner
। यह डिफ़ॉल्ट रूप से इसे स्थिर बनाता है।
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
}
}
}