ViewPager ile sekmeleri kullanırken "Java.lang.IllegalStateException Activity yok edildi" hatası alınıyor


110

Sekme modunda ActionBarSherlock kullanmaktan oluşan bir uygulamam var. 5 sekmem var ve her sekmenin içeriği parçalar kullanılarak işleniyor. Tab2 için yine de, xml dosyasında bir ViewPager öğesi tutan ve daha sonra bazı parça sayfalarına sahip olan bir parçam var. Uygulamayı ilk kez başlattığımda, sekmeler arasında sorunsuz geçiş yapabiliyorum ama sekme2'ye ikinci kez bastığımda yukarıda bahsedilen hatayı alıyorum. Ana faaliyet aşağıdaki gibidir:

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 olmadan parça sınıfı aşağıdaki gibidir:

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 ile parça sınıfı aşağıdaki gibidir:

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

Farklı yerlerde okuduklarımdan (ve yanlışsam lütfen beni düzeltin), bu, ikinci geçişteki parça yöneticisi artık mevcut olmayan etkinlikten parçaları yeniden kullanmaya çalışarak hatayı vermesi nedeniyle olur. Ama parça etkinliğini kullanmadığım için bunun neden burada olduğundan emin değilim. Logcat'e göre hata, mViewPager.setAdapter (mMyFragmentPagerAdapter) satırındaki Tab2 sınıfında, onViewCreated yöntemindedir. Herhangi bir yardım çok takdir edilmektedir ... Teşekkürler.

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)

Bu yüzden sorunu bulduğumu düşünüyorum. Tutulma hata ayıklayıcı üzerinden mMyFragmentPagerAdapter (sınıf Tab2) değişkenine baktığımda, Tab2'ye ilk kez tıklandığında MainActivity'yi işaret eden mActivity adlı bir alana sahip olan FragmentManager değişkenine sahip olduğunu gördüm. diğer sekme ve mActivity'ye tekrar bakıldığında boş değeri vardı, bu belki de Activity hatasını vermesinin neden yok edildiğini açıklıyor.
Yulric Sequeira

Yanıtlar:


284

Bu, iç içe geçmiş parçalar için yeni eklenen destekte bir hata gibi görünüyor. Temel olarak, çocuk FragmentManageraktiviteden ayrıldığında içsel bir durumla sonuçlanır. Bunu benim için düzelten kısa vadeli bir çözüm, aradığınız onDetach()her şeye aşağıdakileri eklemektir :FragmentgetChildFragmentManager()

@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
Fragment uygulamasına bakarsanız, ayrılmış duruma geçerken dahili durumunu sıfırlayacağını göreceksiniz. Ancak, mChildFragmentManager'ı sıfırlamaz (bu, destek kitaplığının geçerli sürümündeki bir hatadır). Bu, Parça yeniden eklendiğinde alt parça yöneticisini yeniden bağlamamasına neden olarak gördüğünüz özel duruma neden olur.
Marcus Forsell Stahre

14
Benimle dalga geçiyor olmalısın. Bunu gönderdiğini bulmana sevindim, ama iyi bir keder.
secureboot

8
Bu hata, Android Açık Kaynak sorun izleyicisinde izleniyor: code.google.com/p/android/issues/detail?id=42601
Kristopher Johnson

3
Bir tutam tuz, ancak bu, support-v4 sürümünü veya android.app sürümünü kullanırken başarısız oluyor. Yani hata yalnızca destek kitaplığında meydana
gelmiyor

6
Destek kitaplığı 24.0.0 sürümünde düzeltilmiş görünüyor. 'Android.support.v4.app.Fragment' öğesinin 'performDetach ()' yöntemi, 'mChildFragmentManager = null;' yapar.
Emerson Dallagnol

13

Tam olarak aynı sorunu yaşıyorum. Bulduğum tek çözüm, sekmeler her değiştirildiğinde parçaları yeni bir örnekle değiştirmektir.

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

Gerçek bir çözüm değil, ancak önceki parça örneğini yeniden kullanmanın bir yolunu bulamadım ...


1
Vay canına çok teşekkürler ... bu sorunu çözdü. Neden çalıştığını bir açıklama yapmak mümkün mü FragmentManager kullanarak hatayı düzeltmeye çalışırken kafamı kırıyordum.
Yulric Sequeira

1
Bellek ayak izinizi analiz ettiniz mi? Bu geçici çözüm onu ​​artırabileceğinden, en azından şüpheliyim
nmxprime

neden çalıştığını bilmiyorum. nasıl çalıştığını bilmiyorum ama çalışıyor lol

7

Metodumun super.onCreate()sonunda arama yaparken aynı sorunla karşılaştım . Nedeni: attachActivity()FragmentActivity'nin onCreate () öğesinde çağrılır. Geçersiz kılarken onCreate()ve örneğin sekmeler oluştururken, Sekme yöneticisi, FragmentManager'a ekli aktivite olmadan bir parçaya geçmeye çalışacaktır.

Basit çözüm: Çağrıyı super.onCreate()işlev gövdesinin başına taşıyın .

Genel olarak, bu sorunun ortaya çıkmasının birçok nedeni var gibi görünüyor. Bu sadece başka bir ...

Matthias


Çok teşekkür ederim, günümü kurtardın! Aynı problemi yaşadım ve bir hafta sonra hala çözemedim; (. Bu cevabı yazdığına çok sevindim !!!
JonasPTFL

4

FragmentTransactionSorunumun, aramadan ÖNCE onCreate oluşturmaya çalıştığım bir aktivitede olduğunu eklemek istedim super.onCreate(). super.onCreate()Fonksiyonun tepesine yeni geçtim ve iyi çalıştım.


2

Bu hatayı aldım çünkü LocalBroadcastManager kullanıyordum ve şunu yaptım:

unregisterReceiver(intentReloadFragmentReceiver);

onun yerine:

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

1
bu benim sorunumu çözmez. Ama Teşekkürler, BroadcastReceivers'ı kullanırken yaptığım hataları düzeltmeme yardımcı oldu
nmxprime

Aktivite bağlamınız boşsa ne olur? O zaman 'bu' geçerli olmaz.
IgorGanapolsky

Etkinlikler bağlamı ne zaman boş olabilir? Asla düşünmüyorum.
Malachiasz

2

Aynı sorunla karşılaştım ve lateron , FragmentActivity'nin super.onCreate( savedInstanceState );içindeki çağrıyı kaçırdığımı onCreate()öğrendi.


1

FragmentManagerParçanın tam olarak başlatılmasından önce çocuğa erişmeye çalışırken aynı hatayı aldım (yani Aktiviteye iliştirilmiş veya en azından onCreateView()çağrılmış). Aksi takdirde , yukarıda belirtilen istisnaya neden FragmentManagerolan bir nullAktivite ile başlatılır .


1

Alt parçayı içeren parçayı onPause'da NULL'a zorluyorum ve bu benim sorunumu çözüyor

fragment = null;

1

Bunun eski bir gönderi olduğunu biliyorum, ancak önerilen yanıtlar benim tarafımda işe yaramadı. Birisinin yararlı bulması ihtimaline karşı bunu burada bırakmak istiyorum.

Yaptığım şey:

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

Daha sonra:

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

0

Bu sorunu yaşadım ve çözümü burada bulamadım, bu yüzden başka birinin bu sorunu tekrar yaşaması durumunda çözümümü paylaşmak istiyorum.

Bu koda sahiptim:

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

ve "onDestroy ()" satırını silerek sorunu çözdü;

public void finishAction() {
  finish();
}

İlk kodu yazmamın nedeni: "finish ()" yi çalıştırdığınızda, etkinliğin "onDestroy ()" u çağırdığını biliyorum, ancak iş parçacıkları kullanıyorum ve bir sonraki etkinliğe başlamadan önce tüm iş parçacıklarının yok edilmesini sağlamak istedim ve "finish ()" her zaman anlık değil gibi görünüyor. Çok fazla "Bitmap" i işlemem / küçültmem ve büyük "bitmapler" göstermem gerekiyor ve uygulamamdaki bellek kullanımını iyileştirmek için çalışıyorum

Şimdi iş parçacıklarını farklı bir yöntem kullanarak öldüreceğim ve bu yöntemi "onDestroy ()" dan çalıştıracağım. ve tüm konuları öldürmem gerektiğini düşündüğümde.

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

0

Ben bu sorunu vardı ve ben çağırıyordu çünkü fark setContentView(int id)benim iki kez Activity'sonCreate


0

Bu beni Xamarin için çıldırttı.

Buna kendisi DrawerLayout'ta uygulanan bir Fragment İÇİNDE TabLayout için bir ViewPager uygulamasıyla karşılaştım:

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

Yani DrawerFragment'ınızda aşağıdaki kodu uygulamanız gerekir . Doğru FragmentManager-Yolunu seçmeye dikkat edin. Çünkü iki farklı FragmentManager Referansınız olabilir:

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

-> Kullandığınız birini seçin. ChildFragmentManager'ı kullanmak istiyorsanız , ViewPager'ınız için Android.App.FragmentManager sınıf bildirimini kullanmanız gerekir!

Android.Support.V4.App.FragmentManager

Aşağıdaki Yöntemi "Ana" Parçanıza uygulayın - bu örnekte: DrawerFragment

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

Bu, ViewPager'ı Android.App.FragmentManager ile başlatmanız gerektiği anlamına gelir.

Aşağıdaki Yöntemi "Ana" Parçanıza uygulayın - bu örnekte: DrawerFragment

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

Hata en son androidx sürümünde düzeltildi. Ve ünlü geçici çözüm şimdi çökmeye neden olacak. yani şimdi buna ihtiyacımız yok.

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.