android - डायलॉग फेंकना "विंडो जोड़ने में असमर्थ-टोकन नल अनुप्रयोग के लिए नहीं है" संदर्भ के रूप में getAplication() के साथ




android-alertdialog android-context (16)

मेरी गतिविधि एक अलर्टडिअलॉग बनाने की कोशिश कर रही है जिसके लिए एक पैरामीटर के रूप में संदर्भ की आवश्यकता है। यदि मैं उपयोग करता हूं तो यह अपेक्षित काम करता है:

AlertDialog.Builder builder = new AlertDialog.Builder(this);

हालांकि, जब मैं गतिविधि को नष्ट कर देता हूं और स्क्रीन रोटेशन की तरह कुछ सरल के दौरान भी पुनर्निर्मित करता हूं, तो मैं स्मृति के लीक की संभावना के कारण संदर्भ के रूप में "इस" का उपयोग करने के लिए तैयार हूं। एंड्रॉइड डेवलपर के ब्लॉग पर संबंधित पोस्ट से :

संदर्भ से संबंधित स्मृति रिसाव से बचने के दो आसान तरीके हैं। सबसे स्पष्ट बात यह है कि संदर्भ को अपने दायरे के बाहर से बचने से बचें। उपर्युक्त उदाहरण में एक स्थिर संदर्भ का मामला दिखाया गया है लेकिन आंतरिक वर्ग और बाहरी वर्ग के उनके निहित संदर्भ समान रूप से खतरनाक हो सकते हैं। दूसरा समाधान अनुप्रयोग संदर्भ का उपयोग करना है। यह संदर्भ तब तक लाइव रहेगा जब तक आपका आवेदन ज़िंदा नहीं है और यह गतिविधि चक्र चक्र पर निर्भर नहीं है। यदि आप दीर्घकालिक वस्तुओं को रखने की योजना बनाते हैं जिन्हें संदर्भ की आवश्यकता है, तो एप्लिकेशन ऑब्जेक्ट को याद रखें। आप Context.getApplicationContext () या Activity.getApplication () को कॉल करके इसे आसानी से प्राप्त कर सकते हैं।

लेकिन AlertDialog() न तो getApplicationContext() या getApplication() को संदर्भ के रूप में स्वीकार्य है, क्योंकि यह अपवाद फेंकता है:

"विंडो जोड़ने में असमर्थ - टोकन नल एक अनुप्रयोग के लिए नहीं है"

प्रति संदर्भ: 1 , 2 , 3 , आदि

तो, क्या इसे वास्तव में "बग" माना जाना चाहिए, क्योंकि हमें आधिकारिक तौर पर Activity.getApplication() का उपयोग करने की सलाह दी जाती है और फिर भी यह विज्ञापन के रूप में कार्य नहीं करती है?

जिम


आप उस संदर्भ के माध्यम से एक एप्लिकेशन window/dialog प्रदर्शित नहीं कर सकते जो गतिविधि या सेवा नहीं हैवैध गतिविधि संदर्भ पारित करने का प्रयास करें


आप getApplicationContext() का उपयोग करना जारी रख सकते हैं, लेकिन उपयोग से पहले, आपको यह ध्वज जोड़ना चाहिए: dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT) , और त्रुटि दिखाई नहीं देगी।

अपने मैनिफेस्ट में निम्नलिखित अनुमति जोड़ें:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

आपने समस्या को सही ढंग से पहचाना है जब आपने कहा था ... "AlertDialog () के लिए न तो getAplicationContext () या getAplication () को संदर्भ के रूप में स्वीकार्य है, क्योंकि यह अपवाद फेंकता है: 'विंडो जोड़ने में असमर्थ - टोकन नल नहीं है एक आवेदन पत्र'"

एक संवाद बनाने के लिए, आपको एक गतिविधि संदर्भ या एक सेवा संदर्भ की आवश्यकता है , न कि एक अनुप्रयोग संदर्भ (दोनों getAplicationContext () और getAplication () एक अनुप्रयोग संदर्भ लौटाएं)।

यहां बताया गया है कि आप गतिविधि संदर्भ कैसे प्राप्त करते हैं:

(1) एक गतिविधि या एक सेवा में:

AlertDialog.Builder builder = new AlertDialog.Builder(this);

(2) एक टुकड़े में: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

मेमोरी लीक ऐसी समस्या नहीं है जो "इस" संदर्भ के लिए आंतरिक है, जो कि ऑब्जेक्ट का संदर्भ है (यानी ऑब्जेक्ट के डेटा को संग्रहीत करने के लिए वास्तविक आवंटित स्मृति का संदर्भ)। यह किसी भी आवंटित स्मृति के साथ होता है जिसके लिए आवंटित स्मृति ने अपने उपयोगी जीवनकाल को पार करने के बाद कचरा कलेक्टर (जीसी) मुक्त करने में असमर्थ है।

अधिकांश समय, जब एक चरणीय दायरे से बाहर हो जाता है, तो स्मृति जीसी द्वारा पुनः दावा की जाएगी। हालांकि, मेमोरी लीक तब हो सकती है जब एक चर द्वारा आयोजित ऑब्जेक्ट का संदर्भ "x" कहता है, ऑब्जेक्ट ने इसके उपयोगी जीवनकाल को पार करने के बाद भी जारी रखा है। इसलिए आवंटित स्मृति तब तक खो जाएगी जब तक "x" इसका संदर्भ नहीं रखता क्योंकि जीसी स्मृति को तब तक मुक्त नहीं करेगा जब तक कि उस स्मृति को अभी भी संदर्भित किया जा रहा हो। कभी-कभी आवंटित स्मृति के संदर्भों की श्रृंखला की वजह से स्मृति रिसाव स्पष्ट नहीं होते हैं। ऐसे मामले में, जीसी स्मृति को तब तक मुक्त नहीं करेगा जब तक कि उस स्मृति के सभी संदर्भ हटा दिए गए हों।

मेमोरी लीक को रोकने के लिए, लॉजिकल त्रुटियों के लिए अपना कोड जांचें जो आवंटित स्मृति को "इस" (या अन्य संदर्भों) द्वारा अनिश्चित काल तक संदर्भित करने का कारण बनता है। श्रृंखला संदर्भों के लिए भी जांचना याद रखें। यहां कुछ टूल्स हैं जिनका उपयोग आप स्मृति उपयोग का विश्लेषण करने और उन अजीब स्मृति लीक को खोजने में आपकी सहायता के लिए कर सकते हैं:


इसका उपयोग करने के लिए मेरे लिए काम नहीं किया, लेकिन MyActivityName.this . MyActivityName.this किया था। उम्मीद है कि यह किसी ऐसे व्यक्ति की मदद करता है जो this काम पर नहीं ला सके।


एक संवाद बॉक्स दिखाते हुए बटन के क्लिक पर Activity

Dialog dialog = new Dialog(MyActivity.this);

मेरे लिए काम किया


एपीआई को देखने के बाद, आप अपनी गतिविधि को संवाद कर सकते हैं या निष्क्रियता प्राप्त कर सकते हैं यदि आप एक टुकड़े में हैं, तो लीक को रोकने के लिए वापसी विधियों में इसे mor.dismiss () के साथ मजबूती से साफ़ करें।

यद्यपि यह कहीं भी स्पष्ट रूप से नहीं बताया गया है, मुझे लगता है कि ऐसा लगता है कि आप इसे करने के लिए ऑनक्लिक हैंडलर में संवाद वापस कर चुके हैं।


थोड़ा हैक: आप जीसी द्वारा गतिविधि को नष्ट करने से रोक सकते हैं (बेशक, आपको यह नहीं करना चाहिए, लेकिन यह कुछ स्थितियों में मदद कर सकता है):

public class PostActivity extends Activity  {
    ...
    private Context contextForDialog = null;
    ...
    public void onCreate(Bundle savedInstanceState) {
        ...
        contextForDialog = this;
    }
    ...
    private void showAnimatedDialog() {
        mSpinner = new Dialog(contextForDialog);
        mSpinner.setContentView(new MySpinner(contextForDialog));
        mSpinner.show();
    }
    ...
}

नए अलर्टडिअलॉग.बिल्डर (getParent ()) जैसे संदर्भ के तर्क स्थान पर getParent () को आज़माएं; उम्मीद है कि यह काम करेगा, यह मेरे लिए काम किया।


मुझे एक खंड में प्रदर्शित एक कस्टम एडाप्टर पर एक कन्स्ट्रक्टर के माध्यम से अपना संदर्भ भेजना पड़ा था और यह समस्या getAplicationContext () के साथ थी। मैंने इसे हल किया:

this.getActivity().getWindow().getContext() को टुकड़ों में this.getActivity().getWindow().getContext()


मुझे लगता है कि यह भी हो सकता है यदि आप थ्रेड से एक संवाद दिखाने की कोशिश कर रहे हैं जो मुख्य यूआई थ्रेड नहीं है।

उस मामले में runOnUiThread () का उपयोग करें।


मैं एक खंड में ProgressDialog का उपयोग कर रहा था और इसे प्राप्त करने के लिए त्रुटि प्राप्त कर रहा था getActivity().getApplicationContext() को कन्स्ट्रक्टर पैरामीटर के रूप में प्राप्त करें। इसे getActivity().getBaseContext() करने के लिए getActivity().getBaseContext() या तो काम नहीं किया।

मेरे लिए काम करने वाला समाधान प्राप्त करने के लिए getActivity() ; अर्थात

progressDialog = new ProgressDialog(getActivity());


यदि आप एक टुकड़े का उपयोग कर रहे हैं और AlertDialog / Toast संदेश का उपयोग कर रहे हैं, तो संदर्भ पैरामीटर में getActivity() उपयोग करें।

मेरे लिए काम किया

चीयर्स!


यदि आप गतिविधि के बाहर हैं तो आपको गतिविधि कार्य के रूप में अपने नाम "NameOfMyActivity.this" में उपयोग करने की आवश्यकता है, उदाहरण:

public static void showDialog(Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Your Message")
        .setPositiveButton("Yes", dialogClickListener)
        .setNegativeButton("No", dialogClickListener).show();
}


//Outside your Activity
showDialog(NameOfMyActivity.this);

या एक और संभावना संवाद के रूप में संवाद बनाने के लिए है:

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));

getApplicationContext() करने के बजाय, ActivityName.this उपयोग करें।


गतिविधि में बस उपयोग करें:

MyActivity.this

टुकड़ा में:

getActivity();




builder