android Görünümü pencere yöneticisine eklenmedi


111

Aşağıdaki istisnalardan bazılarına sahibim:

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)

Googledim ve pop-up'larla ve ekranı döndürmeyle ilgisi olduğunu görüyorum, ancak koduma referans yok.

Sorular şunlardır:

  1. Bu sorunun tam olarak ne zaman ortaya çıktığını öğrenmenin bir yolu var mı?
  2. ekranı çevirmek dışında, bu hatayı tetikleyen başka bir olay veya eylem var mı?
  3. bunun olmasını nasıl engellerim?

1
Bildirimde etkinliğin nasıl tanımlandığını ve hata oluştuğunda ekranda hangi etkinliğin olduğunu açıklayıp açıklayamayacağınıza bakın. Sorununuzu minimal bir test senaryosuna dönüştürüp çözemeyeceğinizi görün.
Josh Lee

Belki görüşünüzü View#onAttachedToWindow()çağrılmadan önce değiştirmeye çalışıyorsunuz ?
Alex Lockwood

Yanıtlar:


163

Bu sorunu, bir ekran yönü değişikliğinde, etkinlik, ilerleme iletişim kutusuyla AsyncTask tamamlanmadan önce tamamlandığında yaşadım. Bunu, iletişim kutusunu null olarak ayarlayarak onPause()ve ardından kapatmadan önce AsyncTask'ta kontrol ederek çözmüş gibiydim.

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

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

... AsyncTask'ımda:

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, etkinlik yeniden başlatıldıktan sonra hayatta kalan ve artık ölü Etkinlik ve Görünümlerine referanslar tutabilen bir iş parçacığında çalışıyor (bu, muhtemelen kısa süreli de olsa, etkin bir bellek sızıntısıdır - görevin ne kadar sürdüğüne bağlıdır. ). Kısa süreli bellek sızıntısını kabul etmekten memnunsanız yukarıdaki çözüm iyi çalışıyor. Önerilen yaklaşım, Etkinlik duraklatıldığında çalışan herhangi bir AsyncTask'ın iptalidir ().
Stevie

8

Bu sorunla kavga ettikten sonra, sonunda şu geçici çözümü buldum:

/**
 * 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;
    }
}

Bazen, bu sorun için daha iyi bir çözüm yoksa iyi bir istisna işleme iyi sonuç verir.


5

ActivityEtrafta asılı bir nesneniz varsa, isDestroyed()yöntemi kullanabilirsiniz :

Activity activity;

// ...

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

AsyncTaskÇeşitli yerlerde kullandığınız anonim olmayan bir alt sınıfınız varsa bu güzel .


3

Bir diyalogu gösteren ve gizleyen özel bir statik sınıf kullanıyorum. bu sınıf tek bir faaliyet değil başka faaliyetler tarafından da kullanılmaktadır. Şimdi anlattığınız sorun bana da geldi ve bir çözüm bulmak için bir gecede kaldım ..

Sonunda size çözümü sunuyorum!

Bir iletişim kutusunu göstermek veya kapatmak istiyorsanız ve ona dokunmak için hangi etkinliğin iletişim kutusunu başlattığını bilmiyorsanız, aşağıdaki kod tam size göre ..

 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

Yukarıdaki çözüm benim için işe yaramadı. Yaptığım şey ProgressDialogküresel olarak alıp bunu faaliyetime eklemek oldu

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

böylece faaliyetin yok edilmesi durumunda ProgressDialog da yok edilecektir.


0

Soru 1 için):

Hata mesajının, kodunuzun hangi satırının soruna neden olduğunu söylemediğini göz önünde bulundurarak, kesme noktalarını kullanarak bunu takip edebilirsiniz. Kesme noktaları, program belirli kod satırlarına ulaştığında programın yürütülmesini duraklatır. Kritik konumlara kesme noktaları ekleyerek, hangi kod satırının çökmeye neden olduğunu belirleyebilirsiniz. Örneğin, programınız bir setContentView () satırında çöküyorsa, oraya bir kesme noktası koyabilirsiniz. Program çalıştığında, o satırı çalıştırmadan önce duracaktır. Devam etmek, bir sonraki kesme noktasına ulaşmadan önce programın çökmesine neden oluyorsa, programı öldüren satırın iki kesme noktası arasında olduğunu bilirsiniz.

Eclipse kullanıyorsanız, kesme noktaları eklemek kolaydır. Kodunuzun hemen solundaki kenar boşluğunu sağ tıklayın ve "Kesme noktasını değiştir" i seçin. Daha sonra uygulamanızı, normal çalıştır düğmesinin yanında yeşil bir böcek gibi görünen düğme olan hata ayıklama modunda çalıştırmanız gerekir. Program bir kesme noktasına ulaştığında, Eclipse hata ayıklama perspektifine geçecek ve size beklediği satırı gösterecektir. Programı tekrar çalıştırmak için, normal bir 'Oynat'a benzeyen, ancak üçgenin solunda dikey bir çubuk bulunan' Devam Et 'düğmesini arayın.

Ayrıca uygulamanızı Log.d ("Uygulamam", "Günlük satırının nerede olduğunu söyleyen bazı bilgiler") ile doldurabilir ve ardından Eclipse'in LogCat penceresinde mesajlar gönderebilirsiniz. Bu pencereyi bulamazsanız, Pencere -> Görünümü Göster -> Diğer ... -> Android -> LogCat ile açın.

Umarım yardımcı olur!


7
Sorun istemcinin telefonlarında oluyor, bu yüzden hata ayıklama seçeneğim yok. Ayrıca sorun her zaman oluyor, sadece bazen oluyor, bu yüzden nasıl izleyeceğinizi
bilmeyin

Elinize bir telefondan ulaşabiliyorsanız, yine de bir telefondan hata ayıklama mesajları alabilirsiniz. Menü -> ayarlar -> uygulamalar -> geliştirmede, USB Hata Ayıklama için bir seçenek vardır. Etkinleştirilirse, daha sonra telefonu bağlayabilirsiniz ve LogCat tüm normal hata ayıklama hatlarını yakalar. Bunun dışında ... peki ... programın durumuna bağlı olarak aralıklılık bununla açıklanabilir. Sorunu yeniden oluşturup yaratamayacağınızı görmek için programı kullanarak uğraşmanız gerektiğini düşünüyorum.
Steve Haley

4
Daha önce de söylediğim gibi, sorun bir müşteri telefonunda oluyor ve ona erişimim yok. Müşteri başka bir kıtada olabilir :)
Daniel Benedykt

Piyasada size logcat'lerini e-posta ile gönderecek uygulamalar var.
Tim Green

1
Öykünücüyü 9 numaralı tuşa basarak döndürebileceğinizi bilmeniz için
Rob

0

Aşağıdakileri o etkinlik için bildirime ekledim

android:configChanges="keyboardHidden|orientation|screenLayout"

19
Bu bir çözüm değil: Sistem başka nedenlerle de faaliyetinizi bozabilir.
Roel

1
Cevabınızı açıklar mısınız lütfen?
Leebeedev

0

windowManager koduna göre (bağlantı buraya ), bu, güncellemeye çalıştığınız görünüm (muhtemelen bir iletişim kutusuna aittir, ancak gerekli değildir) artık pencerelerin gerçek köküne eklenmediğinde gerçekleşir.

diğerlerinin önerdiği gibi, diyaloglarınız üzerinde özel işlemler gerçekleştirmeden önce faaliyetin durumunu kontrol etmelisiniz.

İşte sorunun nedeni olan ilgili kod (Android kaynak kodundan kopyalanmıştır):

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;
        }
    }

burada yazdığım kod, google'ın yaptığı şeydir. Yazdıklarım, bu sorunun nedenini göstermek için.
android geliştiricisi

0

Sorunum, androidimde ekran dönüşünü engelleyerek çözüldü, bana bir soruna neden olan uygulama şimdi mükemmel çalışıyor


0

Diğer bir seçenek, iletişim kutusu pencerede onAttachedToWindow () öğesini geçersiz kılarak pencereye eklenene kadar eşzamansız görevi başlatmamaktır, bu şekilde her zaman kapatılabilir.


0

Veya basitçe ekleyebilirsiniz

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

bu ProgressDialogiptal edilemez hale getirecek


-2

Neden böyle yakalamaya çalışmıyorsun:

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

IllegalStateOfException Anormal davranmak yerine daha iyi bir şekilde ele alınmalıdır.
Lavakush

-3

bildirimde etkinlik bildirdiğinizde android: configChanges = "oryantasyon" gerekir

misal:

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

1
Bu etiket, yalnızca geliştiricinin etkinliği android sistemi ile yok etmek ve yeniden oluşturmak istememesi durumunda gereklidir.
Ankit
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.