अपवाद प्राप्त करना "IllegalStateException: onSaveInstanceState के बाद यह क्रिया नहीं कर सकता है"


355

मेरे पास एक लाइव एंड्रॉइड एप्लिकेशन है, और बाजार से मुझे स्टैक ट्रेस के बाद प्राप्त हुआ है और मुझे पता नहीं है कि ऐसा क्यों हो रहा है क्योंकि यह एप्लिकेशन कोड में नहीं हो रहा है, लेकिन इसकी एप्लिकेशन या धारणा से किसी अन्य घटना के कारण हो रहा है (धारणा)

मैं Fragments का उपयोग नहीं कर रहा हूं, फिर भी FragmentManager का एक संदर्भ है। यदि इस प्रकार के मुद्दे से बचने के लिए कोई भी निकाय कुछ छिपे हुए तथ्यों पर कुछ प्रकाश डाल सकता है:

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)  

क्या आपको अभी तक कोई समाधान मिला? यहाँ एक ही समस्या है: stackoverflow.com/questions/7575921/…
nhaarman


2
@phlebas नहीं आपने नहीं किया। आपका संवादों की चिंता करता है, और यह नहीं करता है। आपके स्टैक ट्रेस मिलान की शीर्ष पंक्ति पर्याप्त नहीं है। बाकी सब बहुत अलग है। मैं यह कहता हूं क्योंकि मैं सिर्फ आपके मुद्दे को देख रहा हूं और यह दुर्भाग्य से मेरे लिए कोई मदद नहीं है।
themightyjon

क्या आप उस गतिविधि में थ्रेड या AsynTask का उपयोग करते हैं?
जोस कास्त्रो

21
मैं अपने ब्लॉग पोस्ट में इस त्रुटि पर चर्चा करता हूं ... आपको इसे पढ़ना चाहिए। :)
एलेक्स लॉकवुड

जवाबों:


455

यह अब तक का सामना किया गया सबसे बेवकूफ बग है। मैं एक था Fragmentके लिए पूरी तरह से काम कर आवेदन एपीआई <11 , और Force Closingपर एपीआई> 11

मैं वास्तव में यह पता नहीं लगा पाया कि वे Activityकॉल में जीवनचक्र के अंदर क्या बदल गए हैं saveInstance, लेकिन मैं यहाँ है कि मैंने इसे कैसे हल किया:

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

मैं सिर्फ कॉल नहीं करता हूं .super()और सब कुछ बहुत अच्छा काम करता है। मुझे उम्मीद है कि यह आपको कुछ समय बचाएगा।

EDIT: कुछ और शोधों के बाद, यह सपोर्ट पैकेज में एक ज्ञात बग है।

यदि आपको उदाहरण सहेजने की आवश्यकता है, और अपने साथ कुछ जोड़ने के लिए outState Bundleआप निम्नलिखित का उपयोग कर सकते हैं:

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

EDIT2: यह तब भी हो सकता है जब आप Activityपृष्ठभूमि में चले जाने के बाद लेनदेन करने की कोशिश कर रहे हों । इससे बचने के लिए आपको इस्तेमाल करना चाहिएcommitAllowingStateLoss()

EDIT3: उपरोक्त समाधान शुरुआती समर्थन में समस्याओं को ठीक कर रहे थे। I4 लाइब्रेरी जो मुझे याद कर सकते हैं। लेकिन आप अगर आप अभी भी इस के साथ समस्या है चाहिए भी पढ़ @AlexLockwood : 'ब्लॉग टुकड़ा लेन-देन और गतिविधि राज्य में कमी

ब्लॉग पोस्ट से सारांश (लेकिन मैं आपको इसे पढ़ने के लिए जोरदार सलाह देता हूं):

  • प्री-हनीकॉम्ब पर और पोस्ट-हनीकॉम्ब के commit()बाद कभी भी लेनदेन न करेंonPause()onStop()
  • Activityजीवन चक्र के तरीकों के अंदर लेनदेन करते समय सावधान रहें । का उपयोग करें onCreate() , onResumeFragments()औरonPostResume()
  • अतुल्यकालिक कॉलबैक विधियों के अंदर लेनदेन करने से बचें
  • commitAllowingStateLoss()केवल अंतिम उपाय के रूप में उपयोग करें

97
आपको कम
meh

7
इसलिए onSaveInstanceState में सुपर कॉल न करना, FragmentManager को सभी टुकड़ों की स्थिति को बचाने और उन्हें पुनर्स्थापित करने में सक्षम होने से रोक देगा। यह रोटेशन के साथ समस्याओं का कारण हो सकता है। इसके अलावा, मैंने सिर्फ बंडल में कबाड़ डालने के बारे में दूसरी बात की कोशिश की है और इससे मेरे लिए कोई फर्क नहीं पड़ता है। निश्चित नहीं है कि यह कैसे होगा - आपने समर्थन पैकेज में जिस बग का संदर्भ दिया था, वह NullPointerException है, और यह IllegalStateException की तरह प्रतीत नहीं होता है ...
themightyjon

56
@meh commitAllowingStateLoss()केवल अपवाद से बचता है। यह आपके आवेदन को आकस्मिक राज्य हानि से बचाता नहीं है। इस ब्लॉग पोस्ट को देखें ।
एलेक्स लॉकवुड

2
उस ब्लॉग पोस्ट से @AlexLockwood हम सीख सकते हैं कि हमें अपने सभी नेटवर्क कॉल्स को खंड के अंदर करना चाहिए (और यदि आवश्यक हो तो कुछ अस्थायी प्रगति यूआई प्रदर्शित करें) और यही एकमात्र तरीका है कि हम इस अपवाद को प्राप्त करने से बच सकते हैं जब यह संभवत: ऐसा होता है कुछ अतुल्यकालिक विधि कॉल के बाद कॉल किया जा रहा है।
meh

1
मुझे पहला बिंदु नहीं मिलता है: "बाद में (ऑन पोस्ट-हनीकॉम्ब पर onStop () लेनदेन"। क्या होगा अगर मुझे एक टुकड़े को दूसरे के साथ बदलने के लिए ट्रिगर करने के लिए एक बटन की आवश्यकता होती है? क्या मुझे एक बूलियन डालनी चाहिए जो यह जांचता है कि गतिविधि समाप्त हो गई है या नहीं, और यदि ऐसा होता है, तो इसके बजाय कमिटिंग स्टैटिस्ट्रेट कॉल करें? इसके अलावा, क्या होगा अगर मेरे पास एक टुकड़े के भीतर एक टुकड़ा है, जिसे मुझे एक बटन पर क्लिक करने की आवश्यकता है?
Android डेवलपर

76

यह समस्या किन कारणों से एंड्रॉइड सोर्स कोड में देखती है कि फ्लैग mStateSaved इन FragmentManagerImplक्लास (उदाहरण एक्टिविटी में उपलब्ध है) वैल्यू ट्रू है। यह तब सही होता है जब कॉल से बैक स्टैक (saveAllState) सहेजा जाता है Activity#onSaveInstanceState। बाद में ActivThread से कॉल इस ध्वज को रीसेट नहीं करती है FragmentManagerImpl#noteStateNotSaved()और उपलब्ध रीसेट विधियों का उपयोग करके dispatch()

जिस तरह से मैं देख रहा हूँ कि आपके ऐप क्या कर रहा है और उपयोग कर रहा है, इसके आधार पर कुछ उपलब्ध फ़िक्सेस हैं:

अच्छे तरीके हैं

कुछ और करने से पहले: मैं एलेक्स लॉकवुड लेख का विज्ञापन करूंगा । फिर, मैंने अब तक क्या किया है:

  1. टुकड़े और गतिविधियों है कि किसी भी राज्य में जानकारी रखने के लिए की जरूरत नहीं है के लिए, फोन commitAllowStateLoss । प्रलेखन से लिया गया:

    किसी गतिविधि की स्थिति को सहेजने के बाद प्रतिबद्ध को निष्पादित करने की अनुमति देता है। यह खतरनाक है क्योंकि कमिट को खो दिया जा सकता है यदि गतिविधि को बाद में अपने राज्य से बहाल करने की आवश्यकता होती है, इसलिए इसका उपयोग केवल उन मामलों के लिए किया जाना चाहिए जहां उपयोगकर्ता पर अप्रत्याशित रूप से बदलने के लिए UI स्थिति के लिए ठीक है। मुझे लगता है कि यह उपयोग करने के लिए ठीक है अगर टुकड़ा केवल-पढ़ने के लिए जानकारी दिखा रहा है। या यहां तक ​​कि अगर वे संपादन योग्य जानकारी दिखाते हैं, तो संपादित जानकारी को बनाए रखने के लिए कॉलबैक विधियों का उपयोग करें।

  2. लेन-देन के ठीक बाद (आपने अभी कॉल किया है commit()), को कॉल करें FragmentManager.executePendingTransactions()

अनुशंसित तरीके नहीं:

  1. जैसा कि Ovidiu Latcu ने ऊपर उल्लेख किया है, कॉल न करें super.onSaveInstanceState()। लेकिन इसका मतलब है कि आप अपनी गतिविधि की संपूर्ण स्थिति को टुकड़ों के साथ खो देंगे।

  2. ओवरराइड onBackPressedऔर केवल कॉल में finish()। यह ठीक होना चाहिए यदि आप अनुप्रयोग Fragments API का उपयोग नहीं करते हैं; के रूप में super.onBackPressedकरने के लिए एक कॉल है FragmentManager#popBackStackImmediate()

  3. यदि आप दोनों Fragments API का उपयोग कर रहे हैं और आपकी गतिविधि की स्थिति महत्वपूर्ण / महत्वपूर्ण है, तो आप प्रतिबिंब API का उपयोग करके कॉल करने का प्रयास कर सकते हैं FragmentManagerImpl#noteStateNotSaved()। लेकिन यह एक हैक है, या कोई कह सकता है कि यह एक वर्कअराउंड है। मुझे यह पसंद नहीं है, लेकिन मेरे मामले में यह काफी स्वीकार्य है क्योंकि मेरे पास एक विरासत ऐप से एक कोड है जो कि पदावनत कोड ( TabActivityऔर अंतर्निहित रूप से LocalActivityManager) का उपयोग करता है ।

नीचे वह कोड है जो प्रतिबिंब का उपयोग करता है:

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

चीयर्स!


ऐसा लगता है कि ActionBarSherlock के साथ भी जिंजरब्रेड के तहत ऐसा होता है, इसलिए Build Id की जाँच करने का मामला मूक लगता है ... :(
t0mm13b

इसके अलावा, आपको इंगित करना चाहिए - जो ABS उपयोग के लिए उपयुक्त नहीं है :)
t0mm13b

@ t0mm13b: उपरोक्त कोड मेरी परियोजना के लिए खड़ा है क्योंकि यह न तो टुकड़ों का उपयोग करता है, न ही समर्थन। यह android.app.Activity पर चलता है और चूंकि असंगति जो अपवाद को ट्रिगर करती है, वह FragmentManager (API स्तर 11 ऊपर की ओर) के कारण होती है, इसीलिए चेक ... यदि आप मानते हैं कि बुराई का स्रोत भी आपके लिए समान है, तो बेझिझक चेक निकालने के लिए। ABS एक अलग कहानी है क्योंकि यह संगतता पैकेज के शीर्ष पर चलता है और समर्थन को लागू करता है। FramentActivity FragmentManager और voila के समान कार्यान्वयन का उपयोग कर सकता है: एक ही समस्या।
गनर

@ t0mm13b: 600 वर्णों को जोड़ने के लिए पर्याप्त नहीं हैं, आपको पहले जांच करनी होगी कि वास्तव में यह आपके लिए क्या कारण है। आपको यह भी महसूस करना होगा कि ऊपर एक बदसूरत हैक है और मैं कोई जिम्मेदारी नहीं ले रहा हूं अगर यह चलता है या नहीं (मेरे लिए परिस्थितियों को देखते हुए सबसे अच्छा समाधान था)। यदि आपको इसका उपयोग करना है, तो वेरिएबल नैमिंग्स के लिए कॉम्पेटिटर सोर्स कोड में डबल चेक करें क्योंकि वे मानक पैकेज से भिन्न हो सकते हैं। मुझे उम्मीद है कि इस मुद्दे को संगतता पैकेज के अगले संस्करणों से
निपटा जाएगा

उह ... इसका ठीक वैसा ही मुद्दा है जैसे इस बग रिपोर्ट में जो इस ओपी के सवाल का बिंदु है। मैं अपनी टिप्पणी के साथ खड़ा हूं - आपको स्पष्ट रूप से एक अस्वीकरण में डाल देना चाहिए और कहना चाहिए कि इसकी गारंटी नहीं है और यह भी कहा जाना चाहिए कि आपने टुकड़ों का उपयोग नहीं किया है - अन्यथा या तो उस उत्तर को पोस्ट करने में परेशान क्यों करें! :) बस कह रहा हूँ ...
t0mm13b

35

इस तरह के एक अपवाद तब होगा जब आप अपनी खंड गतिविधि के onSaveInstanceState()कॉल के बाद एक खंड संक्रमण करने की कोशिश करेंगे ।

ऐसा होने का एक कारण यह भी हो सकता है कि जब आप किसी गतिविधि को रोकते हैं तो आप AsyncTask(या Thread) को छोड़ देते हैं ।

बाद onSaveInstanceState()में कहा जाने वाला कोई भी संक्रमण संभावित रूप से नष्ट हो सकता है यदि सिस्टम संसाधनों के लिए गतिविधि को फिर से बताता है और इसे बाद में फिर से बनाता है।


2
अरे फंक, मेरा यहां एक सवाल है, कैसे आऊंगा ऑनबैकप्रेड को उस गतिविधि या खंड पर बुलाया जा सकता है, अगर उस गतिविधि या टुकड़े को रोक दिया गया है। उपरोक्त अपवाद कुछ UI ईवेंट (यानी बैक की की दबाकर) से उत्पन्न हुआ प्रतीत होता है, मैं हालांकि Async टास्क और बैक कुंजी के बीच के संबंध का पता लगाने में सक्षम नहीं हूं।
dcool

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

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

1
मेरे पास एक अंश के संदर्भ में एक AsyncTask था। सुपर () कॉल को onSaveInstanceState से निकालने और मेरे AsyncTask से WeakReference <Fragment> के संदर्भ को बदलने के बाद समस्या हल हो गई।
भैंस

2
@ बफलो निश्चित रूप से समस्या का समाधान नहीं है। आपको हमेशा कॉल करना चाहिए super.onSaveInstanceState()
एलेक्स लॉकवुड

27

बस अपने टुकड़े को दिखाने से पहले super.onPostResume () पर कॉल करें या super.onPostResume () पर कॉल करने के बाद onPostResume () विधि में अपना कोड स्थानांतरित करें। इस समस्या को हल!


6
OnPostResume () पर कॉल करना सुनिश्चित करता है कि onResumeFragments () कहा जाता है और मेरे लिए यह आदर्श समाधान है।
j2emanue

20

यह तब भी हो सकता है जब dismiss()स्क्रीन लॉक होने के बाद संवाद खंड पर कॉल किया जा रहा है \ n को बंद कर दिया गया है और गतिविधि + संवाद की स्थिति को सहेजा गया है। इस कॉल को प्राप्त करने के लिए:

dismissAllowingStateLoss()

वस्तुतः हर बार जब मैं एक संवाद को खारिज कर रहा होता हूँ, तो मुझे इस बात की कोई परवाह नहीं है कि यह अब वैसे भी है, इसलिए ऐसा करना ठीक है - आप वास्तव में किसी भी राज्य को नहीं खो रहे हैं।


2
यह मेरा सटीक मुद्दा था! आप साहब शानदार हैं!
ताश पेमहिवा

17

लघु और काम कर समाधान:

सरल चरणों का पालन करें:

चरण 1 : संबंधित खंड में onSaveInstanceState स्थिति को ओवरराइड करें। और इससे सुपर मेथड को हटा दें।

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

चरण 2 : कमलागेटस्टेटलॉस () का उपयोग करें; प्रतिबद्ध के बजाय (); टुकड़े के संचालन के दौरान।

fragmentTransaction.commitAllowingStateLoss();

1
सुपर विधि को हटाकर चाल चली गई, क्या आप बता सकते हैं कि हालांकि क्यों? क्या इसे हटाना सुरक्षित है?
ब्रूस

7
यह सुपर () को हटाने के लिए सुरक्षित नहीं है, आप उसके बाद अन्य डेटा को खो देंगे!
डेडफिश

12

मुझे लगता है कि लाइफसाइकल राज्य Android समर्थन से शुरू होने वाले ऐसे क्रैश को रोकने में मदद कर सकता है v26.1.0 आप निम्नलिखित जांच कर सकते हैं:

if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)){
  // Do fragment's transaction commit
}

या आप कोशिश कर सकते हैं:

Fragment.isStateSaved()

अधिक जानकारी यहाँ https://developer.android.com/reference/android/support/v4/app/Fragment.html#isStateSaved ()


7

यह मेरे लिए काम किया है ... यह अपने आप पता चला ... आशा है कि यह आपकी मदद करता है!

1) एक वैश्विक "स्थिर" FragmentManager / FragmentTransaction नहीं है।

2) onCreate, हमेशा FragmentManager को फिर से शुरू करें!

नीचे का नमूना: -

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 () विधि में टुकड़ा दिखाने की कोशिश करता था, तो मुझे यह हमेशा मिल रहा था, इसलिए समस्या अगली थी:

  1. मेरी गतिविधि को रोक दिया गया है और रोक दिया गया है, जिसका अर्थ है, कि onSaveInstanceState () को पहले से ही बुलाया गया था (पूर्व-हनीकॉम्ब और पोस्ट-हनीकॉम्ब दोनों उपकरणों के लिए)।
  2. किसी भी परिणाम के मामले में, मैंने टुकड़े को दिखाने / छिपाने के लिए लेन-देन किया, जो इस IllegalStateException का कारण बनता है।

मैंने जो बनाया है वह अगला है:

  1. यदि मैं चाहता हूं कि कार्रवाई का निर्धारण करने के लिए जोड़ा गया मूल्य (जैसे कैमेरे से फोटो लेना - isPhotoTaken) - यह बूलियन या पूर्णांक मूल्य हो सकता है जो आपको विभिन्न लेनदेन की आवश्यकता के आधार पर हो सकता है।
  2. Overriden onResumeFragments () मेथड में मैंने अपने मूल्य के लिए जाँच की और उसके बाद मेरे द्वारा किए जाने वाले टुकड़े के लेनदेन की आवश्यकता थी। इस स्थिति में onSaveInstanceState के बाद कमिट () नहीं किया गया था, क्योंकि राज्य को onResumeFragments () विधि में वापस कर दिया गया था।

5

मैंने इस मुद्दे को onconfigurationchanged के साथ हल किया। चाल यह है कि एंड्रॉइड गतिविधि जीवन चक्र के अनुसार, जब आप स्पष्ट रूप से एक आशय (कैमरा इरादा, या कोई अन्य) कहते हैं; गतिविधि रोक दी गई है और उस स्थिति में OnavedInstance कहा जाता है। जिस समय यह गतिविधि सक्रिय थी उस समय के अलावा किसी अन्य स्थान पर डिवाइस को घुमाते हुए; टुकड़े टुकड़े करना जैसे कि टुकड़े करना प्रतिबद्ध अवैध राज्य अपवाद का कारण बनता है। इसके बारे में बहुत सारी शिकायतें हैं। यह एंड्रॉइड गतिविधि जीवनचक्र प्रबंधन और उचित विधि कॉल के बारे में कुछ है। इसे हल करने के लिए मैंने ऐसा किया: 1-अपनी गतिविधि की ऑनवेड इनस्टेंस विधि को ओवरराइड करें, और वर्तमान स्क्रीन ओरिएंटेशन (पोर्ट्रेट या लैंडस्केप) को निर्धारित करें और फिर अपनी गतिविधि को रोकने से पहले अपने स्क्रीन ओरिएंटेशन को इसमें सेट करें। इस तरह से आप जिस गतिविधि को अपनी गतिविधि के लिए स्क्रीन रोटेशन को लॉक करते हैं, उसे किसी अन्य द्वारा घुमाए जाने की स्थिति में। 2-फिर, गतिविधि की ऑनरेसम विधि को ओवरराइड करें, और अपने अभिविन्यास मोड को अब सेंसर पर सेट करें ताकि ऑनवेड विधि को कॉल करने के बाद इसे रोटेशन से ठीक से निपटने के लिए एक बार ऑनकोफिग्योरेशन कहें।

इससे निपटने के लिए आप इस कोड को अपनी गतिविधि में कॉपी / पेस्ट कर सकते हैं:

@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

मुझे एक ही समस्या थी, IllegalStateException प्राप्त करना, लेकिन मेरे सभी कॉल को कमिट करने के लिए () प्रतिबद्धAllowingStateLoss () के साथ मदद नहीं की।

अपराधी डायलॉगफ्रेगमेंट.शो () के लिए एक कॉल था।

मैं इसे चारों ओर से घेरे हुए हूं

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

और यह किया है। ठीक है, मुझे संवाद दिखाने की जरूरत नहीं है, लेकिन इस मामले में यह ठीक था।

यह मेरे ऐप की एकमात्र जगह थी, जहाँ मैंने पहली बार FragmentManager.beginTransaction () कहा था, लेकिन कभी भी कमिट () नहीं कहा, इसलिए जब मैंने "कमिट ()" की तलाश की तो मुझे यह नहीं मिला।

मजेदार बात यह है, उपयोगकर्ता कभी भी ऐप नहीं छोड़ता है। हत्यारे के बजाय एक AdMob अंतरालीय विज्ञापन दिखा रहा था।


3
मुझे भी। मैंने 'शो (FragmentManager प्रबंधक, स्ट्रिंग टैग)' विधि को ओवरराइड करने से हल किया है, जो 'कमिट' की जगह 'कमिटमेंट' के साथ कर रहा है; कुछ खोने के कारण मैं डायलॉग की दो निजी विशेषताओं को सेट नहीं कर सकता: mDismissed और mShownByMe। लेकिन यह हर बार काम करने लगता है :)
फ्रांसेस्को दितरानी 20

मैंने DialogFragment का वैकल्पिक हल बनाया है, जो इस अपवाद से बच सकता है: github.com/AndroidDeveloperLB/DialogShard
Android डेवलपर

4

उस समस्या के लिए मेरा समाधान था

टुकड़े जोड़ने के तरीकों में:

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

बुरा हो सकता है, लेकिन कुछ भी बेहतर नहीं मिल सकता है।


Trues .. अपवाद को पकड़ने से एप्लिकेशन क्रैश से बचा जा सकता है, लेकिन व्यवहार के मुद्दे ऐसे टुकड़े स्क्रीन पर छोड़ दिए जाते हैं या जोड़ नहीं पाते हैं।
मार्कोस वास्कोनसेलोस

4
खिसकते रहो। सच्चाई वहाँ से बाहर है
anil

4

मुझे यह मुद्दा मिल गया था। लेकिन मुझे लगता है कि यह समस्या कमिट और कमिटमेंट से संबंधित नहीं है।

निम्नलिखित स्टैक ट्रेस और अपवाद संदेश कमिट () के बारे में है।

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)

लेकिन यह अपवाद onBackPressed () के कारण हुआ

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)

वे सभी checkStateLoss () के कारण थे

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

onSaveInstanceState के बाद mStateSaved सही होगा।

यह समस्या कभी-कभार ही होती है। मैंने कभी इस समस्या का सामना नहीं किया है। मैं इस समस्या का हल नहीं निकाल सकता।

मुझे मुद्दा 25517 मिला

यह निम्नलिखित परिस्थितियों में हुआ हो सकता है

  1. बैक कुंजी को onSaveInstanceState के बाद कहा जाता है, लेकिन नई गतिविधि शुरू होने से पहले।

  2. onStop () कोड में उपयोग करें

मुझे यकीन नहीं है कि समस्या की जड़ क्या है। इसलिए मैंने एक बदसूरत तरीका इस्तेमाल किया।

@Override
public void onBackPressed() {

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

मैंने वास्तव में समस्या का समाधान नहीं किया है, लेकिन यह समस्या कमिट और स्टालोस्टेट से संबंधित नहीं है।
o__ox

4

मुझे अपने ऐप में एक ही मुद्दा मिला है। मुझे इस मुद्दे को केवल super.onBackPressed();पिछले वर्ग commitAllowingStateLoss()पर कॉल करने और उस खंड के साथ वर्तमान कक्षा पर कॉल करने से हल किया गया है ।


2
धन्यवाद। इस समाधान ने समस्या को सुलझायाcommitAllowingStateLoss()commit()
चिंटक पटेल

प्रतिबद्धता का उपयोग करने से बचें ।AllowingStateLoss () medium.com/@elye.project/…
swooby

3

onSaveInstance को कहा जाएगा यदि कोई उपयोगकर्ता स्क्रीन को घुमाता है ताकि यह नए अभिविन्यास से जुड़े संसाधनों को लोड कर सके।

यह संभव है कि इस उपयोगकर्ता ने पीछे के बटन को दबाकर स्क्रीन को घुमाया (क्योंकि यह भी संभव है कि इस उपयोगकर्ता ने आपके ऐप के दौरान अपने फोन को fumbled किया हो)


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


2

मुझसे एक ही मुद्दा और सभी लेखों, ब्लॉग और स्टैकओवरफ़्लो के एक दिन के लंबे विश्लेषण के बाद मुझे एक सरल समाधान मिला है। SaveInstanceState का उपयोग बिल्कुल न करें, यह कोड की एक पंक्ति के साथ शर्त है। टुकड़े कोड पर:

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

2

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

आप इसे दो तरीकों से हल कर सकते हैं

आप विखंडन को लोड करने के लिए transaction.commit () के बजाय transaction.commitAllowingStateLoss () का उपयोग कर सकते हैं, लेकिन हो सकता है कि आपके द्वारा किए गए प्रतिबद्ध संचालन को समाप्त कर सकते हैं।

या

सुनिश्चित करें कि गतिविधि फिर से शुरू हो रही है और एक टुकड़ा लोड करते समय स्थिति को रोकने के लिए नहीं जा रहा है। एक बूलियन बनाएं और जांचें कि क्या गतिविधि ऑनपॉज़ () स्थिति में नहीं जा रही है।

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

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

तब टुकड़ा लोड करते समय जांच लें कि क्या गतिविधि मौजूद है और गतिविधि के सामने आने पर ही लोड करें।

if(mIsResumed){
 //load the fragment
}

1

धन्यवाद @ आंगन, लेकिन मुझे लगता है कि एक बेहतर तरीका है।

डॉक्टर के अनुसार:

 * 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();

इसलिए commitNowप्रतिस्थापित करने के लिए उपयोग करें:

fragmentTransaction.commit();
FragmentManager.executePendingTransactions()

0

ठीक है, सफलता के बिना उपरोक्त सभी समाधानों की कोशिश करने के बाद (क्योंकि मूल रूप से मेरे पास लेनदेन नहीं है)।

मेरे मामले में मैं AlertDialogs और ProgressDialog को टुकड़ों के रूप में उपयोग कर रहा था, कभी-कभी, रोटेशन पर, जब FragmentManager के लिए पूछते हैं, तो त्रुटि बढ़ जाती है।

मुझे कुछ समान पदों को मिलाकर एक वर्कअराउंड मिला:

इसका एक 3 कदम समाधान, सभी आपके FragmentActivity पर किया गया है (इस मामले में, इसे GenericActivity कहा जाता है):

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

जब मैं एक टुकड़े में startactivity का उपयोग करता हूं, तो मुझे यह अपवाद मिलेगा;

जब मैं startactivityforresult का उपयोग करने के लिए बदल, अपवाद चला गया है :)

तो इसे ठीक करने का आसान तरीका है startActivityForResult एपीआई का उपयोग करें :)


0

मुझे यह अपवाद तब मिल रहा था जब मैं अपने नक्शे विखंडन गतिविधि पर इरादा चयनकर्ता को रद्द करने के लिए बैक बटन दबा रहा था। मैंने onResume () के कोड को बदलकर इसे हल किया (जहां मैं टुकड़े को आरंभ कर रहा था और लेनदेन कर रहा था) onStart () और ऐप अब ठीक काम कर रहा है। आशा है ये मदद करेगा।


0

यह एंड्रॉइड 4.2 और समर्थन लाइब्रेरी के स्रोत में भी तय किया गया है। [*]

कारण (और काम के इर्द-गिर्द) की जानकारी के लिए Google बग रिपोर्ट देखें: http://code.google.com/p/android/issues/detail?id=19917

यदि आप समर्थन लाइब्रेरी का उपयोग कर रहे हैं, तो आपको इस बग (लंबे समय तक) [*] के बारे में चिंता नहीं करनी चाहिए। हालाँकि, यदि आप सीधे API का उपयोग कर रहे हैं (अर्थात सपोर्ट लाइब्रेरी के FragmentManager का उपयोग नहीं कर रहे हैं) और Android 4.2 के नीचे एक API को लक्षित कर रहे हैं, तो आपको काम-आसनों में से एक को आज़माना होगा।

[*] एंड्रॉइड एसडीके प्रबंधक लिखने के समय अभी भी एक पुराना संस्करण वितरित कर रहा है जो इस बग को प्रदर्शित करता है।

संपादित करें मैं यहां कुछ स्पष्टीकरण जोड़ने जा रहा हूं क्योंकि मैंने स्पष्ट रूप से किसी को भ्रमित कर दिया है जिसने भी इस जवाब को वोट दिया है।

कर रहे हैं कई अलग अलग (लेकिन संबंधित) परिस्थितियों कि पैदा कर सकता है यह अपवाद उत्पन्न होने के लिए । ऊपर दिया गया मेरा उत्तर प्रश्न में चर्चा किए गए विशिष्ट उदाहरण की ओर इशारा कर रहा है अर्थात Android में एक बग जिसे बाद में ठीक किया गया है। यदि आपको यह अपवाद मिल रहा है, तो इसका कारण यह है कि जब आप नहीं होना चाहिए (जब टुकड़े राज्यों को सहेजे गए हैं) तो आप जोड़ / हटा रहे हैं। यदि आप ऐसी स्थिति में हैं, तो शायद " नेस्टेड फ़्रैगमेंट्स - इललीगलस्टैटेसेप्शन" onSaveInstanceState के बाद यह क्रिया नहीं कर सकते हैं " " आपके लिए उपयोग की जा सकती है।



0

मेरा उपयोग मामला: मैंने गतिविधि को अधिसूचित करने के लिए श्रोता का उपयोग किया है कि कुछ बात हुई। मैंने कॉलबैक पद्धति पर नए टुकड़े किए। यह पहली बार में पूरी तरह से ठीक काम करता है। लेकिन अभिविन्यास परिवर्तन पर गतिविधि को सहेजे गए इंस्टेंस राज्य के साथ फिर से बनाया जाता है। उस मामले में टुकड़ा फिर से नहीं बनाया जाता है इसका मतलब है कि टुकड़े में श्रोता है जो पुरानी नष्ट गतिविधि है। किसी भी तरह से कॉल बैक विधि से कार्रवाई शुरू हो जाएगी। यह नष्ट हो गई गतिविधि जो समस्या का कारण बनती है। इसका समाधान श्रोता को वर्तमान लाइव गतिविधि के साथ टुकड़े में रीसेट करना है। इससे समस्या का समाधान होता है।


0

मैंने जो पाया वह यह है कि यदि कोई अन्य ऐप डायलॉग टाइप है और टच को बैकग्राउंड ऐप पर भेजने की अनुमति देता है तो लगभग कोई भी बैकग्राउंड ऐप इस त्रुटि से क्रैश हो जाएगा। मुझे लगता है कि अगर हर बार ट्रांज़ेक्शन को सेव या रिस्टोर किया जाता है तो हमें हर बार चेक करना होगा।


0

मेरे मामले में, एक ही त्रुटि अपवाद के साथ, मैंने "onBackPressed ()" को एक रननेबल में रखा (आप अपने किसी भी दृश्य का उपयोग कर सकते हैं):

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

मुझे समझ नहीं आता कि क्यों, लेकिन यह काम करता है!


एक दृश्य पर पोस्टिंग केवल रननेबल को चलाएगी जब दृश्य को ठीक से बाहर रखा गया हो और स्क्रीन पर खींचा गया हो; इसका अर्थ अक्सर गतिविधि को पूरी तरह से फिर से शुरू कर दिया जाता है, इसलिए कोई समस्या नहीं है
Mercato

0

आप कॉल कर सकते हैं fragmentManager.popBackStackImmediate (); जब गतिविधि रोक दी जाती है। गतिविधि समाप्त नहीं हुई है, लेकिन रुकी हुई है और अग्रभूमि पर नहीं है। आपको यह जांचने की आवश्यकता है कि क्या गतिविधि रोक दी गई है या पॉपबैकस्टैकमीमेडेट () से पहले नहीं है।


0

मुझे कुछ बहुत ही रोचक लगा। मेरे पास मेरे ऐप में फोन की गैलरी को खोलने का विकल्प है और डिवाइस पूछता है कि किस ऐप का उपयोग करना है, वहां मैं डायल से दूर ग्रे क्षेत्र पर क्लिक करता हूं और इस मुद्दे को देखा। मैंने देखा कि मेरी गतिविधि onPause, onSaveInstanceState से onResume पर कैसे जाती है, यह onCreateView पर जाने के लिए नहीं होता है। मैं onResume पर लेनदेन कर रहा हूं। तो मैंने जो किया वह समाप्त हो रहा है एक ध्वज स्थापित किया जा रहा है, लेकिन यह सच है onCreateView। अगर झंडा सच है, तो फिर चालू करें, ऑन करें, अन्यथा कम करें। मैं इतना समय बर्बाद कर सकता था लेकिन मैं जीवनचक्र की जांच करना चाहता था। मेरे पास एक डिवाइस है जो sdkversion 23 है, और मुझे यह समस्या नहीं मिलती है, लेकिन मेरे पास एक और है जो 21 है, और वहां मैं इसे देखता हूं।


-1

आप PopBackStackImmediate से पहले FragmentActivity.onStart का उपयोग कर सकते हैं

इस तरह:

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.