2013-02-11 35 views
8

प्रसंग की कोशिश कर रहा: मैं एक Fragment और 3 InnerFragments के साथ एक Activity है। जब FragmentonDestroy() कहा जाता है, तो मैं FragmentManager से आंतरिक टुकड़े को हटाना चाहता हूं। onDestroy() से कोड नीचे है।FragmentManager NullPointerException जब commitAllowingStateLoss को

समस्या:FragmentManagerNullPointerException फेंकता है, शायद जब commitAllowingStateLoss() कहा जाता है। मुझे समझ में नहीं आता क्यों।

@Override 
public void onDestroy() 
{ 
    super.onDestroy(); 
    if (getFragmentManager().findFragmentById(R.id.fragment_framelayout_left) != null) 
    { 
     FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 
     fragmentTransaction.remove(mLeftFragment); 
     fragmentTransaction.commitAllowingStateLoss(); 
    } 
} 

स्टैक ट्रेस: ​​

02-11 12:15:14.162: E/AndroidRuntime(25911): FATAL EXCEPTION: main 
02-11 12:15:14.162: E/AndroidRuntime(25911): java.lang.NullPointerException 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1419) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.handleCallback(Handler.java:725) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.dispatchMessage(Handler.java:92) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Looper.loop(Looper.java:137) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.app.ActivityThread.main(ActivityThread.java:5039) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invokeNative(Native Method) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invoke(Method.java:511) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at dalvik.system.NativeStart.main(Native Method) 
+1

मैं अपनी वास्तुकला पूरी तरह से पालन नहीं कर रहा हूँ। 'इनफ्रैगमेंट्स' को 'फ्रैगमेंट' में लाइव करें? यदि ऐसा है, तो मुझे लगता है कि आपको 'getChildFragmentManager()' प्रबंधित करना चाहिए ('गतिविधि' के 'FragmentManager' नहीं)। इस तरह, जब 'फ्रैगमेंट' नष्ट हो जाता है, तो इस अतिरिक्त कोड के बिना, इसके बच्चे 'इनरफ्रैगमेंट्स' भी होते हैं। –

+0

हां, आंतरिक टुकड़े टुकड़े के अंदर रहते हैं (कम से कम गोलियों पर)। फोन पर, वे एक गतिविधि के अंदर रहते हैं (गतिविधि 1 के अंदर InnerFragment1, गतिविधि 2 के अंदर InnerFragment2)। यही कारण है कि मैं उस कोड का उपयोग कर रहा था। क्या यह गतिविधियों में getChildFragmentManager() के साथ भी काम करेगा? LE: बेवकूफ सवाल, क्षमा करें। मैं कुछ घंटों में अपना विचार आज़माउंगा और देख सकता हूं कि यह कैसा चल रहा है। –

+1

'getChildFragmentManager()' केवल 'Fragments' में है, क्योंकि 'गतिविधियां' बच्चों को 'FragmentManagers' तक नहीं पहुंच सकती हैं। हालांकि, 'Fragments'' getFragmentManager() 'को कॉल कर सकते हैं और अपने माता-पिता' गतिविधि 'के' FragmentManager' तक पहुंच सकते हैं, जिससे उन्हें अपने माता-पिता 'गतिविधि' की आवश्यकता के बिना स्वयं के शीर्ष पर 'Fragments' शुरू करने की अनुमति मिलती है। –

उत्तर

9

FragmentManagerActivity स्तर पर सभी Fragments प्रबंधन करता है और उनके जीवन चक्र है कि माता-पिता Activity से संबद्ध रहेगा। बच्चे Fragment प्रबंधक Fragment स्तर पर सभी Fragments प्रबंधित करता है, और उनका जीवन चक्र उस माता-पिता Fragment से बंधेगा।

तो अपने फोन आर्किटेक्चर के लिए, अपने को अपने Activity पर getFragmentManager() का उपयोग करके जोड़ें। जब Activity अच्छे के लिए नष्ट हो जाता है (बैक बटन/finish() के माध्यम से), FragmentManager आपके लिए InnerFragment को नष्ट कर देगा और रिलीज़ करेगा।

अपने टेबलेट आर्किटेक्चर के लिए, InnerFragments अपने Fragment पर getChildFragmentManager() (नवीनतम समर्थन लाइब्रेरी में) का उपयोग करके जोड़ें। जब Fragment अच्छे के लिए नष्ट हो जाता है, तो FragmentManager आपके लिए InnerFragments को नष्ट कर देगा और रिलीज़ करेगा।

आपको अपने Fragments को रिलीज़ और नष्ट करने का प्रबंधन नहीं करना चाहिए। मैं आपके Activities और Fragments की जीवन चक्र घटनाओं को लॉगिंग करने की अनुशंसा करता हूं ताकि आप उन्हें अपने राज्यों के माध्यम से देख सकें और सही व्यवहार सुनिश्चित कर सकें।

+0

बहुत बढ़िया। बहुत बहुत धन्यवाद। यह हल हो गया। एक मामूली समस्या।अगर मैं ChildFragmentManager का उपयोग करता हूं, तो मैं बच्चे के टुकड़े पर रीटेन इंस्टेंस (सत्य) सेट नहीं कर सकता। क्या आसपास कोई काम है ? या ऐसा क्यों व्यवहार करना चाहिए? –

+1

'setRetainInstance (true)' का उपयोग करना वास्तव में पहले से ही एक कामकाज है। Google सुझाया गया दृष्टिकोण किसी भी परिवर्तनीय स्थिति को 'onSaveInstanceState()' में सहेजना है और इसे 'ऑनक्रेट' और 'ऑन क्रिएटिव्यू' में पुनर्स्थापित करना है। किसी भी समय, ओएस स्मृति पर कम चला सकता है और आपके 'Fragments' और/या' क्रियाएँ 'को नष्ट करने की आवश्यकता है, इसलिए यह उनकी ज़िम्मेदारी है कि वे वर्तमान में कैसे हैं, और उपयोगकर्ता को दिखाई देने के लिए उस स्थिति को पुनर्स्थापित करें क्योंकि वे वापस आने पर कुछ भी नहीं बदला है। यहां बताया गया है कि Google आपको राज्य को बचाने की सिफारिश करता है http://developer.android.com/training/basics/activity-lifecycle/recreating.html। –

+1

और यहां 'setRetainInstance (true)' के बारे में कुछ और जानकारी दी गई है - http://stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean –

1

NullPointerException तथ्य यह है कि गतिविधि के हैंडलर FragmentManager से सेट नहीं होने के कारण होता है, तो एक "समाधान" है कि दुर्घटना को रोकने जाएगा निम्नलिखित:

public void onDestroy(){ 
     super.onDestroy(); 
     try { 
      Field mActivityField = getFragmentManager().getClass().getDeclaredField("mActivity"); 
      mActivityField.setAccessible(true); 
      mActivityField.set(getFragmentManager(), this); 

      Field mPendingActionsField = getFragmentManager().getClass().getDeclaredField("mPendingActions"); 
      mPendingActionsField.setAccessible(true); 
      mPendingActionsField.set(getFragmentManager(), null); 


      Field f = Activity.class.getDeclaredField("mHandler"); 
      f.setAccessible(true); 
      Handler handler = (Handler) f.get(this); 
      handler.close(); 
     } catch (Throwable e) { 

     } 
}