打开“不保存活动”后程序不崩溃的修改方案

Posted by BY on July 23, 2018

开发者选项中“不保存活动”按钮的含义

“不保留活动”开启后:

  • 当从Activity A -> Activity B时,A会销毁,当从B退回到A时,A回重新加载,不会回到退出时的状态。
  • 当从应用返回到桌面时,该应用不会保留在后台,而是从内存中直接清除,再次打开不会回到退出时的状态。

由于某些用户打开了这个按钮,会导致app的跳转逻辑和fragment加载出问题,而导致崩溃。在app设计时,处理这个问题刻不容缓。

解决方案

项目界面结构简介

在ListView的头部view中有一个静态加载的fragment,之所以不用代码动态加载fragment是因为在tab3的fragment中找不到replaceId。

在开发者选项中打开“不保存活动”后,多次重复按home再进入app,会复现如下错误:

java.lang.IllegalStateException:Fragment has not been attached yet.
	android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2308)
	android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:773)
	android.support.v4.app.FragmentActivity.markState(FragmentActivity.java:967)
	android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:527)
	android.support.v7.app.AppCompatActivity.onSaveInstanceState(AppCompatActivity.java:509)
	android.app.Activity.performSaveInstanceState(Activity.java:1507)
	android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1326)
	android.app.ActivityThread.callCallActivityOnSaveInstanceState(ActivityThread.java:4587)
	android.app.ActivityThread.performStopActivityInner(ActivityThread.java:3894)
	android.app.ActivityThread.handleStopActivity(ActivityThread.java:3961)
	android.app.ActivityThread.-wrap25(ActivityThread.java)
	android.app.ActivityThread$H.handleMessage(ActivityThread.java:1536)
	android.os.Handler.dispatchMessage(Handler.java:102)
	android.os.Looper.loop(Looper.java:154)
	android.app.ActivityThread.main(ActivityThread.java:6177)
	java.lang.reflect.Method.invoke(Native Method)
	com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:933)
	com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

原因是,我们静态加载的fragment处于MainActivity中的SupportFragmentManager,在页面退出时tab3的fragment退出栈,静态加载的fragment并未出栈,导致出错。修改方法也较为简单,在tab3的fragment中重载onDestroyView方法,如果SupportFragmentManager能找到静态加载的fragment,就将它detach。

@Override
public void onDestroyView() {
    super.onDestroyView();
    //解决多次onSaveInstanceState调用导致
    //ViolationCardsFragment 引发的IllegalStateException:Fragment has not been attached yet.
    Fragment fragment = getHoldingActivity()
            .getSupportFragmentManager()
            .findFragmentById(R.id.fl_auto_owner_fragment_violation);
    if(fragment != null)
        getHoldingActivity().getSupportFragmentManager().beginTransaction().detach(fragment).commitAllowingStateLoss();
}

京东的解决方案

当发现用户打开了“不保留活动”按钮,弹出提示框,建议用户关闭。

int alwaysFinish = Settings.Global.getInt(getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0);
if (alwaysFinish == 1) {
    Dialog dialog = null;
	dialog = new AlertDialog.Builder(this)
					.setMessage(
							"由于您已开启'不保留活动',导致i呼部分功能无法正常使用.我们建议您点击左下方'设置'按钮,在'开发者选项'中关闭'不保留活动'功能.")
					.setNegativeButton("取消", new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}
					}).setPositiveButton("设置", new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							Intent intent = new Intent(
									Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
							startActivity(intent);
						}
					}).create();
	dialog.show();
}

还有一个其他的方案仅供参考