विंडो मैनेजर क्रैश से जुड़ा नहीं देखें


188

मैं ऐप क्रैश की रिपोर्ट करने के लिए ACRA का उपयोग कर रहा हूं। मुझे एक View not attached to window managerत्रुटि संदेश मिल रहा था और मुझे लगा कि मैंने इसे pDialog.dismiss();एक स्टेटमेंट में लपेट कर तय किया है :

if (pDialog!=null) 
{
    if (pDialog.isShowing()) 
    {
        pDialog.dismiss();   
    }
}

इसने View not attached to window managerमेरे द्वारा प्राप्त होने वाली दुर्घटनाओं की मात्रा को कम कर दिया है , लेकिन मुझे अभी भी कुछ मिल रहा है और मुझे यकीन नहीं है कि इसे कैसे हल किया जाए।

त्रुटि संदेश:

java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:425)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:327)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:83)
at android.app.Dialog.dismissDialog(Dialog.java:330)
at android.app.Dialog.dismiss(Dialog.java:312)
at com.package.class$LoadAllProducts.onPostExecute(class.java:624)
at com.package.class$LoadAllProducts.onPostExecute(class.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:631)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)

सांकेतिक टुकड़ा:

class LoadAllProducts extends AsyncTask<String, String, String> 
{

    /**
     * Before starting background thread Show Progress Dialog
     * */
    @Override
    protected void onPreExecute() 
    {
        super.onPreExecute();
        pDialog = new ProgressDialog(CLASS.this);
        pDialog.setMessage("Loading. Please wait...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    /**
     * getting All products from url
     * */
    protected String doInBackground(String... args) 
    {
        // Building Parameters
        doMoreStuff("internet");
        return null;
    }


    /**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(String file_url) 
    {
         // dismiss the dialog after getting all products
         if (pDialog!=null) 
         {
                if (pDialog.isShowing()) 
                {
                    pDialog.dismiss();   //This is line 624!    
                }
         }
         something(note);
    }
}

मैनिफ़ेस्ट:

    <activity
        android:name="pagename.CLASS" 
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout"            
        android:label="@string/name" >
    </activity>

इस दुर्घटना को रोकने के लिए मुझे क्या याद आ रहा है?


1
क्या आपने कभी यह पता लगाया? मुझे भी यही तकलीफ़ है। यह पता लगाने के लिए प्रतीत नहीं कर सकते।
टोमजंग

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

आपका AsyncTaskअंदर घोषित किया जाता है Activityया Fragment?
एटकिटिन

कृपया कार्य "doMoreStuff ()" और "कुछ" () करें।
निडर

मुद्दा मुख्य धागे के बहुत अधिक काम के कारण हो सकता है, इसलिए हैंडलर का उपयोग करने के लिए प्रोगडियोग्लॉग दिखाने की कोशिश करें, और यदि (pDialog! = Null) इस लाइन की कोई आवश्यकता नहीं है, क्योंकि स्वयं को जांचना है कि संवाद प्रगति में है या नहीं।
मधु

जवाबों:


446

बग को कैसे पुन: पेश करें:

  1. अपने डिवाइस पर इस विकल्प को सक्षम करें Settings -> Developer Options -> Don't keep Activities:।
  2. AsyncTaskनिष्पादित करते समय होम बटन दबाएं और ProgressDialogदिखा रहा है।

जैसे ही यह छिपा होगा Android OS एक गतिविधि को नष्ट कर देगा। जब onPostExecuteकहा जाता Activityहै "" परिष्करण " राज्य में ProgressDialogहोगा और वसीयत को संलग्न नहीं किया जाएगा Activity

इसे कैसे जोड़ेंगे:

  1. अपनी onPostExecuteविधि में गतिविधि स्थिति की जाँच करें ।
  2. विधि ProgressDialogमें खारिज करें onDestroy। अन्यथा, android.view.WindowLeakedअपवाद को फेंक दिया जाएगा। यह अपवाद आमतौर पर उन संवादों से आता है जो अभी भी सक्रिय हैं जब गतिविधि समाप्त हो रही है।

इस निश्चित कोड का प्रयास करें:

public class YourActivity extends Activity {

    private void showProgressDialog() {
        if (pDialog == null) {
            pDialog = new ProgressDialog(StartActivity.this);
            pDialog.setMessage("Loading. Please wait...");
            pDialog.setIndeterminate(false);
            pDialog.setCancelable(false);
        }
        pDialog.show();
    }

    private void dismissProgressDialog() {
        if (pDialog != null && pDialog.isShowing()) {
            pDialog.dismiss();
        }
    }

    @Override
    protected void onDestroy() {
        dismissProgressDialog();
        super.onDestroy();
    }

    class LoadAllProducts extends AsyncTask<String, String, String> {

        // Before starting background thread Show Progress Dialog
        @Override
        protected void onPreExecute() {
            showProgressDialog();
        }

        //getting All products from url
        protected String doInBackground(String... args) {
            doMoreStuff("internet");
            return null;
        }

        // After completing background task Dismiss the progress dialog
        protected void onPostExecute(String file_url) {
            if (YourActivity.this.isDestroyed()) { // or call isFinishing() if min sdk version < 17
                return;
            }
            dismissProgressDialog();
            something(note);
        }
    }
}

8
बहुत बढ़िया जवाब! BTW, isShowing () अनावश्यक है क्योंकि बर्खास्तगी () कुछ भी नहीं करेगी यदि ishhowing () == गलत है। स्रोत कोड
पीटर झाओ

3
इस विशिष्ट उद्देश्य के लिए सभी एपीआई पर उपयोग isDestroyed()करने का क्या लाभ है isFinishing()?
अलेक्जेंडर अबाकुमोव

@AlexanderAbakumov: क्या मैं समझता हूं कि isFinishing()गारंटी नहीं दी जाती है trueयदि गतिविधि सिस्टम द्वारा नष्ट हो जाती है, तो गतिविधियों को प्रलेखन देखें ।
मार्कस पेंगुइन

1
@ मर्कसपेंगिन: सही है। लेकिन, इस मामले में, अगर किसी ने लेखक की टिप्पणी से एक सलाह का उपयोग करने का प्रयास किया, तो // or call isFinishing() if min sdk version < 17वह बहुत ही अपवाद में चलता है। इसलिए, हमें एपीआई <17 पर चलने वाले ऐप्स के लिए इस उत्तर की तुलना में एक अलग समाधान की आवश्यकता है।
अलेक्जेंडर अबाकुमोव

@AlexanderAbakumov मुझे वही समस्या हो रही है, लेकिन मेरे लिए काम नहीं कर रहा है, इसने AsyncCallback के अंदर मेरी गतिविधि के लिए एक कमजोरपन को बचाने का काम किया, और फिर:myActivityWeakReference.get() != null && !myActivityWeakReference.get().isFinishing()
rusito23

34

मुद्दा हो सकता है कि Activityकिया गया है finishedया में है progress of finishing

एक चेक जोड़ें isFinishing, और यह होने पर ही डायलॉग को खारिज करेंfalse

if (!YourActivity.this.isFinishing() && pDialog != null) {
    pDialog.dismiss();
}

isFishing: यह देखने के लिए जांचें कि क्या यह गतिविधि परिष्करण की प्रक्रिया में है, या तो क्योंकि आपने finishइसे कॉल किया था या किसी और ने अनुरोध किया है कि यह समाप्त हो गया है।


1
चेक के साथ अपवाद अभी भी फेंका जा रहा है
मार्कोस वास्कोनसेलोस

मेरा प्रोग्रेसडायलॉग एक ऐसी कक्षा में है जो एक गतिविधि नहीं है, इसलिए मैं isinishing check @Libin
Maniraj

10

में Dialogबनाया के लिए Fragment, मैं निम्नलिखित कोड का उपयोग करें:

ProgressDialog myDialog = new ProgressDialog(getActivity());
myDialog.setOwnerActivity(getActivity());
...
Activity activity = myDialog.getOwnerActivity();
if( activity!=null && !activity.isFinishing()) {
    myDialog.dismiss();
}

मैं इस पैटर्न का उपयोग उस मामले से निपटने के लिए Fragmentकर सकता हूं जब पैटर्न से अलग किया जा सकता है Activity


8

देखें कि यहां कोड कैसे काम कर रहा है:

Async कार्य को कॉल करने के बाद, async कार्य पृष्ठभूमि में चलता है। यह वांछनीय है। अब, इस Async कार्य में एक प्रगति संवाद है जो गतिविधि से जुड़ा हुआ है, यदि आप पूछते हैं कि कोड कैसे देखें:

pDialog = new ProgressDialog(CLASS.this);

आप Class.thisतर्क के संदर्भ में पारित कर रहे हैं । इसलिए प्रगति संवाद अभी भी गतिविधि से जुड़ा हुआ है।

अब परिदृश्य पर विचार करें: यदि हम फिनिश () पद्धति का उपयोग करते हुए गतिविधि को पूरा करने का प्रयास करते हैं, जबकि एसिंक्स कार्य प्रगति पर है, तो वह बिंदु है जहां आप गतिविधि से जुड़े संसाधन तक पहुँचने का प्रयास कर रहे हैं अर्थात progress barजब गतिविधि अधिक नहीं होगी वहाँ।

इसलिए आपको मिलता है:

java.lang.IllegalArgumentException: View not attached to the window manager

इसका समाधान:

1) सुनिश्चित करें कि गतिविधि समाप्त होने से पहले संवाद बॉक्स खारिज या रद्द कर दिया गया है।

2) गतिविधि को समाप्त करें, केवल संवाद बॉक्स के खारिज होने के बाद, यह है कि async कार्य समाप्त हो गया है।


1
# 2 के बारे में: आपको पूरा नियंत्रण नहीं है कि कब खत्म करना है Activity; Android इसे किसी भी समय समाप्त कर सकता है। तो, # 2 का कोई मतलब नहीं है।
अलेक्जेंडर अबाकुमोव

6

@Erakitin उत्तर के आधार पर, लेकिन Android संस्करणों के लिए भी संगत <API स्तर 17। उदासी से भरा गतिविधि ।isDestroyed () केवल API स्तर 17 के बाद से समर्थित है, इसलिए यदि आप मेरे जैसे पुराने API स्तर को लक्षित कर रहे हैं, तो आपको करना होगा इसकी जांच स्वयं करें। View not attached to window managerउसके बाद अपवाद नहीं मिला ।

उदाहरण कोड

public class MainActivity extends Activity {
    private TestAsyncTask mAsyncTask;
    private ProgressDialog mProgressDialog;
    private boolean mIsDestroyed;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (condition) {
            mAsyncTask = new TestAsyncTask();
            mAsyncTask.execute();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mAsyncTask != null && mAsyncTask.getStatus() != AsyncTask.Status.FINISHED) {
            Toast.makeText(this, "Still loading", Toast.LENGTH_LONG).show();
            return;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mIsDestroyed = true;

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

    public class TestAsyncTask extends AsyncTask<Void, Void, AsyncResult> {    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mProgressDialog = ProgressDialog.show(MainActivity.this, "Please wait", "doing stuff..");
        }

        @Override
        protected AsyncResult doInBackground(Void... arg0) {
            // Do long running background stuff
            return null;
        }

        @Override
        protected void onPostExecute(AsyncResult result) {
            // Use MainActivity.this.isDestroyed() when targeting API level 17 or higher
            if (mIsDestroyed)// Activity not there anymore
                return;

            mProgressDialog.dismiss();
            // Handle rest onPostExecute
        }
    }
}


3

OnConfigurationChanged ओवरराइड करें और प्रगति संवाद को खारिज करें। यदि प्रगति संवाद चित्र में बनाया गया है और परिदृश्य में खारिज कर दिया गया है, तो यह विंडो प्रबंधक त्रुटि से जुड़ा नहीं दृश्य को फेंक देगा।

इसके अलावा प्रगति बार को रोकें और onPause (), onBackPressed और onDestroy विधि में async कार्य रोकें।

if(asyncTaskObj !=null && asyncTaskObj.getStatus().equals(AsyncTask.Status.RUNNING)){

    asyncTaskObj.cancel(true);

}

3

गतिविधि के onDestroy को ओवरराइड करें और अपने डायलॉग को खारिज करें और इसे शून्य बनाएं

protected void onDestroy ()
    {
        if(mProgressDialog != null)
            if(mProgressDialog.isShowing())
                mProgressDialog.dismiss();
        mProgressDialog= null;
    }

3

सबसे पहले, दुर्घटना का कारण सजावट है दृश्य सूचकांक -1 है, हम इसे एंड्रॉइड स्रोत कोड से जान सकते हैं, कोड स्निपेट है:

वर्ग: android.view.WindowManagerGlobal

फ़ाइल: WindowManagerGlobal.java

private int findViewLocked(View view, boolean required) {
        final int index = mViews.indexOf(view);
//here, view is decorView,comment by OF
        if (required && index < 0) {
            throw new IllegalArgumentException("View=" + view + " not attached to window manager");
        }
        return index;
    }

तो हमें फॉलो रिजोल्यूशन मिलता है, बस डेकोर व्यूज इंडेक्स को जज करें, अगर यह 0 से अधिक है तो जारी रखें या बस वापस लौटें और खारिज करें, निम्नानुसार कोड:

try {
            Class<?> windowMgrGloable = Class.forName("android.view.WindowManagerGlobal");
            try {
                Method mtdGetIntance = windowMgrGloable.getDeclaredMethod("getInstance");
                mtdGetIntance.setAccessible(true);
                try {
                    Object windownGlobal = mtdGetIntance.invoke(null,null);
                    try {
                        Field mViewField = windowMgrGloable.getDeclaredField("mViews");
                        mViewField.setAccessible(true);
                        ArrayList<View> mViews = (ArrayList<View>) mViewField.get(windownGlobal);
                        int decorViewIndex = mViews.indexOf(pd.getWindow().getDecorView());
                        Log.i(TAG,"check index:"+decorViewIndex);
                        if (decorViewIndex < 0) {
                            return;
                        }
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        if (pd.isShowing()) {
            pd.dismiss();
        }

2

dismiss()इस तरह से विधि को पार करें:

@Override
public void dismiss() {
    Window window = getWindow();
    if (window == null) {
        return;
    }
    View decor = window.getDecorView();
    if (decor != null && decor.getParent() != null) {
        super.dismiss();
    }
}

समस्या को पुन: उत्पन्न करने के लिए, संवाद समाप्त करने से पहले गतिविधि को समाप्त करें।


1

सबसे अच्छा उपाय। पहले संदर्भ की जाँच करें गतिविधि संदर्भ या अनुप्रयोग संदर्भ यदि गतिविधि का संदर्भ है तो केवल जाँच गतिविधि समाप्त हो गई है या नहीं तो कॉल करें dialog.show()याdialog.dismiss();

नीचे नमूना कोड देखें ... आशा है कि यह उपयोगी होगा!

संवाद प्रदर्शित करें

if (context instanceof Activity) {
   if (!((Activity) context).isFinishing())
     dialog.show();
}

संवाद को खारिज करें

if (context instanceof Activity) {
       if (!((Activity) context).isFinishing())
         dialog.dismiss();
    }

यदि आप अधिक चेक जोड़ना चाहते हैं तो स्थिति जोड़ें dialog.isShowing()या dialog !-nullउपयोग करें &&


0

यह समस्या इसलिए है क्योंकि बर्खास्तगी फ़ंक्शन को कॉल करने से पहले आपकी गतिविधि समाप्त हो जाती है। अपवाद को हैंडल करें और सटीक कारण के लिए अपने एडीबी लॉग की जांच करें।

/**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(String file_url) {
    try {
         if (pDialog!=null) {
            pDialog.dismiss();   //This is line 624!    
         }
    } catch (Exception e) {
        // do nothing
    }
     something(note);
}

0

मुझे इस अपवाद को पुन: पेश करने का एक तरीका मिला।

मैं 2 का उपयोग करता हूं AsyncTask। एक लंबा टास्क करता है और दूसरा शॉर्ट टास्क करता है। शॉर्ट टास्क पूरा होने के बाद कॉल करें finish()। जब लंबे काम पूरा हो जाता है और कॉल होता है Dialog.dismiss(), तो यह क्रैश हो जाता है।

यहाँ मेरा नमूना कोड है:

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    private ProgressDialog mProgressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate");

        new AsyncTask<Void, Void, Void>(){
            @Override
            protected void onPreExecute() {
                mProgressDialog = ProgressDialog.show(MainActivity.this, "", "plz wait...", true);
            }

            @Override
            protected Void doInBackground(Void... nothing) {
                try {
                    Log.d(TAG, "long thread doInBackground");
                    Thread.sleep(20000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return null;
            }

            @Override
            protected void onPostExecute(Void result) {
                Log.d(TAG, "long thread onPostExecute");
                if (mProgressDialog != null && mProgressDialog.isShowing()) {
                    mProgressDialog.dismiss();
                    mProgressDialog = null;
                }
                Log.d(TAG, "long thread onPostExecute call dismiss");
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        new AsyncTask<Void, Void, Void>(){
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    Log.d(TAG, "short thread doInBackground");
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                Log.d(TAG, "short thread onPostExecute");
                finish();
                Log.d(TAG, "short thread onPostExecute call finish");
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

आप यह कोशिश कर सकते हैं और पता लगा सकते हैं कि इस मुद्दे को ठीक करने का सबसे अच्छा तरीका क्या है। मेरे अध्ययन से, इसे ठीक करने के कम से कम 4 तरीके हैं:

  1. @ एराकिटिन का जवाब: isFinishing()गतिविधि की स्थिति की जांच करने के लिए कॉल करें
  2. @ कपे का जवाब: गतिविधि की स्थिति की जाँच करने के लिए ध्वज सेट करें
  3. इसे संभालने के लिए try / catch का प्रयोग करें।
  4. कॉल AsyncTask.cancel(false)में onDestroy()। यह asynctask को निष्पादित करने के लिए रोक देगा, onPostExecute()लेकिन onCancelled()इसके बजाय निष्पादित करें ।
    नोट: onPostExecute()अभी भी निष्पादित करेगा यहां तक ​​कि आप AsyncTask.cancel(false)पुराने Android OS पर कॉल करते हैं, जैसे कि Android 2.XX

आप अपने लिए सर्वश्रेष्ठ चुन सकते हैं।


0

हो सकता है कि आप वैश्विक रूप से pDialog को इनिशियलाइज़ करें, फिर इसे हटा दें और स्थानीय रूप से अपने विचार या संवाद को बढ़ा दें। मेरे पास एक ही मुद्दा है, मैंने यह किया है और मेरा मुद्दा हल हो गया है। आशा है कि यह यू के लिए काम करेगा।


0

हमने onPauseविधि या onDestroyविधि पर अपने संवाद को भी खारिज कर दिया है

@Override
protected void onPause() {
    super.onPause();
    dialog.dismiss();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    dialog.dismiss();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.