我在下面的 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);
}
}
Fatal Exception: java.lang.IllegalStateException: Can not perform this
action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2044)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2067)
at android.support.v4.app.FragmentManagerImpl.popBackStack(FragmentManager.java:799)
at com.exposure.activities.BaseActivity.updateView(BaseActivity.java:239)
at com.exposure.activities.events.EventActivity.setupEvent(EventActivity.java:204)
at com.exposure.activities.events.EventActivity.getData(EventActivity.java:117)
at com.exposure.utilities.ActivityContainer.getData(ActivityContainer.java:83)
at com.exposure.utilities.DataTask.onPostExecute(DataTask.java:37)
at android.os.AsyncTask.finish(AsyncTask.java:695)
at android.os.AsyncTask.-wrap1(Unknown Source)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
最佳答案
如 Fragment Transactions & Activity State Loss 中所述在要点 “避免在异步回调方法中执行事务” 下:
Avoid performing transactions inside asynchronous callback methods. This includes commonly used methods such as
AsyncTask#onPostExecute()
andLoaderManager.LoaderCallbacks#onLoadFinished()
. The problem with performing transactions in these methods is that they have no knowledge of the current state of the Activity lifecycle when they are called.
这似乎是您遇到的问题,因为 updateView()
是从异步任务中调用的,但让我们测试一下这个假设。
以下演示应用程序创建一个 fragment ,模拟后台处理和一个模仿您的异步回调的回调。代码中有一个标志,mFixIt
当设置为 true 时会导致应用程序正常运行(不会崩溃),当设置为 false 时会使应用程序失败。
使用 mFixIt == false。触发器是导致应用程序进入停止状态的主页按钮:
这是堆栈跟踪:
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。这次的不同之处在于,应用程序在 Activity 处于停止状态时识别异步回调,记录这已经发生并在应用程序重新启动时完成处理。视觉只是按下主页按钮并从“最近”恢复。该应用程序只是在开始时放置 fragment ,当重新启动时更改顶部 TextView
文本并从后台弹出 fragment 。
可以看出,处理按预期完成。
这是一个简单的例子。如果您的处理涉及更多,或者您只是想要一种更正式的方式来处理这种情况,我建议您查看 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>
关于java - popBackStack 导致 java.lang.IllegalStateException : Can not perform this action after onSaveInstanceState,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53566847/