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




android-alertdialog android-context (19)

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

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

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

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

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

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

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

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

जिम


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

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

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

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

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

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

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

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

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


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

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


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


मेरे मामले में काम:

this.getContext();

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

इस तरह

ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();

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

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

progressDialog = new ProgressDialog(getActivity());


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


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

MyActivity.this

टुकड़ा में:

getActivity();

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


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

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


भविष्य के पाठकों के लिए, इससे मदद मिलनी चाहिए:

public void show() {
    if(mContext instanceof Activity) {
        Activity activity = (Activity) mContext;
        if (!activity.isFinishing() && !activity.isDestroyed()) {
            dialog.show();
        }
    }
}

यदि आप गतिविधि के बाहर हैं तो आपको गतिविधि कार्य के रूप में अपने नाम "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);

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

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();
    }
    ...
}

आपका संवाद "दीर्घकालिक वस्तु" नहीं होना चाहिए जिसे संदर्भ की आवश्यकता है "। दस्तावेज उलझन में है। असल में यदि आप कुछ ऐसा करते हैं:

static Dialog sDialog;

( स्थिर नोट करें)

फिर कहीं एक गतिविधि में आपने किया था

 sDialog = new Dialog(this);

आप घूर्णन या इसी तरह के दौरान मूल गतिविधि को लीक कर सकते हैं जो गतिविधि को नष्ट कर देगा। (जब तक आप डेस्ट्रॉय में साफ नहीं करते हैं, लेकिन उस स्थिति में आप शायद संवाद ऑब्जेक्ट को स्थिर नहीं करेंगे)

कुछ डेटा संरचनाओं के लिए उन्हें स्थिर और एप्लिकेशन के संदर्भ के आधार पर समझदारी होगी, लेकिन आमतौर पर यूआई से संबंधित चीजों के लिए नहीं, जैसे संवाद। तो ऐसा कुछ है:

Dialog mDialog;

...

mDialog = new Dialog(this);

ठीक है और गतिविधि को रिसाव नहीं करना चाहिए क्योंकि mDialog गतिविधि से मुक्त हो जाएगा क्योंकि यह स्थैतिक नहीं है।


जोड़ने

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

तथा

"android.permission.SYSTEM_ALERT_WINDOW"/> प्रकट में

यह अब मेरे लिए काम करता है। एप्लिकेशन को बंद करने और खोलने के बाद, मुझे उस समय त्रुटि मिली।


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

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

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

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

चीयर्स!


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


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

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

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




builder