ViewPager के साथ टैब का उपयोग करते समय त्रुटि "Java.lang.IllegalStateException गतिविधि नष्ट हो गई है"


110

मेरे पास एक एप्लिकेशन है जिसमें टैब मोड में ActionBarSherlock का उपयोग करना है। मेरे पास 5 टैब हैं और प्रत्येक टैब की सामग्री को टुकड़ों का उपयोग करके नियंत्रित किया जाता है। Tab2 के लिए, हालांकि, मेरे पास एक xml फ़ाइल है, जिसमें एक ViewPager तत्व है, जिसके बदले में कुछ खंड पृष्ठ हैं। जब मैं शुरू में आवेदन शुरू करता हूं, तो मैं टैब के बीच स्विच करने में सक्षम हूं कोई समस्या नहीं है लेकिन जब मैं दूसरी बार टैब 2 पर प्रेस करता हूं तो मुझे ऊपर उल्लिखित त्रुटि मिलती है। मुख्य गतिविधि इस प्रकार है:

public class MainActivity extends SherlockFragmentActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar actionBar = getSupportActionBar();

        ActionBar.Tab tab1 = actionBar.newTab().setText("Tab1");
        ActionBar.Tab tab3 = actionBar.newTab().setText("Tab3");
        ActionBar.Tab tab2 = actionBar.newTab().setText("Tab2");
        ActionBar.Tab tab4 = actionBar.newTab().setText("Tab4");
        ActionBar.Tab tab5 = actionBar.newTab().setText("Tab5");

        Fragment fragment1 = new Tab1();
        Fragment fragment3 = new Tab3();
        Fragment fragment2 = new Tab2();
        Fragment fragment5 = new Tab5();
        Fragment fragment4 = new Tab4();

        tab1.setTabListener(new MyTabListener(fragment1));
        tab3.setTabListener(new MyTabListener(fragment3));
        tab2.setTabListener(new MyTabListener(fragment2));
        tab5.setTabListener(new MyTabListener(fragment5));
        tab4.setTabListener(new MyTabListener(fragment4));

        actionBar.addTab(tab1);
        actionBar.addTab(tab2);
        actionBar.addTab(tab3);
        actionBar.addTab(tab4);
        actionBar.addTab(tab5); 

        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    }

    class MyTabListener implements ActionBar.TabListener
    {
        Fragment fragment;

        public MyTabListener(Fragment fragment)
        {
            this.fragment = fragment;
        }

        @Override
        public void onTabSelected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {
            ft.replace(R.id.fragment_container,fragment);
        }

        @Override
        public void onTabUnselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {

        }

        @Override
        public void onTabReselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft) 
        {

        }
    }
}

ViewPager के बिना टुकड़ा वर्ग निम्नानुसार है:

public class Tab1 extends Fragment 
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.activity_tab1, container, false);
    }
}

ViewPager के साथ टुकड़ा वर्ग निम्नानुसार है:

public class Tab2 extends Fragment 
{
    ViewPager mViewPager;
    private MyFragmentPagerAdapter mMyFragmentPagerAdapter;  
    private static int NUMBER_OF_PAGES = 5;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
    {
        View view =  inflater.inflate(R.layout.activity_tab2, container, false); 
        return view;
    }

    @Override
    public void onViewCreated(View view,Bundle savedInstanceState)
    {
        super.onViewCreated(view, savedInstanceState);
        mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
        mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());  
        mViewPager.setAdapter(mMyFragmentPagerAdapter);  
    }

    private static class MyFragmentPagerAdapter extends FragmentPagerAdapter 
    {    
        public MyFragmentPagerAdapter(FragmentManager fm) 
        {  
             super(fm);  
        }  

        @Override  
        public Fragment getItem(int index) 
        {  
             return PageFragment.newInstance("My Message " + index);
        }  

        @Override  
        public int getCount() 
        {  
             return NUMBER_OF_PAGES;  
        }  
   }
}

जो मैंने विभिन्न स्थानों में पढ़ा है (और अगर मैं गलत हूं तो कृपया मुझे सुधारें), यह इसलिए होता है क्योंकि दूसरे पास पर टुकड़ा प्रबंधक उस गतिविधि से टुकड़ों का पुन: उपयोग करने की कोशिश करता है जो अब मौजूद नहीं है और इस प्रकार त्रुटि दे रहा है। लेकिन मुझे यकीन नहीं है कि यह यहाँ पर क्यों होता है क्योंकि मैं खंड गतिविधि का उपयोग नहीं कर रहा हूँ। Logcat के अनुसार त्रुटि Tab2 वर्ग में है, लाइन पर onViewCreated विधि जो mViewPager.setAdapter (mMyFragmentPagerAdapter) कहती है। किसी भी मदद की बहुत सराहना की है ... धन्यवाद

03-04 12:01:05.468: E/AndroidRuntime(2474): FATAL EXCEPTION: main
03-04 12:01:05.468: E/AndroidRuntime(2474): java.lang.IllegalStateException: Activity has been destroyed
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1342)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:578)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:139)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.populate(ViewPager.java:1011)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.populate(ViewPager.java:880)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:433)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.example.tabs.Tab2.onViewCreated(Tab2.java:31)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:925)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Handler.handleCallback(Handler.java:587)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Handler.dispatchMessage(Handler.java:92)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.os.Looper.loop(Looper.java:123)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at android.app.ActivityThread.main(ActivityThread.java:3687)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at java.lang.reflect.Method.invokeNative(Native Method)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at java.lang.reflect.Method.invoke(Method.java:507)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
03-04 12:01:05.468: E/AndroidRuntime(2474):     at dalvik.system.NativeStart.main(Native Method)

इसलिए मुझे लगता है कि मुझे समस्या मिल गई होगी। ग्रहण डिबगर के माध्यम से चर mMyFragmentPagerAdapter (वर्ग Tab2) को देखते हुए, मैंने देखा कि इसमें एक FragmentManager चर था, जब पहली बार Tab2 पर क्लिक करने पर एक फ़ील्ड था जिसे mctctivity कहा जाता था जो कि MainActivity.But पर टैब 2 से स्विच करने पर इंगित करता था। अन्य टैब और mActivity को देखकर फिर से अशक्त होने का मूल्य था, जो शायद यह बताता है कि इसकी त्रुटि गतिविधि को नष्ट क्यों किया गया है।
यूल्रिक सेकीरा

जवाबों:


284

यह नेस्टेड टुकड़ों के लिए नए जोड़े गए समर्थन में एक बग प्रतीत होता है। मूल रूप FragmentManagerसे, गतिविधि से अलग होने पर बच्चा एक टूटी हुई आंतरिक स्थिति के साथ समाप्त होता है। एक छोटी अवधि का वर्कअराउंड जो मेरे लिए तय किया गया है, वह यह है कि आप onDetach()हर Fragmentकॉल getChildFragmentManager()पर निम्नलिखित को जोड़ें :

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

    try {
        Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
        childFragmentManager.setAccessible(true);
        childFragmentManager.set(this, null);

    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

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

14
तुम जरूर मजाक कर रहे हो। खुशी है कि आप इस पोस्ट किया है, लेकिन अच्छा दु: ख।
18

8
यह बग एंड्रॉइड ओपन सोर्स इशू ट्रैकर में कोड किया जा रहा है: code.google.com/p/android/issues/detail?id=42601
क्रिस्टोफर जॉनसन

3
एक चुटकी नमक, लेकिन यह समर्थन- v4 संस्करण या android.app संस्करण का उपयोग करके विफल हो रहा है। तो बग न केवल समर्थन पुस्तकालय में होता है
gbero

6
यह समर्थन लाइब्रेरी संस्करण 24.0.0 में निश्चित है। 'Android.support.v4.app.Fragment' की विधि 'performDetach ()', 'mChildFragmentManager = null;' करें।
एमर्सन डेल्नाग्नोल

13

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

ft.replace(R.id.fragment_container, Fragment.instantiate(PlayerMainActivity.this, fragment.getClass().getName()));

एक वास्तविक समाधान नहीं है, लेकिन मुझे पिछले टुकड़े के पुन: उपयोग का तरीका नहीं मिला है ...


1
वाह बहुत बहुत धन्यवाद ... जिसने समस्या को ठीक कर दिया। क्या यह स्पष्टीकरण देना संभव है कि यह क्यों काम करता है? मैं अपने सिर को तोड़ रहा था, जो कि फ्रैगमेंटमैन का उपयोग करके त्रुटि को ठीक करने की कोशिश कर रहा था।
1925 में यूलिक सेकेरा

1
क्या आपने अपनी स्मृति पदचिह्न का विश्लेषण किया है? क्योंकि यह वर्कअराउंड इसे बढ़ा सकता है, कम से कम मुझे संदेह है
nmxprime

न जाने क्यों यह काम करता है..नहीं जानता कि यह कैसे काम करता है लेकिन यह काम करता है

7

मुझे super.onCreate()अपनी पद्धति के अंत में कॉल करते समय उसी समस्या का सामना करना पड़ा । कारण: attachActivity()FrCmentActivity के onCreate () में कहा जाता है। जब ओवरराइडिंग onCreate()और, उदाहरण के लिए, टैब बना रहे हैं, तब टैब प्रबंधक FragmentManager से जुड़ी गतिविधि नहीं करते हुए एक खंड में स्विच करने का प्रयास करेगा।

सरल समाधान: कॉल को super.onCreate()फ़ंक्शन बॉडी के प्रमुख पर ले जाएं ।

सामान्य तौर पर, ऐसा लगता है कि इस समस्या के कारणों का भार हो सकता है। यह सिर्फ एक और एक है ...

मथायस


आपका बहुत-बहुत धन्यवाद, आपने मेरा दिन बचाया! मेरे पास एक ही समस्या थी और एक सप्ताह के बाद भी इसे हल नहीं किया जा सका? (इसलिए बहुत खुश हूँ आपने यह उत्तर लिखा है !!!
जोनासपीटीएफएल

4

जोड़ना चाहते थे कि मेरी समस्या एक ऐसी गतिविधि में थी जहाँ मैंने कोशिश की थी कि मुझे FragmentTransactionपहले से बुलाया गया था super.onCreate()। मैं सिर्फ super.onCreate()समारोह के शीर्ष पर चला गया और ठीक काम किया गया।


2

मुझे यह त्रुटि थी क्योंकि मैं LocalBroadcastManager का उपयोग कर रहा था और मैंने किया था:

unregisterReceiver(intentReloadFragmentReceiver);

के बजाय:

LocalBroadcastManager.getInstance(this).unregisterReceiver(intentReloadFragmentReceiver);

1
यह मेरी संभावना को हल नहीं करता है। लेकिन धन्यवाद इससे मुझे ब्रॉडकास्टर्स का उपयोग करने पर अपनी गलतियों को ठीक करने में मदद मिली
nmxprime

यदि आपकी गतिविधि का संदर्भ शून्य है तो क्या होगा। तब 'यह' मान्य नहीं होगा।
इगोरगानापोलस्की

जब गतिविधियों का संदर्भ शून्य हो सकता है? मुझे लगता है कि कभी नहीं।
मलयासीज

2

मुझे उसी मुद्दे का सामना करना पड़ा और बाद में पता चला कि, मुझे फ्रैगमेंटएक्टिविटी super.onCreate( savedInstanceState );में मिस्ड कॉल है onCreate()


1

मुझे बहुत ही त्रुटि मिली जब FragmentManagerटुकड़े को पूरी तरह से शुरू करने से पहले बच्चे तक पहुंचने की कोशिश की गई थी (यानी गतिविधि से जुड़ी या कम से कम onCreateView()कहा जाता है)। एल्स को FragmentManagerएक nullगतिविधि के साथ आरंभिक रूप दिया जाता है, जो उपरोक्त अपवाद का कारण बनता है।


1

मैं बच्चे के टुकड़े से युक्त टुकड़े को बलपूर्वक NULL को ऑनपॉज़ करता हूं और यह मेरी समस्या को ठीक करता है

fragment = null;

1

मुझे पता है कि यह एक पुरानी पोस्ट है, लेकिन सुझाए गए उत्तर मेरे अंत में काम नहीं करते। मैं इसे यहां छोड़ना चाहता हूं, जब कोई इसे उपयोगी समझेगा।

मैंने क्या किया है:

@Override
public void onResume() {
    super.onResume();
    // add all fragments
    FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
    for(Fragment fragment : fragmentPages){
        String tag = fragment.getClass().getSimpleName();
        fragmentTransaction.add(R.id.contentPanel, fragment, tag);
        if(fragmentPages.indexOf(fragment) != currentPosition){
            fragmentTransaction.hide(fragment);
        } else {
            lastTag = tag;
        }
    }
    fragmentTransaction.commit();
}

फिर:

@Override
public void onPause() {
    super.onPause();
    // remove all attached fragments
    for(Fragment fragment: fragmentPages){
        getChildFragmentManager().beginTransaction().remove(fragment).commit();
    }
}

0

मुझे यह समस्या थी और मैं यहां समाधान नहीं ढूंढ सका, इसलिए मैं अपना समाधान साझा करना चाहता हूं अगर किसी और को यह समस्या फिर से हो।

मेरे पास यह कोड था:

public void finishAction() {
  onDestroy();
  finish();
}

और लाइन "onDestroy ();" को हटाकर समस्या का समाधान करें

public void finishAction() {
  finish();
}

कारण मैंने प्रारंभिक कोड लिखा था: मुझे पता है कि जब आप "फिनिश ()" गतिविधि को "onDestroy ()" कहते हैं, लेकिन मैं थ्रेड्स का उपयोग कर रहा हूं और मैं यह सुनिश्चित करना चाहता था कि अगली गतिविधि शुरू करने से पहले सभी धागे नष्ट हो जाएं। , और ऐसा लगता है कि "खत्म ()" हमेशा तत्काल नहीं होता है। मुझे बहुत सारे "बिटमैप" को संसाधित करने / कम करने और बड़े "बिटमैप" को प्रदर्शित करने की आवश्यकता है और मैं अपने ऐप में मेमोरी के उपयोग को बेहतर बनाने पर काम कर रहा हूं

अब मैं एक अलग विधि का उपयोग करके थ्रेड्स को मारूंगा और मैं "onDestroy ();" और जब मुझे लगता है कि मुझे सभी धागों को मारने की जरूरत है।

public void finishAction() {
  onDestroyThreads();
  finish();
}

0

मैं इस मुद्दे पर था और महसूस किया कि यह गया था क्योंकि मैं बुला रहा था setContentView(int id)मेरी में दो बार ActivityकीonCreate


0

इसने मुझे ज़मीर के लिए पागल कर दिया।

मैं एक दृश्य के साथ TabLayout के लिए एक ViewPager कार्यान्वयन के साथ इस में भाग गया, जो खुद DrawerLout में लागू किया गया है:

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

तो आपको अपने दराज में निम्नलिखित कोड को लागू करना होगा । सही FragmentManager-Path चुनने के लिए जागरूक रहें। क्योंकि आपके पास दो भिन्न FragmentManager संदर्भ हो सकते हैं:

  1. Android.Support.V4.App.FragmentManager
  2. Android.App.FragmentManager

-> जो आप उपयोग करते हैं उसे चुनें। यदि आप ChildFragmentManager का उपयोग करना चाहते हैं, तो आपको कक्षा घोषणा का उपयोग करना था। Android.App.FragmentManager अपने ViewPager के लिए !

Android.Support.V4.App.FragmentManager

निम्नलिखित विधि को अपने "मुख्य" खंड में लागू करें - इस उदाहरण में: दराजफ्रेग्मेंट

public override void OnDetach() {
    base.OnDetach();
    try {
        Fragment x = this;
        var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
        IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
        var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/support/v4/app/FragmentManagerImpl;");
        JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
    }
    catch (Exception e) {
        Log.Debug("Error", e+"");
    }
}

Android.App.FragmentManager

public class TabViewPager: Android.Support.V13.App.FragmentPagerAdapter {}

इसका मतलब है कि आपको Android.App के साथ ViewPager में प्रवेश करना था।

निम्नलिखित विधि को अपने "मुख्य" खंड में लागू करें - इस उदाहरण में: दराजफ्रेग्मेंट

public override void OnDetach() {
    base.OnDetach();
    try {
        Fragment x = this;
        var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
        IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
        var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/app/FragmentManagerImpl;");
        JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
    }
    catch (Exception e) {
        Log.Debug("Error", e+"");
    }
}

0

बग को नवीनतम Androidx संस्करण में तय किया गया है। और प्रसिद्ध वर्कअराउंड दुर्घटना का कारण बनेगा। इसलिए हमें अब इसकी आवश्यकता नहीं है।

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