Отримання помилки "Java.lang.IllegalStateException Activity було знищено" під час використання вкладок з ViewPager


110

У мене є програма, яка складається з використання ActionBarSherlock в режимі вкладки. У мене є 5 вкладок, і вміст кожної вкладки обробляється за допомогою фрагментів. Для tab2, однак, у мене є фрагмент, у файлі xml якого міститься елемент ViewPager, який, у свою чергу, містить деякі сторінки фрагментів. Коли я спочатку запускаю програму, я можу переходити між вкладками без проблем, але коли я вдруге натискаю на tab2, я отримую згадану вище помилку. Основний вид діяльності:

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, методом onViewCreate у рядку, що говорить 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) через налагоджувач eclipse, я побачив, що вона мала змінну FragmentManager, яка при першому натисканні на Tab2 мала поле під назвою mActivity, яке вказувало на MainActivity.But при переході з tab2 на деякий інша вкладка і знову дивлячись на mActivity, вона мала значення null, що, можливо, пояснює, чому її знищення Activity Activity було знищено.
Yulric Sequeira

Відповіді:


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 (це помилка в поточній версії бібліотеки підтримки). Це призводить до того, що він не приєднає дочірнього менеджера фрагментів, коли фрагмент повторно закріплений, що спричинить виняток, який ви бачили.
Marcus Forsell Stahre

14
Ти мусиш жартувати мене. Радий, що ви знайшли повідомлення про це, але добре горе.
secureboot

8
Ця помилка відслідковується у відстежувачі проблем Android Open Source: code.google.com/p/android/isissue/detail?id=42601
Крістофер Джонсон

3
Щіпка солі, але це не вдається використовувати версію support-v4 або версію android.app. Тож помилка виникає не лише у бібліотеці підтримки
gbero

6
Це здається зафіксованим у бібліотеці підтримки версії 24.0.0. Метод 'performDetach ()', 'android.support.v4.app.Fragment', виконайте 'mChildFragmentManager = null;'.
Емерсон Даллагнол

13

У мене точно така ж проблема. Єдине вирішення, яке я знайшов, - це замінити фрагменти на новий екземпляр, щоразу змінюючи вкладки.

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

Це не справжнє рішення, але я не знайшов способу повторного використання попереднього фрагмента фрагмента ...


1
Дякую велике ... що вирішило проблему. Чи можна дати пояснення, чому це працює? Я ламав голову, намагаючись виправити помилку за допомогою FragmentManager.
Yulric Sequeira

1
Ви проаналізували свій слід пам’яті? Оскільки цей спосіб вирішення може його збільшити, принаймні, я підозрюю
nmxprime

не знаю, чому це працює .. не знаю, як це працює, але це працює lol

7

З тією ж проблемою я стикався, коли дзвонив super.onCreate()наприкінці свого методу. Причина: attachActivity()викликається в onCreate () фрагментаActivity. При переопределенні onCreate()та, наприклад, створенні вкладок, менеджер вкладок намагатиметься переключитися на фрагмент, не маючи активності, прикріпленої до FragmentManager.

Просте рішення: Перенесіть заклик до super.onCreate()голови функції функції.

Взагалі, здається, є безліч причин, через які ця проблема може виникнути. Це просто ще один ...

Маттіас


Дуже дякую, ти врятував мені день! У мене була така ж проблема, і я все ще не міг її вирішити через тиждень; (. Я дуже радий, що ти написав цю відповідь !!!
JonasPTFL

4

Хотів додати, що моя проблема полягала в тій діяльності, де я спробував зробити « FragmentTransactiononCreate», перш ніж я подзвонив super.onCreate(). Я просто перейшов super.onCreate()до вершини функції і працював чудово.


2

У мене виникла помилка, оскільки я використовував LocalBroadcastManager, і я зробив:

unregisterReceiver(intentReloadFragmentReceiver);

замість:

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

1
це не вирішує мою проблему. Але дякую, це допомогло мені виправити мої помилки щодо використання BroadcastReceivers
nmxprime

Що робити, якщо ваш контекст діяльності недійсний. Тоді "це" не було б дійсним.
ІгорГанапольський

коли контекст діяльності може бути нульовим? Я думаю, що ніколи.
Малахіаш

2

Я зіткнувся з тією ж проблемою, і латерон дізнався, що я пропустив дзвінок super.onCreate( savedInstanceState );у onCreate()FragmentActivity.


1

Я отримав ту саму помилку, коли намагався отримати доступ до дитини FragmentManagerдо того, як фрагмент був повністю ініціалізований (тобто приєднаний до Діяльності або, принаймні, onCreateView()викликаний). В іншому випадку FragmentManagerініціалізація над nullактивністю спричиняє вищезгаданий виняток.


1

Я змушую фрагмент, що містить дочірній фрагмент, NULL в onPause, і він вирішує мою проблему

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

Причина, по якій я написав початковий код: я знаю, що при виконанні "Finish ()" активність викликає "onDestroy ()", але я використовую теми, і я хотів переконатися, що всі потоки будуть знищені перед початком наступної діяльності , і схоже, що "закінчення ()" не завжди є негайним. Мені потрібно обробити / зменшити багато «растрових зображень» та відобразити великі «растрові карти», і я працюю над покращенням використання пам’яті у своєму додатку

Тепер я буду вбивати нитки, використовуючи інший метод, і виконую цей метод з "onDestroy ();" і коли я думаю, що мені потрібно вбити всі нитки.

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

0

Я мав це питання і зрозумів , що це було , тому що я дзвонив setContentView(int id)двічі в моєму ActivityхonCreate


0

Цей звів мене з розуму за Ксамарін.

Я зіткнувся з цим із реалізацією ViewPager для TabLayout В рамках фрагмента, який реалізований у DrawerLayout:

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

Тому вам доведеться реалізувати наступний код у своєму DrawerFragment . Будьте в курсі, щоб вибрати правильний FragmentManager-Path. Оскільки у вас можуть бути дві різні посилання FragmentManager:

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

-> Виберіть той, який ви використовуєте. Якщо ви хочете використовувати ChildFragmentManager, вам довелося використовувати декларацію класу Android.App.FragmentManager для свого ViewPager!

Android.Support.V4.App.FragmentManager

Реалізуйте наступний метод у своєму " Основному " фрагменті - у цьому прикладі: 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 {}

Це означає, що вам довелося запускати ViewPager за допомогою Android.App.FragmentManager.

Реалізуйте наступний метод у своєму " Основному " фрагменті - у цьому прикладі: 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

Помилка була виправлена ​​в останній версії androidx. І відомий спосіб вирішення справи спричинить крах вже зараз. тому нам це зараз не потрібно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.