Mendapatkan error "Java.lang.IllegalStateException Activity telah dihancurkan" saat menggunakan tab dengan ViewPager

110

Saya memiliki aplikasi yang terdiri dari penggunaan ActionBarSherlock dalam mode tab. Saya memiliki 5 tab dan konten setiap tab ditangani menggunakan fragmen. Untuk tab2, saya memiliki sebuah fragmen yang file xml-nya berisi elemen ViewPager yang pada gilirannya memiliki beberapa halaman fragmen. Ketika saya awalnya memulai aplikasi aplikasi, saya dapat beralih antar tab tidak ada masalah tetapi ketika saya menekan tab2 untuk kedua kalinya saya mendapatkan kesalahan yang disebutkan di atas. Kegiatan utamanya adalah sebagai berikut:

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

        }
    }
}

Kelas fragmen tanpa ViewPager adalah sebagai berikut:

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

Kelas fragmen dengan ViewPager adalah sebagai berikut:

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

Dari apa yang saya baca di tempat yang berbeda (dan tolong koreksi saya jika saya salah), ini terjadi karena pengelola fragmen pada lintasan kedua mencoba menggunakan kembali fragmen dari aktivitas yang sudah tidak ada lagi sehingga menimbulkan kesalahan. Tapi saya tidak yakin mengapa ini terjadi di sini karena saya tidak menggunakan aktivitas fragmen. Menurut logcat, error ada di kelas Tab2, metode onViewCreated pada baris yang bertuliskan mViewPager.setAdapter (mMyFragmentPagerAdapter). Setiap bantuan sangat dihargai ... Terima kasih.

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)
Yulric Sequeira
sumber
Jadi saya pikir saya mungkin telah menemukan masalahnya. Saat melihat variabel mMyFragmentPagerAdapter (class Tab2) melalui debugger eclipse, saya melihat bahwa variabel itu memiliki variabel FragmentManager yang saat mengklik Tab2 untuk pertama kalinya memiliki bidang yang disebut mActivity yang mengarah ke MainActivity. Namun saat beralih dari tab2 ke beberapa tab lain dan melihat mActivity lagi itu memiliki nilai null, yang mungkin menjelaskan mengapa pemberiannya, Aktivitas telah dimusnahkan.
Yulric Sequeira

Jawaban:

284

Ini tampaknya merupakan bug dalam dukungan yang baru ditambahkan untuk fragmen bersarang. Pada dasarnya, anak FragmentManagerberakhir dengan keadaan internal yang rusak saat terlepas dari aktivitas. Solusi jangka pendek yang memperbaikinya bagi saya adalah menambahkan yang berikut ini ke onDetach()setiap Fragmentyang Anda hubungi 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);
    }
}
Marcus Forsell Stahre
sumber
21
Jika Anda melihat implementasi Fragment, Anda akan melihat bahwa saat berpindah ke status terlepas, ini akan menyetel ulang status internalnya. Namun, ini tidak menyetel ulang mChildFragmentManager (ini adalah bug dalam versi pustaka dukungan saat ini). Ini menyebabkannya tidak memasang kembali pengelola fragmen turunan saat Fragmen dilampirkan kembali, menyebabkan pengecualian yang Anda lihat.
Marcus Forsell Stahre
14
Kamu pasti sudah bercanda. Senang Anda menemukan memposting ini, tapi kesedihan yang baik.
secureboot
8
Bug ini dilacak di pelacak masalah Sumber Terbuka Android: code.google.com/p/android/issues/detail?id=42601
Kristopher Johnson
3
Sedikit garam, tetapi ini gagal menggunakan versi support-v4 atau versi android.app. Jadi bug tidak hanya terjadi di pustaka dukungan
gbero
6
Tampaknya telah diperbaiki dalam pustaka dukungan versi 24.0.0. Metode 'performDetach ()', dari 'android.support.v4.app.Fragment', lakukan 'mChildFragmentManager = null;'.
Emerson Dallagnol
13

Saya mengalami masalah yang persis sama. Satu-satunya solusi yang saya temukan, adalah mengganti fragmen dengan instance baru, setiap kali tab diubah.

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

Bukan solusi nyata, tetapi saya belum menemukan cara untuk menggunakan kembali contoh fragmen sebelumnya ...

jekatt
sumber
1
Wow terima kasih banyak ... yang telah memperbaiki masalah. Apakah mungkin untuk memberikan penjelasan mengapa ini berhasil? Saya putus asa mencoba memperbaiki kesalahan menggunakan FragmentManager.
Yulric Sequeira
1
Sudahkah Anda menganalisis jejak memori Anda? Karena solusi ini dapat meningkatkannya, setidaknya saya curiga
nmxprime
tidak tahu mengapa ini bekerja .. tidak tahu cara kerjanya tetapi berhasil lol
7

Saya mengalami masalah yang sama saat menelepon super.onCreate()di akhir metode saya. Alasan: attachActivity()dipanggil di onCreate () dari FragmentActivity. Saat mengganti onCreate()dan, misalnya, membuat tab, pengelola Tab akan mencoba beralih ke fragmen sambil tidak memiliki aktivitas yang dilampirkan ke FragmentManager.

Solusi sederhana: Pindahkan panggilan ke super.onCreate()kepala badan fungsi.

Secara umum, tampaknya ada banyak alasan mengapa masalah ini dapat terjadi. Ini hanyalah satu lagi ...

Matthias

pengguna1050133
sumber
Terima kasih banyak, Anda menyelamatkan hari saya! Saya memiliki masalah yang sama dan masih tidak bisa menyelesaikannya setelah satu minggu; (Jadi saya sangat senang Anda menulis jawaban ini !!!
JonasPTFL
4

Ingin menambahkan bahwa masalah saya adalah dalam aktivitas di mana saya mencoba masuk ke FragmentTransactiononCreate SEBELUM saya menelepon super.onCreate(). Saya baru saja pindah super.onCreate()ke atas fungsi dan bekerja dengan baik.

sgarman
sumber
2

Saya mengalami kesalahan ini karena saya menggunakan LocalBroadcastManager dan saya melakukannya:

unregisterReceiver(intentReloadFragmentReceiver);

dari pada:

LocalBroadcastManager.getInstance(this).unregisterReceiver(intentReloadFragmentReceiver);
Malachiasz
sumber
1
ini tidak menyelesaikan masalah saya. Tapi Terima kasih telah membantu saya memperbaiki kesalahan saya dalam menggunakan BroadcastReceivers
nmxprime
Bagaimana jika konteks Aktivitas Anda null. Maka 'ini' tidak akan valid.
IgorGanapolsky
kapan konteks Aktivitas bisa nihil? Saya kira tidak pernah.
Malachiasz
2

Saya mengalami masalah yang sama dan kemudian menemukan bahwa, saya telah melewatkan panggilan ke super.onCreate( savedInstanceState );dalam onCreate()FragmentActivity.

Swapnil Chaudhari
sumber
1

Saya mendapat kesalahan yang sama ketika mencoba mengakses anak FragmentManagersebelum fragmen diinisialisasi sepenuhnya (yaitu dilampirkan ke Aktivitas atau setidaknya onCreateView()dipanggil). Jika tidak, FragmentManagerakan diinisialisasi dengan nullAktivitas yang menyebabkan pengecualian yang disebutkan di atas.

ubuntudroid
sumber
1

Saya memaksa fragmen yang berisi fragmen anak menjadi NULL di onPause dan itu memperbaiki masalah saya

fragment = null;
MobileMon
sumber
1

Saya tahu ini adalah posting lama, tetapi jawaban yang disarankan tidak berhasil di pihak saya. Saya ingin meninggalkan ini di sini kalau-kalau ada yang menganggapnya berguna.

Apa yang saya lakukan adalah:

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

Kemudian di:

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

Saya mengalami masalah ini dan saya tidak dapat menemukan solusinya di sini, jadi saya ingin membagikan solusi saya jika ada orang lain yang mengalami masalah ini lagi.

Saya punya kode ini:

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

dan memecahkan masalah dengan menghapus baris "onDestroy ();"

public void finishAction() {
  finish();
}

Alasan saya menulis kode awal: Saya tahu bahwa ketika Anda mengeksekusi "finish ()" aktivitas memanggil "onDestroy ()", tetapi saya menggunakan utas dan saya ingin memastikan bahwa semua utas dihancurkan sebelum memulai aktivitas berikutnya , dan sepertinya "finish ()" tidak selalu langsung. Saya perlu memproses / mengurangi banyak "Bitmap" dan menampilkan "bitmap" yang besar dan saya sedang berupaya meningkatkan penggunaan memori di aplikasi saya

Sekarang saya akan mematikan utas menggunakan metode yang berbeda dan saya akan menjalankan metode ini dari "onDestroy ();" dan ketika saya pikir saya harus mematikan semua utas.

public void finishAction() {
  onDestroyThreads();
  finish();
}
pengguna713059
sumber
0

Saya memiliki masalah ini dan menyadari itu karena aku menelepon setContentView(int id)dua kali dalam saya Activity'sonCreate

LukasE078
sumber
0

Yang ini membuatku tergila-gila pada Xamarin.

Saya mengalami ini dengan implementasi ViewPager untuk TabLayout DALAM sebuah Fragmen, yang diimplementasikan dengan sendirinya di DrawerLayout:

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

Jadi, Anda harus menerapkan kode berikut di DrawerFragment Anda . Berhati-hatilah untuk memilih FragmentManager-Path yang benar. Karena Anda mungkin memiliki dua Referensi FragmentManager yang berbeda:

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

-> Pilih salah satu yang Anda gunakan. Jika Anda ingin menggunakan ChildFragmentManager, Anda harus menggunakan deklarasi kelas Android.App.FragmentManager untuk ViewPager Anda!

Android.Support.V4.App.FragmentManager

Terapkan Metode berikut dalam Fragmen "Utama" Anda - dalam contoh ini: 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 {}

Itu berarti Anda harus membuka ViewPager dengan Android.App.FragmentManager.

Terapkan Metode berikut dalam Fragmen "Utama" Anda - dalam contoh ini: 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+"");
    }
}
Lepidopteron
sumber
0

Bug telah diperbaiki di versi androidx terbaru. Dan solusi terkenal akan menyebabkan crash sekarang. jadi kita tidak membutuhkannya sekarang.

vipcxj
sumber