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


665

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

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

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

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

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

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

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

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

जिम


पहले आइटम के लिए संदर्भ जहां R.Guy getApplication का उपयोग करने की सलाह देता है: android-developers.blogspot.com/2009/01/…
जिमहोए

अन्य संदर्भ: stackoverflow.com/questions/1561803/…
Gymhoe

1
अन्य संदर्भ: stackoverflow.com/questions/2634991/…
Gymhoe


जवाबों:


1354

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


67
महान! बस उस पर टिप्पणी करने के लिए .. आपको कभी-कभी "इस" को वैश्विक रूप से संग्रहीत करने की आवश्यकता हो सकती है, (उदाहरण के लिए) इसे सुनने के लिए कार्यान्वित विधि के भीतर एक्सेस करने के लिए, जिसके पास यह 'यह' है। उस स्थिति में, आप "संदर्भ संदर्भ" को वैश्विक रूप से परिभाषित करेंगे, और फिर ऑनक्रीट में, "संदर्भ = यह" सेट करें, और फिर "संदर्भ" का संदर्भ लें। आशा है कि काम में भी आता है।
स्टीवन एल

8
वास्तव में, चूंकि Listenerकक्षाएं अक्सर अनाम-आंतरिक होती हैं, मैं बस कर final Context ctx = this;रहा हूं और मैं दूर हूं;)
एलेक्स

28
@StevenL आप जो कह रहे हैं, उसे करने के लिए, आपको बाह्य वर्ग के "इस" को स्पष्ट रूप से संदर्भित करने के लिए बाह्यक्लासनाम.थिस का उपयोग करना चाहिए।
आर्टेम रसाकोवस्की

11
यदि आपका डायलॉग कॉलबैक में उपयोग किया जाता है और कॉलबैक कहे जाने से पहले आप गतिविधि छोड़ देते हैं, तो इसे "इसे" लीक नहीं करेंगे? कम से कम यह है कि एंड्रॉइड लॉगकोट में शिकायत करने के लिए क्या लगता है।
आर्टेम रसाकोवस्की

6
मैं @StevenLs दृष्टिकोण की सलाह नहीं दूंगा क्योंकि आप उस गतिविधि की मेमोरी को आसानी से लीक कर सकते हैं जब तक कि आपको onDestroy में स्थिर संदर्भ को साफ़ करने की याद न हो - आर्टेम सही है। StevenLs दृष्टिकोण यह समझने की कमी से बोर्न है कि जावा कैसे काम करता है
डोरी

191

का उपयोग करना thisमेरे लिए काम नहीं किया, लेकिन MyActivityName.thisकिया। आशा है कि यह किसी को भी thisकाम करने में मदद नहीं कर सकता है ।


63
ऐसा तब होता है जब आप thisएक आंतरिक वर्ग के अंदर से उपयोग करते हैं । यदि आप एक बाहरी वर्ग के उदाहरण को संदर्भित करना चाहते हैं, तो आपको इसे निर्दिष्ट करना होगा, जैसा कि आप करते हैं OuterClass.this। बस thisहमेशा सबसे आंतरिक वर्ग के उदाहरण का उपयोग करना।
काका

60

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

अपनी अनुमति के लिए निम्नलिखित अनुमति जोड़ें:

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

1
मुझे विंडो जोड़ने में असमर्थ Android.view.ViewRootImpl$W@426ce670 - इस विंडो प्रकार के लिए अनुमति से इनकार कर दिया गया
राम जी।

अनुमति जोड़ें: <उपयोग-अनुमति Android: नाम = "android.permission.SYSTEM_ALERT_WINDOW" />
codezjx

3
ऐसा लगता है कि आप एपीआई 23 में इस अनुमति को सक्षम नहीं कर सकते हैं। बाद में कोड .google.com/p/android
preview

1
आप इसे एपीआई 23 के लिए बाद में उपयोग कर सकते हैं, हालांकि आपको उपयोगकर्ता को संकेत देने की आवश्यकता है: startActivityForResult (नया इरादा (Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse) (पैकेज: "+ getPackageName ())), OVERLAY_PERMISSION_REOD_REOD हालांकि, चाहे आपको इसका उपयोग करना चाहिए एक और मामला है ...
बेन नील

2
यह उपयोगी है जब आप सेवा के अंदर प्रगति संवाद दिखा रहे हैं
आनंद सावजनी

37

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

डायलॉग बनाने के लिए, आपको एक एक्टिविटी कॉन्सेप्ट या सर्विस कॉनटेक्स्ट की जरूरत है , न कि एक एप्लीकेशन कॉन्सेप्ट (दोनों getApplicationContext) (और getApplication () एक एप्लीकेशन कॉन्सेप्ट को वापस)।

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

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

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

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

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

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

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


एक गतिविधि के लिए आप भी उपयोग कर सकते हैं ActivityName.this जहां ActivityName (जाहिर है) है (उदाहरण के MainActivity के लिए) अपनी गतिविधि का नाम
लुइस काब्रेरा बेनिटो

34

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

static Dialog sDialog;

( स्थिर ध्यान दें )

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

 sDialog = new Dialog(this);

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

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

Dialog mDialog;

...

mDialog = new Dialog(this);

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


मैं इसे एसिंक्टस्क से बुला रहा हूं, यह मेरे लिए काम करता है, thx mate
MemLeak

मेरा संवाद स्थिर था, एक बार जब मैंने काम किया स्थिर घोषणा को हटा दिया।
सेडी मुओज़ा

25

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

this.getActivity().getWindow().getContext()टुकड़ों में onCreateकॉलबैक।


4
यह मेरे लिए भी काम करता है, मैंने इसे बाहरी AsyncTask के कंस्ट्रक्टर को पास किया है जो मैं उपयोग कर रहा हूं (यह एक प्रगति डायलॉग दिखाता है)।
रोहन कंडवाल

3
यह अधिक जटिल कार्यों के लिए वास्तविक उत्तर है :)
teejay

1
मैं @tejay
Erdi Julzgi

23

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

MyActivity.this

में टुकड़ा:

getActivity();

यह मेरे लिए मेरी गतिविधि में तय किया। धन्यवाद
वर्नर

20

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

Dialog dialog = new Dialog(MyActivity.this);

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


19

***** कोटलिन संस्करण *****

आप पास करना चाहिए this@YourActivityके बजाय applicationContextयाbaseContext


18

थोड़ा हैक: आप GC द्वारा अपनी गतिविधि को नष्ट करने से रोक सकते हैं (आपको ऐसा नहीं करना चाहिए, लेकिन यह कुछ स्थितियों में मदद कर सकता है। यह निर्धारित contextForDialogकरने के लिए मत भूलना कि nullअब इसकी आवश्यकता नहीं है):

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

@ मुर्तुजाकाबुल यह इसलिए काम करता है क्योंकि यह == पोस्टएक्टिविटी जो एक्टिविटी से विरासत में मिलती है- जो कॉन्टेक्ट से विरासत में मिलती है, इसलिए जब आप अपने संदर्भ को पास करते हैं तो आप वास्तव में एक्टिविटी से गुजर रहे होते हैं
एलाड जेलमैन

13

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

इस तरह

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

12

बस निम्नलिखित का उपयोग करें:

जावा उपयोगकर्ताओं के लिए

मामले में आप गतिविधि का उपयोग कर रहे हैं -> AlertDialog.Builder builder = new AlertDialog.Builder(this);

या

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

मामले में आप टुकड़े -> का उपयोग कर रहे हैं AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

KOTLIN USERS के लिए

मामले में आप गतिविधि का उपयोग कर रहे हैं -> val builder = AlertDialog.Builder(this)

या

val builder = AlertDialog.Builder(this@your_activity.this)

मामले में आप टुकड़े -> का उपयोग कर रहे हैं val builder = AlertDialog.Builder(activity!!)


9

जोड़ने

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

तथा

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

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


9

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

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

progressDialog = new ProgressDialog(getActivity());



6

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

5

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

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

चीयर्स!


5

एक गतिविधि के संदर्भ का उपयोग करने का प्रयास करें जो संवाद के तहत होगा। लेकिन जब आप "इस" कीवर्ड का उपयोग करते हैं तो लापरवाह रहें, क्योंकि यह हर बार काम नहीं करेगा।

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

मुझे यह जानकारी किसी दस्तावेज से नहीं बल्कि कोशिश से मिली। यह मजबूत पृष्ठभूमि के बिना मेरा समाधान है, अगर किसी को बेहतर ज्ञात के साथ, टिप्पणी करने के लिए स्वतंत्र महसूस करें।


4

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

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



2

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

runOnUiThread()उस स्थिति में उपयोग करें ।


2

getParent()नई तरह के संदर्भ के तर्क स्थान पर प्रयास करें AlertDialog.Builder(getParent());आशा है कि यह काम करेगा, इसने मेरे लिए काम किया।


1

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

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


0

यदि आपका डायलॉग एडॉप्टर पर बन रहा है:

एडेप्टर कंस्ट्रक्टर को गतिविधि पास करें:

adapter = new MyAdapter(getActivity(),data);

एडाप्टर पर प्राप्त करें:

 public MyAdapter(Activity activity, List<Data> dataList){
       this.activity = activity;
    }

अब आप अपने बिल्डर पर उपयोग कर सकते हैं

            AlertDialog.Builder alert = new AlertDialog.Builder(activity);

-1

यहाँ मैंने अपने आवेदन के लिए एक ही त्रुटि को हल किया है:
संवाद बनाने के बाद निम्नलिखित पंक्ति को जोड़ना:

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

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

आशा है कि यह आपके ऐप के विकास में आपकी मदद कर सकता है।

डेविड


-1
android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(getWindow().getDecorView().getRootView().getContext());

builder.setTitle("Confirm");
builder.setMessage("Are you sure you want delete your old account?");

builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {

    public void onClick(DialogInterface dialog, int which) {
        //Do nothing but close the dialog



        dialog.dismiss();

    }
});

builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

        //Do nothing
        dialog.dismiss();
    }
});

android.support.v7.app.AlertDialog alert = builder.create();
alert.show();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.