记录一次关于Activity与Fragment生命周期引起的异常
2017-05-23 17:30
746 查看
在Activity和Frgment生命周期中对于数据保存应该是大部分都能保存的,像按Home返回到后台,再切换回来后应该不会出大问题的,但一次内存过底把保存的Activity给Destroy后引起了错误,具体是Activity里Fragment A里有一个Fragment B, Fragment B 按理是在A的onCreate里进行网络请求后异步创建,那么Activity销毁后走OnCreate应该不会有什么问题。
但是呢,Fragment B报空指针。这便引出这个文章。
https://developer.android.com/guide/components/fragments.html
https://developer.android.com//guide/components/activities.html
这里贴上重要的生命周期图
上面的图是初学者应该了解的,但Android开发一段时间后也应该复习一下。具体情景是DetailActivity里replace一个framelayout后添加的fragment A, 在fragment A里再使用相同方式添加 fragment B, 但使用的是fragmentManager 是调用 A的
正常情况下看打印的数据
这里按home键后
也很好对应上面的图片了。相同之处是在onPause后调用了
不过,即使您什么都不做,也不实现 onSaveInstanceState(),Activity 类的 onSaveInstanceState() 默认实现也会恢复部分 Activity 状态。具体地讲,默认实现会为布局中的每个 View 调用相应的 onSaveInstanceState() 方法,让每个视图都能提供有关自身的应保存信息。Android 框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复对 UI 所做的任何可见更改。例如,EditText 小部件保存用户输入的任何文本,CheckBox 小部件保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小部件提供一个唯一的 ID(通过 android:id 属性)。如果小部件没有 ID,则系统无法保存其状态。
尽管 onSaveInstanceState() 的默认实现会保存有关您的Activity UI 的有用信息,您可能仍需替换它以保存更多信息。例如,您可能需要保存在 Activity 生命周期内发生了变化的成员值(它们可能与 UI 中恢复的值有关联,但默认情况下系统不会恢复储存这些 UI 值的成员)。
由于 onSaveInstanceState() 的默认实现有助于保存 UI 的状态,因此如果您为了保存更多状态信息而替换该方法,应始终先调用 onSaveInstanceState() 的超类实现,然后再执行任何操作。 同样,如果您替换 onRestoreInstanceState() 方法,也应调用它的超类实现,以便默认实现能够恢复视图状态。
注:由于无法保证系统会调用 onSaveInstanceState(),因此您只应利用它来记录 Activity 的瞬态(UI 的状态)— 切勿使用它来存储持久性数据,而应使用 onPause() 在用户离开 Activity 后存储持久性数据(例如应保存到数据库的数据)。
再看下按回的打印
执行的生命周期不多,不会走onCreate,而且都没有销毁,所以看不是问题。这里如果打开开发者选项中的不保留活动, 那么问题就来了,Activity会Destory
返回打印结果
看到fragment B会先onCreate再destoryview,然后异步方法再new instance 一个新的, 因此产生多个实例,造成内存泄露。其实fragment A也同的情况。
但是呢,Fragment B报空指针。这便引出这个文章。
Activity & Fragment
介绍文章直接有官方网站地址如下:https://developer.android.com/guide/components/fragments.html
https://developer.android.com//guide/components/activities.html
这里贴上重要的生命周期图
上面的图是初学者应该了解的,但Android开发一段时间后也应该复习一下。具体情景是DetailActivity里replace一个framelayout后添加的fragment A, 在fragment A里再使用相同方式添加 fragment B, 但使用的是fragmentManager 是调用 A的
getChildFragmentManager()。
正常情况下看打印的数据
05-24 17:24:18.584 22965-22965/com.yorkyu.fragmentlifedemo D/DetailActivity: onCreate: 05-24 17:24:18.586 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onAttach: 05-24 17:24:18.586 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onCreate: 05-24 17:24:18.587 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onCreateView: 05-24 17:24:18.622 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onViewCreated: 05-24 17:24:18.622 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onActivityCreated: 05-24 17:24:18.622 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onViewStateRestored: 05-24 17:24:18.622 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onStart: 05-24 17:24:18.622 22965-22965/com.yorkyu.fragmentlifedemo D/DetailActivity: onStart: 05-24 17:24:18.623 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onResume: 05-24 17:24:23.593 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onAttach: 05-24 17:24:23.594 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onCreate: 05-24 17:24:23.595 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onCreateView: 05-24 17:24:23.612 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onViewCreated: 05-24 17:24:23.612 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onActivityCreated: 05-24 17:24:23.613 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onViewStateRestored: 05-24 17:24:23.613 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onStart: 05-24 17:24:23.613 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onResume:
这里按home键后
05-24 17:26:50.408 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onPause: 05-24 17:26:50.409 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onPause: 05-24 17:26:50.409 22965-22965/com.yorkyu.fragmentlifedemo D/DetailActivity: onPause: 05-24 17:26:50.726 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onSaveInstanceState: 05-24 17:26:50.730 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onSaveInstanceState: 05-24 17:26:50.730 22965-22965/com.yorkyu.fragmentlifedemo D/DetailActivity: onSaveInstanceState: 05-24 17:26:50.730 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onStop: 05-24 17:26:50.730 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onStop: 05-24 17:26:50.730 22965-22965/com.yorkyu.fragmentlifedemo D/DetailActivity: onStop:
也很好对应上面的图片了。相同之处是在onPause后调用了
onSaveInstanceState。官方也介绍了如下,
不过,即使您什么都不做,也不实现 onSaveInstanceState(),Activity 类的 onSaveInstanceState() 默认实现也会恢复部分 Activity 状态。具体地讲,默认实现会为布局中的每个 View 调用相应的 onSaveInstanceState() 方法,让每个视图都能提供有关自身的应保存信息。Android 框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复对 UI 所做的任何可见更改。例如,EditText 小部件保存用户输入的任何文本,CheckBox 小部件保存复选框的选中或未选中状态。您只需为想要保存其状态的每个小部件提供一个唯一的 ID(通过 android:id 属性)。如果小部件没有 ID,则系统无法保存其状态。
尽管 onSaveInstanceState() 的默认实现会保存有关您的Activity UI 的有用信息,您可能仍需替换它以保存更多信息。例如,您可能需要保存在 Activity 生命周期内发生了变化的成员值(它们可能与 UI 中恢复的值有关联,但默认情况下系统不会恢复储存这些 UI 值的成员)。
由于 onSaveInstanceState() 的默认实现有助于保存 UI 的状态,因此如果您为了保存更多状态信息而替换该方法,应始终先调用 onSaveInstanceState() 的超类实现,然后再执行任何操作。 同样,如果您替换 onRestoreInstanceState() 方法,也应调用它的超类实现,以便默认实现能够恢复视图状态。
注:由于无法保证系统会调用 onSaveInstanceState(),因此您只应利用它来记录 Activity 的瞬态(UI 的状态)— 切勿使用它来存储持久性数据,而应使用 onPause() 在用户离开 Activity 后存储持久性数据(例如应保存到数据库的数据)。
再看下按回的打印
05-24 17:31:42.592 22965-22965/com.yorkyu.fragmentlifedemo D/DetailActivity: onRestart: 05-24 17:31:42.593 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onStart: 05-24 17:31:42.593 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onStart: 05-24 17:31:42.593 22965-22965/com.yorkyu.fragmentlifedemo D/DetailActivity: onStart: 05-24 17:31:42.594 22965-22965/com.yorkyu.fragmentlifedemo D/AFragment: onResume: 05-24 17:31:42.595 22965-22965/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onResume:
执行的生命周期不多,不会走onCreate,而且都没有销毁,所以看不是问题。这里如果打开开发者选项中的不保留活动, 那么问题就来了,Activity会Destory
05-24 11:13:03.969 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onPause: 05-24 11:13:03.970 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onPause: 05-24 11:13:03.970 12289-12289/com.yorkyu.fragmentlifedemo D/DetailActivity: onPause: 05-24 11:13:04.911 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onSaveInstanceState: 05-24 11:13:04.912 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onSaveInstanceState: 05-24 11:13:04.928 12289-12289/com.yorkyu.fragmentlifedemo D/DetailActivity: onSaveInstanceState: 05-24 11:13:04.929 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onStop: 05-24 11:13:04.929 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onStop: 05-24 11:13:04.929 12289-12289/com.yorkyu.fragmentlifedemo D/DetailActivity: onStop: 05-24 11:13:04.950 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onDestroyView: 05-24 11:13:04.951 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onDestroyView: 05-24 11:13:04.952 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onDestroy: 05-24 11:13:04.952 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onDetach: 05-24 11:13:04.953 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onDestroy: 05-24 11:13:04.953 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onDetach: 05-24 11:13:04.953 12289-12289/com.yorkyu.fragmentlifedemo D/DetailActivity: onDestroy:
返回打印结果
05-24 11:13:31.331 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onAttach: 05-24 11:13:31.331 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onAttach: 05-24 11:13:31.332 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onCreate: 05-24 11:13:31.332 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onCreate: 05-24 11:13:31.358 12289-12289/com.yorkyu.fragmentlifedemo D/DetailActivity: onCreate: 05-24 11:13:31.360 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onCreateView: 05-24 11:13:31.392 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onViewCreated: 05-24 11:13:31.392 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onActivityCreated: 05-24 11:13:31.392 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onCreateView: 05-24 11:13:31.396 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onViewCreated: 05-24 11:13:31.396 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onActivityCreated: 05-24 11:13:31.396 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onViewStateRestored: 05-24 11:13:31.396 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onViewStateRestored: 05-24 11:13:31.396 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onAttach: 05-24 11:13:31.396 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onCreate: 05-24 11:13:31.397 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onDestroyView: 05-24 11:13:31.397 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onDestroyView: 05-24 11:13:31.397 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onCreateView: 05-24 11:13:31.400 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onViewCreated: 05-24 11:13:31.400 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onActivityCreated: 05-24 11:13:31.400 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onViewStateRestored: 05-24 11:13:31.400 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onStart: 05-24 11:13:31.400 12289-12289/com.yorkyu.fragmentlifedemo D/DetailActivity: onStart: 05-24 11:13:31.400 12289-12289/com.yorkyu.fragmentlifedemo D/DetailActivity: onRestoreInstanceState: 05-24 11:13:31.401 12289-12289/com.yorkyu.fragmentlifedemo D/AFragment: onResume: 05-24 11:13:31.405 12289-12289/com.yorkyu.fragmentlifedemo D/ActivityThreadInjector: clearCachedDrawables. 05-24 11:13:36.367 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onAttach: 05-24 11:13:36.367 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onCreate: 05-24 11:13:36.399 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onAttach: 05-24 11:13:36.399 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onCreate: 05-24 11:13:36.400 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onCreateView: 05-24 11:13:36.413 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onViewCreated: 05-24 11:13:36.413 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onActivityCreated: 05-24 11:13:36.413 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onViewStateRestored: 05-24 11:13:36.414 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onStart: 05-24 11:13:36.414 12289-12289/com.yorkyu.fragmentlifedemo D/BFragment - main - 1: onResume:
看到fragment B会先onCreate再destoryview,然后异步方法再new instance 一个新的, 因此产生多个实例,造成内存泄露。其实fragment A也同的情况。
解决办法
onSaveInstanceState里处理
必须在回调前通过fragmentManager移除当前页面的fragment,这样再走onCreate都会new Instance,这样也有一个问题就是每次跳转页面返回这个页面后一样会new Instance,性能不是太好。但解决了异步动态添加Fragment和Activity及Fragment自动恢复机制引起重复创建。我观察过这种情况大概在我这个应用里会造成每次1MB左右的内存泄露。@Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); int backStackEntryCount = mChildFragmentManager.getBackStackEntryCount(); for (int i = 0; i < backStackEntryCount; i++) { mChildFragmentManager.popBackStackImmediate(); } Log.d(TAG, "onSaveInstanceState: "); }
在OnCreate()或者onRestart()里判断
既然无法很好在onDestory去remove fragment,那么就配合activity 与fragment的自动保存机制,在onSaveInstanceState()里保留自动保留外的数据。大意代码如下:@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate: "); if (savedInstanceState != null) { // do something } else { // do anothering } }
参考
Fragment Transactions & Activity State Loss相关文章推荐
- 关于Activity和Fragment生命周期的小记录
- 关于android的activity和fragment的生命周期
- Android 复习 3 有关于fragment Activity 生命周期
- 关于Fragment(XXFragment) not attached to Activity 异常
- 关于Activity、Fragment、ActivityLifecycleCallbacks、FragmentLifecycleCallbacks的生命周期方法执行顺序
- 关于Activity的横竖屏切换引起的生命周期变化的问题
- 关于Activity和Fragment生命周期关系
- 开发时Activity生命周期异常记录
- 关于Fragment not attached to Activity 异常
- 关于Fragment.onCreate()中引用Activity.onCreate()创建的对象时的一个异常
- 关于fragment与activity生命周期相关讨论
- 关于Activity及启动模式,Fragment,Service的使用以及生命周期
- 关于Fragment与Activity生命周期前后关系详解
- 关于startActivity跳转引起的异常
- 关于Activity中的Viewpager中的Fragment的生命周期
- 一个FragmentActivity多个Fragment的生命周期事件记录
- 关于Activity的生命周期以及异常销毁
- 敏捷开发生态系统系列之五:关于敏捷生态系统的一次聊天记录(敏捷估算,同行压力,估算扑克)
- Android Fragment---与Activity生命周期的协调
- 敏捷开发生态系统系列之五:关于敏捷生态系统的一次聊天记录(敏捷估算,同行压力,估算扑克)