istisna alma “IllegalStateException: onSaveInstanceState sonrasında bu eylem gerçekleştirilemiyor”


355

Canlı bir Android uygulamam var ve piyasadan yığın izlemesini aldım ve neden onun uygulama kodunda olmuyor ama uygulamadan bir veya başka bir olaydan (varsayım) kaynaklandığı gibi bir fikrim yok

Ben Fragments kullanmıyorum, hala FragmentManager bir referans var. Herhangi bir vücut bu tür bir sorunu önlemek için bazı gizli gerçeklere biraz ışık tutabilirse:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyDown(Activity.java:1962)
at android.view.KeyEvent.dispatch(KeyEvent.java:2482)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1720)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1258)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2851)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2824)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2011)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4025)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)  

Henüz bir çözüm buldunuz mu? Burada aynı problemi
yaşıyoruz


2
@phlebas Hayır, yapmadın. Sizinki diyaloglar ile ilgili, ve bu değil. Yığın izleme eşleştirmenizin en üst satırı yeterli değil. Gerisi çok farklı. Bunu söylüyorum çünkü sorununa baktım ve maalesef bana bir yardımı olmadı.
themightyjon

Bu aktivitede bir Thread veya AsynTask kullanıyor musunuz?
José Castro

21
Bu hatayı blog yayınımda tartışıyorum ... okumalısın. :)
Alex Lockwood

Yanıtlar:


455

Bu şimdiye kadar karşılaştığım en aptal böcek. Ben vardı Fragmentiçin mükemmel çalışıyor uygulamayı API <11 ve Force Closingüzerinde 11 API> .

ActivityÇağrısında yaşam döngüsünde neleri değiştirdiklerini gerçekten anlayamadım saveInstance, ama burada bunu nasıl çözdüm:

@Override
protected void onSaveInstanceState(Bundle outState) {
    //No call for super(). Bug on API Level > 11.
}

Ben sadece çağrı yapmıyorum .super()ve her şey harika çalışıyor. Umarım bu size biraz zaman kazandırır.

EDIT: biraz daha araştırmadan sonra, bu destek paketinde bilinen bir hatadır .

Örneği kaydetmeniz ve bir şey eklemeniz gerekiyorsa outState Bundleaşağıdakileri kullanabilirsiniz:

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
    super.onSaveInstanceState(outState);
}

EDIT2:Activity arka planda gittikten sonra bir işlem yapmaya çalışıyorsanız da oluşabilir . Bundan kaçınmak içincommitAllowingStateLoss()

EDIT3: Yukarıdaki çözümler erken support.v4 kitaplıklarındaki hatırlayabildiğim sorunları . Sen hâlâ bu sorunları Ama eğer GEREKİR da okumak @AlexLockwood 'ın blog: Fragment İşlemler ve Etkinlik Devlet Kaybı

Blog gönderisinden özet (ama kesinlikle okumanızı tavsiye ederim):

  • ASLA commit() sonra işlemler onPause()öncesi Petek üzerinde ve onStop()sonrası Petek üzerinde
  • İçinde işlem yaparken dikkatli olun Activity döngüsü yöntemleri . Kullanım onCreate() , onResumeFragments()veonPostResume()
  • Eşzamansız geri arama yöntemlerinde işlem yapmaktan kaçının
  • commitAllowingStateLoss()Yalnızca son çare olarak kullanın

97
Commit () yerine commitAllowingStateLoss () kullanmalısınız
meh

7
Bu nedenle, onSaveInstanceState içinde super çağrılmaması, FragmentManager'ın tüm parçaların durumunu kaydetmesini ve geri yüklemesini durduracaktır. Bu, döndürme ile ilgili sorunlara neden olabilir. Ayrıca, önemsizleri demete koymakla ilgili başka bir şey denedim ve bu benim için hiçbir şey değiştirmiyor. Nasıl olacağından emin değilim - destek paketinde başvurduğunuz hata bir NullPointerException ve bu IllegalStateException gibi görünmüyor ...
themightyjon

56
@meh commitAllowingStateLoss()sadece istisnayı önler. Uygulamanızı kazara devlet kaybından korumaz. Bu blog yayınına bakın .
Alex Lockwood

2
@AlexLockwood, böylece bu blog gönderisinden tüm ağ çağrılarımızı parça içinde yapmamız gerektiğini öğrenebiliriz (ve gerekirse geçici ilerleme ui'sini görüntüleyebiliriz) ve bu, büyük olasılıkla gerçekleştiğinde bu istisnadan kaçınmanın tek yolu budur çünkü bazı eşzamansız yöntem çağrısından sonra çağrılıyor.
meh

1
İlk noktayı almıyorum: "ASLA ... sonrası Petek sonrası onStop () işlemlerini ASLA taahhüt etmiyorum". Bir parçanın başka bir parçayla değiştirilmesini tetiklemek için bir düğmeye ihtiyacım olursa ne olur? Etkinliğin onStop'ta bitip bitmediğini kontrol eden bir boolean koymalı mıyım ve eğer varsa, bunun yerine commitAllowingStateLoss'u arayın? Ayrıca, bir parçanın içinde bir parçam varsa, bir düğmeyi tıklattığınızda değiştirmem gerekir?
android geliştirici

76

Bu soruna neyin neden olduğuna dair Android kaynak koduna bakıldığında, FragmentManagerImplsınıftaki mStateSaved bayrağının (Etkinlik'te bulunan örnek) true değerine sahip olması sağlanır. Arka yığın çağrıldığında kaydedildiğinde (saveAllState) true olarak ayarlanır Activity#onSaveInstanceState. Daha sonra ActivityThread'den gelen çağrılar FragmentManagerImpl#noteStateNotSaved()vedispatch() .

Gördüğüm şekilde, uygulamanızın ne yaptığına ve kullandığına bağlı olarak bazı mevcut düzeltmeler var:

İyi yollar

Her şeyden önce: Alex Lockwood'un makalesinin reklamını yapardım . Sonra, şimdiye kadar yaptığımdan:

  1. Herhangi bir durum bilgisi tutması gerekmeyen parçalar ve etkinlikler için, commitAllowStateLoss'u arayın . Belgelerden alınmıştır:

    Bir etkinliğin durumu kaydedildikten sonra taahhüdün yürütülmesine izin verir. Bu tehlikelidir çünkü etkinliğin daha sonra durumundan geri yüklenmesi gerekiyorsa taahhüt kaybedilebilir, bu nedenle bu yalnızca kullanıcı arayüzünün kullanıcının beklenmedik bir şekilde değişmesinin uygun olduğu durumlarda kullanılmalıdır. Parçanın salt okunur bilgileri göstermesi durumunda bunun iyi olduğunu düşünüyorum. Veya düzenlenebilir bilgiler gösterse bile, düzenlenen bilgileri korumak için geri arama yöntemlerini kullanın.

  2. İşlem tamamlandıktan hemen sonra (az önce aradınız commit()), arayın FragmentManager.executePendingTransactions().

Tavsiye edilmeyen yollar:

  1. Ovidiu Latcu'nun yukarıda bahsettiği gibi, arama super.onSaveInstanceState(). Ancak bu, parça durumuyla birlikte aktivitenizin tüm durumunu kaybedeceğiniz anlamına gelir.

  2. Sadece geçersiz kıl onBackPressedve oradaki çağrı finish(). Uygulamanız Parçalar API'sını kullanmıyorsa bu sorun olmamalıdır; olduğu gibi super.onBackPressedbir çağrı var FragmentManager#popBackStackImmediate().

  3. Her iki Parça API'sını kullanıyorsanız ve etkinliğinizin durumu önemli / hayati önem taşıyorsa, yansıma API'sını kullanarak aramayı deneyebilirsiniz FragmentManagerImpl#noteStateNotSaved(). Ama bu bir hack, ya da bir çözüm olduğunu söyleyebiliriz. Sevmiyorum, ancak benim durumumda, kabul edilmemiş kod ( TabActivityve dolaylı olarak LocalActivityManager) kullanan eski bir uygulamadan bir kod aldığım için oldukça kabul edilebilir .

Yansıma kullanan kod aşağıdadır:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    invokeFragmentManagerNoteStateNotSaved();
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private void invokeFragmentManagerNoteStateNotSaved() {
    /**
     * For post-Honeycomb devices
     */
    if (Build.VERSION.SDK_INT < 11) {
        return;
    }
    try {
        Class cls = getClass();
        do {
            cls = cls.getSuperclass();
        } while (!"Activity".equals(cls.getSimpleName()));
        Field fragmentMgrField = cls.getDeclaredField("mFragments");
        fragmentMgrField.setAccessible(true);

        Object fragmentMgr = fragmentMgrField.get(this);
        cls = fragmentMgr.getClass();

        Method noteStateNotSavedMethod = cls.getDeclaredMethod("noteStateNotSaved", new Class[] {});
        noteStateNotSavedMethod.invoke(fragmentMgr, new Object[] {});
        Log.d("DLOutState", "Successful call for noteStateNotSaved!!!");
    } catch (Exception ex) {
        Log.e("DLOutState", "Exception on worka FM.noteStateNotSaved", ex);
    }
}

Şerefe!


Bu, Gingerbread altında ActionBarSherlock ile de oluyor gibi görünüyor, bu nedenle Build
Id'i

Ayrıca, dikkat etmelisiniz - bu ABS kullanımı için uygun değildir :)
t0mm13b

@ t0mm13b: Yukarıdaki kod, ne fragman ne de destek kullanmadığı için projemi temsil ediyor. Android.app.Activity üzerinde çalışır ve İstisna tetikleyen tutarsızlık FragmentManager (API seviye 11 yukarı) neden olduğu için, bu yüzden kontrol ... Kötülük kaynağının sizin için de aynı olduğuna inanıyorsanız, çekinmeyin onay işaretini kaldırın. ABS, uyumluluk paketinin ve desteğin uygulanmasında çalıştığı için farklı bir hikaye.
gunar

@ t0mm13b: 600 karakter daha fazla eklemek için yeterli olmadığından, öncelikle bunun sizin için neye sebep olduğunu araştırmanız gerekir. Ayrıca, yukarıda çirkin bir hack olduğunu ve çalışıp çalışmadığına dair herhangi bir sorumluluk almamaya dikkat etmelisiniz (benim için koşulları göz önünde bulundurarak en iyi çözümdü). Kullanmanız gerekiyorsa, standart pakette farklılık gösterebileceğinden, uyumluluk kaynak kodunu değişken adları için iki kez kontrol edin. Umarım bu sorun uyumluluk paketinin sonraki sürümleri tarafından ele alınacaktır, ancak Android deneyiminden, gerçekleşme şansı azdır ...
gunar

Uhhh ... Bu OP raporunun konusu olan bu hata raporundakiyle tamamen aynı . Benim yorumum stand by - Eğer gereken açıkça beyanda koyduk ve garanti edilmemektedir demek ve ayrıca gerektiğini size parçaları kullanmak vermedi ifade etmişlerdir - Aksi neden ya o Yanıt göndererek rahatsız! :) Sadece söyleyerek ...
t0mm13b

35

Parça etkinliğiniz onSaveInstanceState()çağrıldıktan sonra bir parça geçişi gerçekleştirmeye çalışırsanız böyle bir istisna oluşur .

Bunun olmasının bir nedeni, bir faaliyet durdurulduğunda bir AsyncTask(veya Thread) çalışmayı bırakmanızdır .

Daha sonra onSaveInstanceState()çağrılan herhangi bir geçiş , sistem kaynakların etkinliğini geri alır ve daha sonra yeniden oluşturursa kaybolabilir.


2
Hey Funk, burada bir sorum var, onBackPressed nasıl olur, eğer o aktivite veya parça durdurulmuşsa, o aktivite veya parça üzerinde nasıl çağrılabilir. Yukarıdaki istisna bazı UI olaydan (örn. GERİ tuşuna basarak) oluşturulmuş gibi görünüyor, ancak Async Görev ve Geri tuşu arasındaki ilişkiyi bulamıyorum.
dcool

Parça geçişlerini geri durumuna kaydedebileceğiniz için, geri düğmesine basmak, kaydettiğiniz geçişin tersine neden olabilir (böylece eski parçalar geri gelir). onSaveInstanceState, her zaman onStop çağrıldıktan sonra değil, kaynakları sisteme geri yüklemek için etkinliğiniz yok edilmeden önce çağrılır. Üzgünüm, bu cevabımda çok net değildi.
FunkTheMonk

Funk, ama uygulamamda hiçbir Parça kullanmıyorum. Yerel kodda kullanılan parçalar olabilir. daha önce aynı şeyden bahsettiğini sanıyordum.
dcool

1
Bir parça referansı ile bir AsyncTask vardı. Super () çağrısını onSaveInstanceState öğesinden kaldırdıktan ve referansı AsyncTask'ımdan WeakReference <Fragment> ile değiştirdikten sonra sorun çözüldü.
Buffalo

2
@Buffalo Bu kesinlikle soruna bir çözüm değil. Her zaman aramalısın super.onSaveInstanceState().
Alex Lockwood

27

Basitçe çağrı super.onPostResume () sizin parça gösteren öncesinde veya super.onPostResume çağırmadan sonra) (onPostResume yöntemini kodunuzu taşımak (). Bu sorunu çözmek!


6
OnPostResume () öğesini çağırmak, onResumeFragments () yönteminin çağrılmasını sağlar ve bana bu ideal çözümdür.
j2emanue

20

Bu dismiss(), ekran kilitlendikten ve boşaltıldıktan ve Activity + iletişim kutusunun örnek durumu kaydedildikten sonra bir iletişim parçası çağrıldığında da olabilir . Bu görüşmeyi almak için:

dismissAllowingStateLoss()

Kelimenin tam anlamıyla her zaman bir iletişim kutusunu işten çıkarıyorum artık zaten umurumda değil, bu yüzden bunu yapmak için sorun yok - aslında herhangi bir durumu kaybetmiyorsunuz.


2
Bu benim tam sorunumdu! Siz efendim!
Tash Pemhiwa

17

Kısa Ve Çalışma Çözümü:

Basit Adımları İzleyin:

Adım 1 : İlgili parçadaki onSaveInstanceState durumunu geçersiz kılın. Ve süper yöntemi ondan kaldırın.

@Override
public void onSaveInstanceState(Bundle outState) {
};

Adım 2 : CommAllowingStateLoss () kullanın; commit () yerine; parça operasyonları.

fragmentTransaction.commitAllowingStateLoss();

1
Süper yöntemi kaldırmak hile yaptı, neden olsa açıklayabilir misiniz? Bunu kaldırmak güvenli mi?
Bruce

7
super () kaldırmak güvenli değil, bundan sonra diğer verileri kaybedeceksiniz!
deadfish


7

bu benim için çalıştı ... bunu kendi başıma buldum ... umarım sana yardımcı olur!

1) global bir "statik" FragmentManager / FragmentTransaction'a sahip DEĞİLDİR.

2) onCreate, DAİMA FragmentManager'ı tekrar başlatın!

aşağıdaki örnek: -

public abstract class FragmentController extends AnotherActivity{
protected FragmentManager fragmentManager;
protected FragmentTransaction fragmentTransaction;
protected Bundle mSavedInstanceState;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedInstanceState = savedInstanceState;
    setDefaultFragments();
}

protected void setDefaultFragments() {
    fragmentManager = getSupportFragmentManager();
    //check if on orientation change.. do not re-add fragments!
    if(mSavedInstanceState == null) {
        //instantiate the fragment manager

        fragmentTransaction = fragmentManager.beginTransaction();

        //the navigation fragments
        NavigationFragment navFrag = new NavigationFragment();
        ToolbarFragment toolFrag = new ToolbarFragment();

        fragmentTransaction.add(R.id.NavLayout, navFrag, "NavFrag");
        fragmentTransaction.add(R.id.ToolbarLayout, toolFrag, "ToolFrag");
        fragmentTransaction.commitAllowingStateLoss();

        //add own fragment to the nav (abstract method)
        setOwnFragment();
    }
}

6

OnActivityForResult () yönteminde parça göstermeye çalıştığımda her zaman bu başlamıştı, bu yüzden sorun sonraki oldu:

  1. Etkinliğim duraklatıldı ve durduruldu, yani onSaveInstanceState () zaten çağrıldı (hem Petek öncesi hem de Petek sonrası cihazlar için).
  2. Herhangi bir sonuç durumunda ben bu IllegalStateException neden parçası göstermek / gizlemek için işlem yaptı.

Sonra ne yaptım:

  1. İstediğim eylemin yapılıp yapılmadığını belirlemek için katma değer (örn. Camere - isPhotoTaken'den fotoğraf çekmek) - ihtiyacınız olan farklı işlemlere bağlı olarak boole veya tamsayı değeri olabilir.
  2. Geçersiz kılınan onResumeFragments () yönteminde değerimi kontrol ettim ve parça işlemlerini yaptıktan sonra ihtiyacım vardı. Bu durumda, durum onResumeFragments () yönteminde döndürüldüğü için, onSaveInstanceState öğesinden sonra commit () işlemi yapılmadı.

5

Onconfigurationchanging ile sorunu çözdüm. İşin püf noktası, android aktivite yaşam döngüsüne göre, açıkça bir niyet (kamera amacı veya başka bir tane) çağırdığınızda; etkinlik duraklatılır ve onavedInstance bu durumda çağrılır. Cihazı, etkinliğin aktif olduğu konumdan farklı bir konuma döndürürken; fragman taahhüdü gibi fragman işlemleri yapmak Yasadışı durum istisnasına neden olur. Bu konuda çok şikayet var. Android aktivite yaşam döngüsü yönetimi ve uygun yöntem çağrıları hakkında bir şey. Bunu çözmek için şunu yaptım: 1-Etkinliğinizin onavedInstance yöntemini geçersiz kılın ve geçerli ekran yönünü (dikey veya yatay) belirleyin, ardından etkinliğiniz duraklatılmadan önce ekran yönünüzü ayarlayın. bu şekilde, başka bir etkinlik tarafından döndürülmüş olması durumunda, etkinliğiniz için ekran döndürmeyi kilitlediğiniz etkinlik. 2-sonra, devam ettirme aktivite yöntemini geçersiz kılın ve kaydedilen yöntem çağrıldıktan sonra rotasyonla düzgün bir şekilde başa çıkmak için bir kez daha yapılandırmada bir kez daha çağrılacak şekilde yönlendirme modunuzu şimdi sensöre ayarlayın.

Bu kodu, onunla başa çıkmak için etkinliğinize kopyalayabilir / yapıştırabilirsiniz:

@Override
protected void onSaveInstanceState(Bundle outState) {       
    super.onSaveInstanceState(outState);

    Toast.makeText(this, "Activity OnResume(): Lock Screen Orientation ", Toast.LENGTH_LONG).show();
    int orientation =this.getDisplayOrientation();
    //Lock the screen orientation to the current display orientation : Landscape or Potrait
    this.setRequestedOrientation(orientation);
}

//A method found in stackOverflow, don't remember the author, to determine the right screen orientation independently of the phone or tablet device 
public int getDisplayOrientation() {
    Display getOrient = getWindowManager().getDefaultDisplay();

    int orientation = getOrient.getOrientation();

    // Sometimes you may get undefined orientation Value is 0
    // simple logic solves the problem compare the screen
    // X,Y Co-ordinates and determine the Orientation in such cases
    if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        Configuration config = getResources().getConfiguration();
        orientation = config.orientation;

        if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        // if height and widht of screen are equal then
        // it is square orientation
            if (getOrient.getWidth() == getOrient.getHeight()) {
                orientation = Configuration.ORIENTATION_SQUARE;
            } else { //if widht is less than height than it is portrait
                if (getOrient.getWidth() < getOrient.getHeight()) {
                    orientation = Configuration.ORIENTATION_PORTRAIT;
                } else { // if it is not any of the above it will defineitly be landscape
                    orientation = Configuration.ORIENTATION_LANDSCAPE;
                }
            }
        }
    }
    return orientation; // return value 1 is portrait and 2 is Landscape Mode
}

@Override
public void onResume() {
    super.onResume();
    Toast.makeText(this, "Activity OnResume(): Unlock Screen Orientation ", Toast.LENGTH_LONG).show();
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
} 

4

Aynı sorun vardı, IllegalStateException alıyorum, ancak, commandAllowingStateLoss () ile commit () tüm çağrıları yerine yardımcı olmadı.

Suçlu DialogFragment.show () çağrısıydı.

Onu çevreliyorum

try {
    dialog.show(transaction, "blah blah");
}
catch(IllegalStateException e) {
    return;
}

ve bunu başardı. Tamam, iletişim kutusunu gösteremiyorum, ama bu durumda bu iyi oldu.

Benim app FragmentManager.beginTransaction () denilen ama asla commit () olarak adlandırılan tek yerdi bu yüzden "commit ()" aradığımda bulamadım.

Komik olan şey, kullanıcı uygulamayı asla terk etmez. Bunun yerine katil, gösterilen bir AdMob geçiş reklamıydı.


3
Burada aynı. 'Commit' yerine 'commitAllowingStateLoss' yerine 'show (FragmentManager manager, String tag)' yöntemini geçersiz kılma; Dialog'un iki özel özelliğini ayarlayamadığım için bir şey kaybetmek: mDismissed ve mShownByMe. Ama her seferinde işe yarıyor gibi görünüyor :)
Francesco Ditrani

DialogFragment için bu istisnayı önleyebilecek alternatif bir çözüm yaptım: github.com/AndroidDeveloperLB/DialogShard
android geliştirici

4

Bu sorun için benim çözümüm

Parça ekleme yöntemlerinde:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ...
    guideMapFragment = (SupportMapFragment)a.getSupportFragmentManager().findFragmentById(R.id.guideMap);
    guideMap = guideMapFragment.getMap();
    ...
}

@Override
public void onDestroyView() {
    SherlockFragmentActivity a = getSherlockActivity();
    if (a != null && guideMapFragment != null) {
        try {
            Log.i(LOGTAG, "Removing map fragment");
            a.getSupportFragmentManager().beginTransaction().remove(guideMapFragment).commit();
            guideMapFragment = null;
        } catch(IllegalStateException e) {
            Log.i(LOGTAG, "IllegalStateException on exit");
        }
    }
    super.onDestroyView();
}

Kötü olabilir, ama daha iyi bir şey bulamadı.


Trues .. istisna yakalamak uygulama çökmesini önleyebilir, ancak bu tür parçalar ekranda kalan ya da ek alamadım davranış sorunları.
Marcos Vasconcelos

4
kaydırmaya devam. gerçek orada
anil

4

Bu sorunu anladım, ancak bence bu sorun kesin ve commitAllowStateLoss ile ilgili değil.

Aşağıdaki yığın izleme ve özel durum iletisi commit () ile ilgilidir.

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

Ancak bu istisna onBackPressed () neden oldu

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(Unknown Source)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(Unknown Source)
at android.support.v4.app.FragmentActivity.onBackPressed(Unknown Source)

Bunların hepsine checkStateLoss () neden oldu

private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }

mStateSaved, onSaveInstanceState öğesinden sonra geçerli olacaktır.

Bu sorun nadiren olur.Bu sorunla daha önce hiç karşılaşmadım, sorunu tekrarlayamıyorum.

Bulduğum sorunu 25517

Aşağıdaki durumlarda meydana gelmiş olabilir

  1. Geri tuşu onSaveInstanceState öğesinden sonra ancak yeni etkinlik başlatılmadan önce çağrılır.

  2. kodda onStop () kullanın

Sorunun kökeninin ne olduğundan emin değilim. Çirkin bir yol kullandım.

@Override
public void onBackPressed() {

    try{
        super.onBackPressed();
    }catch (IllegalStateException e){
        // can output some information here
        finish();
    }
}

Sorunu gerçekten çözmedim, ancak bu sorun commit ve commitAllowStateLoss ile ilgili değil.
oO_ox

4

Uygulamamda da aynı sorunu var. Ben sadece super.onBackPressed();önceki sınıf çağrısı commitAllowingStateLoss()ve geçerli parça bu parça ile çağırma bu sorunu çözüldü .


2
Teşekkür ederim. Bu çözüm commitAllowingStateLoss()yerine sorunu çözdücommit()
Chintak Patel

CommitAllowingStateLoss () medium.com/@elye.project/…
swooby

3

Bir kullanıcı ekranı yeni yönlendirmeyle ilişkili kaynakları yükleyebilmesi için döndürürse onSaveInstance çağrılır.

Bu kullanıcının ekranı döndürmesi ve ardından geri düğmesine basması mümkündür (çünkü bu kullanıcının uygulamanızı kullanırken telefonunu çalması da mümkündür)


2
Yapılandırma değişiklikleri (yönlendirme değişiklikleri gibi) bu istisnayla sonuçlanabilirken, bunların temel nedeni değildir.
Alex Lockwood


2

Aynı konu benden ve bir gün süren analiz sonrası tüm makalelerin, blog ve stackoverflow basit bir çözüm buldum. SaveInstanceState işlevini hiç kullanmayın, bu bir kod satırının bulunduğu durumdur. Parça kodunda:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
    .....

2

Bu, bir parçayı yüklemeye çalıştığınızda ancak etkinliğin durumunu onPause () olarak değiştirdiğinde gerçekleşir.Bu, örneğin verileri getirmeye ve etkinliğe yüklemeye çalıştığınızda, ancak kullanıcı bir düğmeyi tıklayıp sonraki etkinliğe taşındı.

Bunu iki şekilde çözebilirsiniz

Parçayı yüklemek için transaction.commit () yerine transaction.commitAllowingStateLoss () öğesini kullanabilirsiniz, ancak tamamlanan tamamlama işlemini kaybedebilirsiniz.

veya

Bir parçayı yüklerken etkinliğin devam ettiğinden ve durma durumuna geçmediğinden emin olun. Bir boole oluşturun ve etkinliğin onPause () durumuna geçip gitmediğini kontrol edin.

@Override
public void onResume() {
    super.onResume();
    mIsResumed = true;
}

@Override
public void onPause() {
    mIsResumed = false;
    super.onPause();
}

daha sonra fragman yüklenirken etkinliğin olup olmadığını kontrol edin ve sadece etkinlik ön planda olduğunda yükleyin.

if(mIsResumed){
 //load the fragment
}

1

Teşekkürler @gunar, ama bence daha iyi bir yol var.

Doc göre:

 * If you are committing a single transaction that does not modify the
 * fragment back stack, strongly consider using
 * {@link FragmentTransaction#commitNow()} instead. This can help avoid
 * unwanted side effects when other code in your app has pending committed
 * transactions that expect different timing.
 *
 * @return Returns true if there were any pending transactions to be
 * executed.
 */
public abstract boolean executePendingTransactions();

Bu yüzden commitNowdeğiştirmek için kullanın :

fragmentTransaction.commit();
FragmentManager.executePendingTransactions()

0

Eh, yukarıdaki tüm çözümleri başarı olmadan denedikten sonra (çünkü temelde işlemleri yok).

Benim durumumda AlertDialogs ve ProgressDialog'u bazen FragmentManager'ı sorduğunuzda hata yükselen rotasyonlarda kullanıyordum.

Birkaç benzer gönderiyi karıştıran bir çözüm buldum:

Tümü FragmentActivity'de yapılan 3 adımlı bir çözüm (bu durumda, GenericActivity olarak adlandırılır):

private static WeakReference<GenericActivity> activity = null; //To avoid bug for fragments: Step 1 of 3

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    //To avoid bug for fragments: Step 2 of 3
    activity = new WeakReference<GenericActivity>(this);
}

@Override
public FragmentManager getSupportFragmentManager(){
    //To avoid bug for fragments: Step 3 of 3
    if (this == activity.get()) {
        return super.getSupportFragmentManager();
    }
    return activity.get().getSupportFragmentManager();
}

0

Bir parçada startactivity kullandığımda, bu istisnayı alacak;

Startactivityforresult kullanmak için değiştirdiğimde, istisna gitti :)

Bu yüzden düzeltmenin kolay yolu startActivityForResult api'yi kullanmaktır :)


0

Harita parçası etkinliğimdeki niyet seçiciyi iptal etmek için geri düğmesine basarken bu istisnayı alıyordum. Ben onStart () onResume () (burada parça başlatma ve işlem gerçekleştiriyordu) kodunu değiştirerek bu sorunu çözdü ve uygulama şimdi iyi çalışıyor. Umarım yardımcı olur.


0

Bu, Android 4.2 ve ayrıca destek kitaplığının kaynağında düzeltilmiştir. [*]

Nedenin (ve geçici çözümlerin) ayrıntıları için Google hata raporuna bakın: http://code.google.com/p/android/issues/detail?id=19917

Destek kitaplığını kullanıyorsanız, bu hata hakkında endişelenmenize gerek yoktur (uzun süre) [*]. Ancak, API'yı doğrudan kullanıyorsanız (yani, destek kitaplığının FragmentManager'ını kullanmıyorsanız) ve Android 4.2'nin altında bir API'yi hedefliyorsanız, geçici çözümlerden birini denemeniz gerekir.

[*] Yazma sırasında Android SDK Yöneticisi hala bu hatayı gösteren eski bir sürümü dağıtıyor.

Düzenle Buraya biraz açıklama ekleyeceğim çünkü bu cevabı kimin oy verdiğini bir şekilde karıştırdım.

Orada bu istisna atılmasına neden olabilir birkaç farklı (ancak ilgili) durumlar . Yukarıdaki cevabım, soruda tartışılan belirli bir örneğe, yani Android'de daha sonra düzeltilen bir hataya atıfta bulunmaktır. Bu istisnayı başka bir nedenden dolayı alıyorsanız, olmamak istediğinizde (parça durumları kaydedildikten sonra) parça eklemeniz / kaldırmanızdır. Böyle bir durumdaysanız, belki de " İç İçe Parçalar - IllegalStateException" Bu eylem onSaveInstanceState'den sonra gerçekleştirilemez " sizin için yararlı olabilir.



0

Kullanım durumum: Dinleyiciyi, bir şeylerin gerçekleştiğini bildirmek için parça parça kullandım. Geri arama yönteminde yeni parça çalışmaları yaptım. Bu ilk kez mükemmel çalışıyor. Ancak yönlendirme değişikliğinde, etkinlik kaydedilmiş örnek durumuyla yeniden oluşturulur. Bu durumda fragman tekrar yaratılmaz, fragmanın eski tahrip edilmiş aktivite olan dinleyiciye sahip olduğu anlamına gelir. Herhangi bir şekilde geri arama yöntemi işlem sırasında tetiklenir. Soruna neden olan yok edilen aktiviteye gider. Çözüm, dinleyiciyi mevcut canlı etkinlikle parçalanmış olarak sıfırlamaktır. Bu sorunu çözer.


0

Bulduğum şey, başka bir uygulama iletişim türü ise ve dokunuşların arka plan uygulamasına gönderilmesine izin veriyorsa, hemen hemen her arka plan uygulaması bu hatayla kilitlenir. Sanırım her işlem gerçekleştirildiğinde, örneğin kaydedilmiş veya geri yüklenmiş olup olmadığını kontrol etmemiz gerekiyor.


0

Benim durumumda, aynı hata istisnası ile, bir runnable "onBackPressed ()" koymak (görünümünüzden herhangi birini kullanabilirsiniz):

myView.post(new Runnable() {
                    @Override
                    public void run() {
                        onBackPressed()
                    }
                });

Nedenini anlamıyorum, ama işe yarıyor!


Bir görünümde yayın yapmak, yalnızca görünüm düzgün bir şekilde düzenlendikten ve ekrana çizildikten sonra Runnable'ı çalıştırır; bu genellikle Faaliyetin tamamen yeniden başladığı, dolayısıyla sorun olmadığı anlamına gelir
Mercato

0

FragmentManager.popBackStackImmediate (); etkinlik duraklatıldığında. Etkinlik tamamlanmadı, ancak duraklatıldı ve ön planda değil. PopBackStackImmediate () öğesinden önce etkinliğin duraklatılmış olup olmadığını kontrol etmeniz gerekir.


0

Çok ilginç bir şey fark ettim. Uygulamamda telefonun galerisini açma seçeneği var ve cihaz hangi uygulamanın kullanılacağını sorar, orada iletişim kutusundan uzak gri alanı tıklıyorum ve bu sorunu gördüm. Etkinliğimin onPause'dan, onSaveInstanceState'ten onResume'e nasıl gittiğini fark ettim, onCreateView'u ziyaret etmek olmaz. OnResume'ta işlemler yapıyorum. Bu yüzden ne yaptım sonunda bir bayrak ayarlandıOpause, ancak gerçek onCreateView olmak. bayrak onResume üzerinde true ise, onCommit yapın, aksi takdirde commitAllowingStateLoss. Devam edip çok zaman kaybedebilirdim ama yaşam döngüsünü kontrol etmek istedim. Sdkversion 23 olan bir cihazım var ve bu sorunu alamıyorum, ancak 21 olan başka bir cihazım var ve görüyorum.


-1

popBackStackImmediate'den önce FragmentActivity.onStart'ı kullanabilirsiniz

bunun gibi:

public void backStackFragment() {
    this.start();
    getFragmentManager().popBackStackImmediate();
}

public void start(){
    FragmentActivity a = getActivity();
    if(a instanceof DepositPlanPadActivity){
      ((DepositPlanPadActivity)a).onStart();
    }
    if(a instanceof SmallChangePlanPad){
            ((SmallChangePlanPad)a).onStart();
        }
        if(a instanceof UserCenterActivity){
            ((UserCenterActivity)a).onStart();
        }
    }

http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html

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.