首页 文章

popBackStack导致java.lang.IllegalStateException:onSaveInstanceState后无法执行此操作

提问于
浏览
-2

我在manager.popBackStack的行下面收到此错误 . 有没有解决的办法?它恰好发生了 .

public void updateView(Fragment fragment) {

        IFragment currentFragment = (IFragment)fragment;

        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = manager.beginTransaction();
        fragmentTransaction.replace(R.id.content_frame, fragment);

        if(currentFragment != null)
        {
            if(currentFragment.isRoot())
            {
                manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
            }
            else
            {
                fragmentTransaction.addToBackStack("test");
            }
        }

        fragmentTransaction.commitAllowingStateLoss();

        if(drawerManager.DrawerLayout != null) {
            drawerManager.DrawerLayout.closeDrawer(drawerManager.DrawerList);
        }
    }

致命异常:java.lang.IllegalStateException:在android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager)的android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2044)的onSaveInstanceState之后无法执行此操作.java:2067)位于com.exposure.activities.events的com.exposure.activities.BaseActivity.updateView(BaseActivity.java:239)的android.support.v4.app.FragmentManagerImpl.popBackStack(FragmentManager.java:799) . 位于com.exposure的com.exposure.utilities.ActivityContainer.getData(ActivityContainer.java:83)的com.exposure.activities.events.EventActivity.getData(EventActivity.java:117)中的EventActivity.setupEvent(EventActivity.java:204) .utilities.DataTask.onPostExecute(DataTask.java:37)在android.os.AsyncTask.finish(AsyncTask.java:695)的android.os.AsyncTask.-wrap1(未知来源)android.os.AsyncTask $ InternalHandler . android.os.Looper.lo上android.os.Handler.dispatchMessage(Handler.java:105)的handleMessage(AsyncTask.java:712)位于android.app.ActivityThread.main(ActivityThread.java:6938)的op(Looper.java:164)位于com.android.internal.os.Zygote的java.lang.reflect.Method.invoke(Method.java)$ MethodAndArgsCaller .run(Zygote.java:327)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

3 回答

  • 1

    Fragment Transactions & Activity State Loss中的子弹点"Avoid performing transactions inside asynchronous callback methods"所述:

    避免在异步回调方法中执行事务 . 这包括常用的方法,如AsyncTask#onPostExecute()和LoaderManager.LoaderCallbacks#onLoadFinished() . 在这些方法中执行事务的问题是,在调用它们时,它们不知道Activity生命周期的当前状态 .

    这似乎是您从异步任务调用 updateView() 以来所遇到的问题,但让我们测试一下这个假设 .

    以下演示应用程序创建一个片段,模拟后台处理和模仿异步回调的回调 . 代码中有一个标志,当设置为true时, mFixIt 会导致应用程序正常运行(不会爆炸),而当为false时,应用程序会失败 .

    使用mFixIt == false . 触发器是主页按钮,导致应用程序进入停止状态:

    enter image description here

    这是堆栈跟踪:

    14967-15003 E/AndroidRuntime: FATAL EXCEPTION: Thread-2
        Process: com.example.illegalstatepopbackstack, PID: 14967
        java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
            at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2080)
            at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2106)
            at android.support.v4.app.FragmentManagerImpl.popBackStack(FragmentManager.java:832)
            at com.example.illegalstatepopbackstack.MainActivity.updateView(MainActivity.java:70)
            at com.example.illegalstatepopbackstack.ui.main.MainFragment$1.run(MainFragment.java:63)
            at java.lang.Thread.run(Thread.java:764)
    

    现在 mFixIt == true . 这次的不同之处在于,当活动处于停止状态时,应用会识别异步回调,记录已发生这种情况,并在重新启动应用时完成处理 . 视觉效果只是按下主页按钮并从"recents"恢复 . 该应用程序只是在开始时放置片段,并在重新启动时更改顶部 TextView 文本并从backstack弹出片段 .

    enter image description here

    可以看出,处理按预期完成 .

    这是一个微不足道的例子 . 如果您的处理涉及更多,或者您只是想要一种更正式的方式来处理这种情况,我建议您查看this solution .

    以下是演示应用的代码:

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
        // Set to true to fix the problem; false will cause the IllegalStateException
        private boolean mFixIt = false;
    
        private MainFragment mFragment;
        private TextView mTextView;
        private boolean mIsPaused;
        private boolean mUpdateViewNeeded;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_activity);
            mTextView = findViewById(R.id.textView);
    
            FragmentManager fm = getSupportFragmentManager();
            if (savedInstanceState == null) {
                // Create out fragment
                mFragment = MainFragment.newInstance();
                fm.beginTransaction()
                    .replace(R.id.container, mFragment)
                    .addToBackStack(FRAGMENT_TAG)
                    .commit();
            } else {
                // Find the restored fragment.
                mFragment = (MainFragment) fm.findFragmentByTag(FRAGMENT_TAG);
            }
        }
    
        @Override
        protected void onStop() {
            super.onStop();
    
            // Simulate a background task that does something useful. This one just waits a few
            // second then does a callback to updateView(). The activity will be fully paused by then.
            mFragment.doSomethingInBackground();
            mIsPaused = true;
            Log.d("MainActivity","<<<< stopped");
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            mIsPaused = false;
            if (mUpdateViewNeeded) {
                // Execute delayed processing now that the activity is resumed.
                updateView(getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG));
            }
        }
    
        public void updateView(Fragment fragment) {
            if (mIsPaused && mFixIt) {
                // Delay processing
                mUpdateViewNeeded = true;
            } else {
                // Do out update work. If we are paused, this will get an IllegalStateException. If
                // we are resumed, this will work as intended.
                mTextView.setText("Replaced...");
                getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                mUpdateViewNeeded = false;
            }
        }
    
        public static final String FRAGMENT_TAG = "MyFragment";
    }
    

    MainFragment.java

    public class MainFragment extends Fragment {
    
        MainActivity mMainActivity;
    
        public static MainFragment newInstance() {
            return new MainFragment();
        }
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                                 @Nullable Bundle savedInstanceState) {
            return inflater.inflate(R.layout.main_fragment, container, false);
        }
    
        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
        }
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            mMainActivity = (MainActivity) context;
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            mMainActivity = null;
        }
    
        @Override
        public void onStart() {
            super.onStart();
    
        }
    
        public void doSomethingInBackground() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (mMainActivity != null) {
                        mMainActivity.updateView(MainFragment.this);
                    }
                }
            }).start();
        }
    }
    

    main_activity.xml

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_blue_light"
        android:gravity="center"
        android:text="To be replaced..."
        android:textSize="36sp"
        android:textStyle="bold" />
    
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" />
    

    main_fragment.xml

    <android.support.constraint.ConstraintLayout 
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_green_light"
        tools:context=".ui.main.MainFragment">
    
        <TextView
            android:id="@+id/message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="MainFragment"
            android:textSize="36sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </android.support.constraint.ConstraintLayout>
    
  • 4

    只需调用 popBackStackImmediate() ,因为常规 popBackStack() 是异步的...

  • 1

    问题主要是:

    IllegalStateException:无法在onSaveInstanceState之后执行此操作 .

    因此,请在 .updateView() 中查看 !isFinishing() && !isDestroyed()

    因为这会在 onSaveInstanceState() 上返回 true ...

    类似的情况可以减轻情况,防止崩溃 .

相关问题