在使用 ViewPager 选项卡时获取错误“ Java.lang.IllegalStateException Activity has been delete”

我有一个在 tab 模式下使用 ActionBarSherlock 的应用程序。我有5个 tab,每个 tab 的内容都是使用片段处理的。但是对于 tab2,我有一个片段,其 xml 文件包含一个 ViewPager 元素,而 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类中,在 mViewPager.setAdapter (mMyFragmentPagerAdapter)行上的 onViewCreated 方法。非常感谢你的帮助... 谢谢。

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)
114013 次浏览

I'm having exactly the same problem. The only workaround I've found, is to replace the fragments by a new instance, each time the tabs are changed.

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

Not a real solution, but i haven't found a way to reuse the previous fragment instance...

This seems to be a bug in the newly added support for nested fragments. Basically, the child FragmentManager ends up with a broken internal state when it is detached from the activity. A short-term workaround that fixed it for me is to add the following to onDetach() of every Fragment which you call getChildFragmentManager() on:

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

I had this error because I was using LocalBroadcastManager and I did:

unregisterReceiver(intentReloadFragmentReceiver);

instead of:

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

I had this problem and I couldn't find the solution here, so I want to share my solution in case someone else has this problem again.

I had this code:

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

and solved the problem by deleting the line "onDestroy();"

public void finishAction() {
finish();
}

The reason I wrote the initial code: I know that when you execute "finish()" the activity calls "onDestroy()", but I'm using threads and I wanted to ensure that all the threads are destroyed before starting the next activity, and it looks like "finish()" is not always immediate. I need to process/reduce a lot of “Bitmap” and display big “bitmaps” and I’m working on improving the use of the memory in my app

Now I will kill the threads using a different method and I’ll execute this method from "onDestroy();" and when I think I need to kill all the threads.

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

I got the very same error when trying to access the child FragmentManager before the fragment was fully initialized (i.e. attached to the Activity or at least onCreateView() called). Else the FragmentManager gets initialized with a null Activity causing the aforementioned exception.

Wanted to add that my problem was in an activity where I tried to make a FragmentTransaction in onCreate BEFORE I called super.onCreate(). I just moved super.onCreate() to top of function and was worked fine.

I encountered the same issue when calling super.onCreate() at the end of my method. The reason: attachActivity() is called in onCreate() of FragmentActivity. When overriding onCreate() and, for example, creating tabs, the Tab manager will try to switch to a fragment while not having the activity attached to the FragmentManager.

Simple solution: Move the call to super.onCreate() to the head of the function body.

In general, it seems there are loads of reasons this issue may occur. This is just another one ...

Matthias

I encountered the same issue and lateron found out that, I have missed call to super.onCreate( savedInstanceState ); in onCreate() of FragmentActivity.

I had this issue and realized it was because I was calling setContentView(int id) twice in my Activity's onCreate

I force the fragment containing the child fragment to NULL in onPause and it fixes my problem

fragment = null;

I know this is an old post, but the suggested answers didn't work on my end. I want to leave this here just in case someone will find it useful.

What i did is:

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

Then in:

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

This one drove me crazy for Xamarin.

I ran into this with a ViewPager implementation for TabLayout WITHIN a Fragment, that is itself implemented in the DrawerLayout:

 - DrawerLayout
- DrawerFragment
- TabLayout
- TabViewPager
- TabViewPagerFragments

So you have to implement the following code in your DrawerFragment. Be aware to choose the correct FragmentManager-Path. Because you might have two different FragmentManager References:

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

--> Choose the one you use. If you want to make use of the ChildFragmentManager, you had to use the class declaration Android.App.FragmentManager for your ViewPager!

Android.Support.V4.App.FragmentManager

Implement the following Method in your "Main" Fragment - in this example: 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 {}

That means you had to init the ViewPager with Android.App.FragmentManager.

Implement the following Method in your "Main" Fragment - in this example: 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+"");
}
}

The bug has been fixed in the latest androidx version. And the famous workaround will cause crash now. so we need not it now.

i found that i had a timer running in the background. when the activity is killed, yet the timer still running. in the timer finish callback i access fragment object to do some work, and here is the bug!!!! the fragment exists but the activity isn't.

if you have service of timer or any background threads, make sure to not access fragments objects.