Получение ошибки "Активность Java.lang.IllegalStateException была уничтожена" при использовании вкладок с ViewPager
У меня есть приложение, которое состоит из использования 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, 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)
Ответы
Ответ 1
Это, кажется, ошибка в недавно добавленной поддержке вложенных фрагментов. В принципе, ребенок 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);
}
}
Ответ 2
У меня точно такая же проблема.
Единственным обходным решением, которое я нашел, является замена фрагментов новым экземпляром при каждом изменении вкладок.
ft.replace(R.id.fragment_container, Fragment.instantiate(PlayerMainActivity.this, fragment.getClass().getName()));
Не настоящее решение, но я не нашел способ повторного использования предыдущего экземпляра фрагмента...
Ответ 3
Я столкнулся с той же проблемой при вызове super.onCreate()
в конце моего метода. Причина: attachActivity()
вызывается в onCreate() функции FragmentActivity. При переопределении onCreate()
и, например, создании вкладок, менеджер табуляции будет пытаться переключиться на фрагмент, не имея активности, прикрепленной к FragmentManager.
Простое решение: переместите вызов на super.onCreate()
в голову тела функции.
В целом, похоже, есть множество причин, по которым может возникнуть эта проблема. Это еще один...
Маттиас
Ответ 4
Хотелось добавить, что моя проблема была в том, что я пытался сделать FragmentTransaction
в onCreate ПЕРЕД тем, как я назвал super.onCreate()
. Я просто переместил super.onCreate()
в начало функции и работал нормально.
Ответ 5
У меня была эта ошибка, потому что я использовал LocalBroadcastManager, и я сделал:
unregisterReceiver(intentReloadFragmentReceiver);
вместо:
LocalBroadcastManager.getInstance(this).unregisterReceiver(intentReloadFragmentReceiver);
Ответ 6
Я столкнулся с той же проблемой, и позже выяснилось, что я пропустил вызов super.onCreate( savedInstanceState );
в onCreate()
из FragmentActivity.
Ответ 7
Я получил ту же самую ошибку при попытке получить доступ к дочернему элементу FragmentManager
до того, как фрагмент был полностью инициализирован (т.е. подключен к операции или по меньшей мере onCreateView()
). Иначе FragmentManager
инициализируется с помощью операции null
, вызывающей вышеупомянутое исключение.
Ответ 8
Я заставляю фрагмент, содержащий дочерний фрагмент, NULL в onPause, и он исправляет мою проблему
fragment = null;
Ответ 9
Я знаю, что это старый пост, но предлагаемые ответы не сработали с моей стороны. Я хочу оставить это здесь на всякий случай, если кто-то найдет это полезным.
Что я сделал:
@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();
}
}
Ответ 10
У меня была эта проблема, и я не мог найти решение здесь, поэтому хочу поделиться своим решением, если у кого-то еще проблема.
У меня был этот код:
public void finishAction() {
onDestroy();
finish();
}
и решил проблему, удалив строку "onDestroy();"
public void finishAction() {
finish();
}
Причина, по которой я написал исходный код:
Я знаю, что когда вы выполняете "finish()", действие вызывает "onDestroy()", но я использую потоки, и я хочу, чтобы все потоки были уничтожены до начала следующего действия, и это выглядит как "закончить ( )" не всегда мгновенно.
Мне нужно обработать/уменьшить количество "растровых изображений" и отобразить большие "растровые изображения", а Im работает над улучшением использования памяти в моем приложении.
Теперь я буду убивать потоки, используя другой метод, и Ill выполнить этот метод из "onDestroy();" и когда я думаю, что мне нужно убить все потоки.
public void finishAction() {
onDestroyThreads();
finish();
}
Ответ 11
У меня была эта проблема, и я понял, что это было потому, что я дважды звонил setContentView(int id)
в мой Activity
onCreate
Ответ 12
Это заставило меня сходить с ума от Ксамарина.
Я столкнулся с этим с реализацией ViewPager для TabLayout WITH IN Fragment, который сам реализован в DrawerLayout:
- DrawerLayout
- DrawerFragment
- TabLayout
- TabViewPager
- TabViewPagerFragments
Итак, вы должны реализовать следующий код в DrawerFragment.
Имейте в виду выбрать правильный путь FragmentManager. Поскольку у вас могут быть две разные ссылки на FragmentManager:
- Android.Support.V4.App.FragmentManager
- 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+"");
}
}