Android दृश्य विंडो प्रबंधक से जुड़ा नहीं है


111

मैं निम्नलिखित अपवादों में से कुछ कर रहा हूँ:

java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:191)
at android.view.Window$LocalWindowManager.updateViewLayout(Window.java:428)
at android.app.Dialog.onWindowAttributesChanged(Dialog.java:596)
at android.view.Window.setDefaultWindowFormat(Window.java:1013)
at com.android.internal.policy.impl.PhoneWindow.access$700(PhoneWindow.java:86)
at com.android.internal.policy.impl.PhoneWindow$DecorView.drawableChanged(PhoneWindow.java:1951)
at com.android.internal.policy.impl.PhoneWindow$DecorView.fitSystemWindows(PhoneWindow.java:1889)
at android.view.ViewRoot.performTraversals(ViewRoot.java:727)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1633)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4338)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)

मैंने इसे देखा है और देखा है कि इसका पॉपअप के साथ कुछ करना है और स्क्रीन को मोड़ना है, लेकिन मेरे कोड का कोई संदर्भ नहीं है।

प्रश्न हैं:

  1. क्या यह पता लगाने का कोई तरीका है कि यह समस्या कब हो रही है?
  2. स्क्रीन को चालू करने के अलावा, क्या कोई अन्य घटना या क्रिया है जो इस त्रुटि को ट्रिगर करती है?
  3. मैं इसे कैसे रोकूँ?

1
यह देखें कि क्या आप बता सकते हैं कि गतिविधि किस प्रकार प्रकट होती है और त्रुटि होने पर स्क्रीन पर क्या गतिविधि होती है। देखें कि क्या आप अपनी समस्या को न्यूनतम टेस्टकेस में निकाल सकते हैं।
जोश ली

हो सकता है कि आपको View#onAttachedToWindow()बुलाए जाने से पहले अपने विचार को संशोधित करने की कोशिश कर रहे हों ?
एलेक्स लॉकवुड

जवाबों:


163

मेरे पास यह समस्या थी कि स्क्रीन ओरिएंटेशन में बदलाव होने पर, एस्क्युनटैस्क से पहले की गतिविधि पूरी हो जाने के बाद गतिविधि समाप्त हो गई। मैं संवाद को अशक्त करने के लिए इसे सेट कर रहा था onPause()और फिर इसे खारिज करने से पहले AsyncTask में जाँच कर रहा था।

@Override
public void onPause() {
    super.onPause();

    if ((mDialog != null) && mDialog.isShowing())
        mDialog.dismiss();
    mDialog = null;
}

... मेरे AsyncTask में:

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...",
            true);
}

protected void onPostExecute(Object result) {
   if ((mDialog != null) && mDialog.isShowing()) { 
        mDialog.dismiss();
   }
}

12
@YekhezkelYovel AsyncTask एक थ्रेड में चल रहा है, जो गतिविधि को फिर से चालू करता है और अब मृत गतिविधि और इसके दृश्य के संदर्भ में हो सकता है (यह एक प्रभावी रूप से एक मेमोरी लीक है, शायद एक छोटी अवधि के लिए - कार्य को पूरा होने में कितना समय लगता है )। यदि आप अल्पावधि स्मृति रिसाव को स्वीकार करने के लिए खुश हैं, तो उपरोक्त समाधान ठीक काम करता है। जब गतिविधि को रोक दिया जाता है तब किसी भी चल रहे AsyncTask को रद्द करने की सिफारिश की जाती है।
स्टीव

8

इस समस्या से लड़ने के बाद, मैं अंत में इस समाधान के साथ समाप्त होता हूं:

/**
 * Dismiss {@link ProgressDialog} with check for nullability and SDK version
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissProgressDialog(ProgressDialog dialog) {
    if (dialog != null && dialog.isShowing()) {

            //get the Context object that was used to great the dialog
            Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();

            // if the Context used here was an activity AND it hasn't been finished or destroyed
            // then dismiss it
            if (context instanceof Activity) {

                // Api >=17
                if (!((Activity) context).isFinishing() {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        if (!((Activity) context).isDestroyed()) {
                            dismissWithExceptionHandling(dialog);
                        }
                    } else { 
                        // Api < 17. Unfortunately cannot check for isDestroyed()
                        dismissWithExceptionHandling(dialog);
                    }
                }
            } else
                // if the Context used wasn't an Activity, then dismiss it too
                dismissWithExceptionHandling(dialog);
        }
        dialog = null;
    }
}

/**
 * Dismiss {@link ProgressDialog} with try catch
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissWithExceptionHandling(ProgressDialog dialog) {
    try {
        dialog.dismiss();
    } catch (final IllegalArgumentException e) {
        // Do nothing.
    } catch (final Exception e) {
        // Do nothing.
    } finally {
        dialog = null;
    }
}

कभी-कभी, अच्छा अपवाद हैंडलिंग अच्छी तरह से काम करता है अगर इस मुद्दे के लिए एक बेहतर समाधान नहीं था।


5

यदि आपके पास कोई Activityवस्तु घूम रही है, तो आप isDestroyed()विधि का उपयोग कर सकते हैं :

Activity activity;

// ...

if (!activity.isDestroyed()) {
    // ...
}

यह अच्छा है यदि आपके पास एक गैर-अनाम AsyncTaskउपवर्ग है, जिसे आप विभिन्न स्थानों पर उपयोग करते हैं।


3

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

अंत में मैं आपको समाधान प्रस्तुत करता हूं!

अगर आप किसी डायलॉग को दिखाना या खारिज करना चाहते हैं और आपको नहीं पता कि उसे छूने के लिए कौन सी गतिविधि शुरू की गई है तो निम्न कोड आपके लिए है ..

 static class CustomDialog{

     public static void initDialog(){
         ...
         //init code
         ...
     }

      public static void showDialog(){
         ...
         //init code for show dialog
         ...
     }

     /****This is your Dismiss dialog code :D*******/
     public static void dismissProgressDialog(Context context) {                
            //Can't touch other View of other Activiy..
            //http://stackoverflow.com/questions/23458162/dismiss-progress-dialog-in-another-activity-android
            if ( (progressdialog != null) && progressdialog.isShowing()) {

                //is it the same context from the caller ?
                Log.w("ProgressDIalog dismiss", "the dialog is from"+progressdialog.getContext());

                Class caller_context= context.getClass();
                Activity call_Act = (Activity)context;
                Class progress_context= progressdialog.getContext().getClass();

                Boolean is_act= ( (progressdialog.getContext()) instanceof  Activity )?true:false;
                Boolean is_ctw= ( (progressdialog.getContext()) instanceof  ContextThemeWrapper )?true:false;

                if (is_ctw) {
                    ContextThemeWrapper cthw=(ContextThemeWrapper) progressdialog.getContext();
                    Boolean is_same_acivity_with_Caller= ((Activity)(cthw).getBaseContext() ==  call_Act )?true:false;

                    if (is_same_acivity_with_Caller){
                        progressdialog.dismiss();
                        progressdialog = null;
                    }
                    else {
                        Log.e("ProgressDIalog dismiss", "the dialog is NOT from the same context! Can't touch.."+((Activity)(cthw).getBaseContext()).getClass());
                        progressdialog = null;
                    }
                }


            }
        } 

 }

1

उपरोक्त समाधान मेरे लिए काम नहीं किया। इसलिए मैंने जो किया वह ProgressDialogविश्व स्तर पर लिया और फिर इसे अपनी गतिविधि में शामिल किया

@Override
    protected void onDestroy() {
        if (progressDialog != null && progressDialog.isShowing())
            progressDialog.dismiss();
        super.onDestroy();
    }

ताकि अगर गतिविधि नष्ट हो जाती है, तो प्रोग्रेसडायलॉग भी नष्ट हो जाएगा।


0

प्रश्न 1 के लिए):

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

यदि आप ग्रहण का उपयोग कर रहे हैं तो ब्रेकप्वाइंट जोड़ना आसान है। अपने कोड के बाईं ओर मार्जिन में राइट क्लिक करें और "टॉगल ब्रेकपॉइंट" चुनें। फिर आपको अपने एप्लिकेशन को डिबग मोड में चलाने की आवश्यकता है, वह बटन जो सामान्य रन बटन के बगल में हरे रंग की कीट की तरह दिखता है। जब प्रोग्राम एक ब्रेकपॉइंट मारता है, तो एक्लिप्स डिबग परिप्रेक्ष्य में बदल जाएगा और आपको वह रेखा दिखाएगा जिसका वह इंतजार कर रहा है। प्रोग्राम को फिर से शुरू करने के लिए, 'फिर से शुरू करें' बटन देखें, जो सामान्य 'प्ले' जैसा दिखता है, लेकिन त्रिभुज के बाईं ओर एक ऊर्ध्वाधर पट्टी के साथ।

आप अपने आवेदन को Log.d ("मेरा आवेदन", "यहां कुछ जानकारी जो आपको बताती है कि लॉग लाइन कहां है") के साथ भर सकते हैं, जो तब एक्लिप्स के लॉगकट विंडो में संदेश पोस्ट करता है। यदि आपको वह विंडो नहीं मिल रही है, तो उसे विंडो -> शो व्यू -> अन्य ... -> एंड्रॉइड -> लॉगकट के साथ खोलें।

उम्मीद है की वो मदद करदे!


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

आप अभी भी फोन से डिबगिंग संदेश प्राप्त कर सकते हैं, यदि आप एक पर अपने हाथ पा सकते हैं। मेनू में -> सेटिंग्स -> एप्लिकेशन -> विकास, यूएसबी डिबगिंग के लिए एक विकल्प है। यदि सक्षम किया गया है, तो आप फ़ोन को प्लग इन कर सकते हैं और LogCat सभी सामान्य डिबगिंग लाइनों को पकड़ता है। इसके अलावा ... अच्छी तरह से ... आंतरायिकता को कार्यक्रम की स्थिति के आधार पर इसके द्वारा समझाया जा सकता है। मुझे लगता है कि आपको इस कार्यक्रम का उपयोग करके यह देखने के लिए गड़बड़ करना होगा कि क्या आप समस्या को फिर से बना सकते हैं।
स्टीव हेली

4
जैसा कि मैंने पहले कहा, इस मुद्दे पर एक ग्राहक फोन पर हो रहा है, और मैं इसे करने के लिए उपयोग नहीं है। मुवक्किल एक और महाद्वीप पर हो सकता है :)
डैनियल बेनिदित

बाजार पर ऐसे ऐप हैं जो आपको अपना लॉगकैट ईमेल करेंगे।
टिम ग्रीन

1
बस इतना है कि आप जानते हैं कि आप एम्युपिटर को 9
Rob

0

मैंने उस गतिविधि के लिए निम्नलिखित को जोड़ा

android:configChanges="keyboardHidden|orientation|screenLayout"

19
यह एक समाधान नहीं है: सिस्टम अन्य कारणों से भी आपकी गतिविधि को नष्ट कर सकता है।
रोएल

1
क्या आप अपना उत्तर बता सकते हैं?
लीबेदेव

0

विंडो मैनजर के कोड ( यहां लिंक ) के अनुसार, यह तब होता है जब आप जिस दृश्य को अपडेट करने का प्रयास कर रहे हैं (जो संभवतः एक संवाद से संबंधित है, लेकिन आवश्यक नहीं है) अब खिड़कियों की वास्तविक जड़ से जुड़ा नहीं है।

जैसा कि दूसरों ने सुझाव दिया है, आपको अपने संवादों पर विशेष संचालन करने से पहले गतिविधि की स्थिति की जांच करनी चाहिए।

यहाँ एक relavant कोड है, जो समस्या का कारण है (Android स्रोत कोड से कॉपी किया गया):

public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams
            = (WindowManager.LayoutParams)params;

    view.setLayoutParams(wparams);

    synchronized (this) {
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots[index];
        mParams[index] = wparams;
        root.setLayoutParams(wparams, false);
    }
}

private int findViewLocked(View view, boolean required) {
        synchronized (this) {
            final int count = mViews != null ? mViews.length : 0;
            for (int i=0; i<count; i++) {
                if (mViews[i] == view) {
                    return i;
                }
            }
            if (required) {
                throw new IllegalArgumentException(
                        "View not attached to window manager");
            }
            return -1;
        }
    }

यहाँ जो कोड मैंने लिखा है वह वही है जो गूगल करता है। इस समस्या का कारण बताने के लिए मैंने जो कुछ लिखा है, वह है।
Android डेवलपर

0

मेरी समस्या का हल मेरे एंड्रॉइड ऐप पर स्क्रीन रोटेशन को उहलॉक करके किया गया था जो मुझे एक समस्या पैदा कर रहा था जो अब पूरी तरह से काम करता है


0

एक अन्य विकल्प यह नहीं है कि जब तक संवाद खिड़की पर संलग्न न हो जाए तब तक एसिंक्स टास्क शुरू न करें। डायलॉग पर onAttachedToWindow () ओवरराइड करके, यह हमेशा खारिज करने वाला तरीका है।


0

या बस आप जोड़ सकते हैं

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...", true, false);
}

जो ProgressDialogरद्द नहीं कर पाएगा


-2

क्यों नहीं पकड़ने की कोशिश, इस तरह:

protected void onPostExecute(Object result) {
        try {
            if ((mDialog != null) && mDialog.isShowing()) {
                mDialog.dismiss();
            }
        } catch (Exception ex) {
            Log.e(TAG, ex.getMessage(), ex);
        }
    }

IllegalStateOfException को एक बेहतर तरीके से निपटा जाना चाहिए, न कि केवल असामान्य व्यवहार करने के लिए।
लवकुश

-3

जब आप गतिविधि में घोषणा करते हैं, तो आपको Android की आवश्यकता होती है: configChanges = "ओरिएंटेशन"

उदाहरण:

<activity android:theme="@android:style/Theme.Light.NoTitleBar" android:configChanges="orientation"  android:label="traducción" android:name=".PantallaTraductorAppActivity"></activity>

1
यह टैग केवल तभी आवश्यक है जब डेवलपर एंड्रॉइड सिस्टम द्वारा गतिविधि को नष्ट और फिर से बनाना नहीं चाहता है।
अंकित
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.