记录一次关于Activity与Fragment生命周期引起的异常

在Activity和Frgment生命周期中对于数据保存应该是大部分都能保存的,像按Home返回到后台,再切换回来后应该不会出大问题的,但一次内存过底把保存的Activity给Destroy后引起了错误,具体是Activity里Fragment
A里有一个Fragment B, Fragment B
按理是在A的onCreate里进行网络请求后异步创建,那么Activity销毁后走OnCreate应该不会有什么问题。

但是呢,Fragment B报空指针。这便引出这个文章。

Activity & Fragment

介绍文章直接有官方网站地址如下:

https://developer.android.com/guide/components/fragments.html 
https://developer.android.com//guide/components/activities.html 
这里贴上重要的生命周期图

activity_lifecycle

instance_restore

fragment_lifecycle

activity_fragment_lifecycle

上面的图是初学者应该了解的,但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: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

这里按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:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

也很好对应上面的图片了。相同之处是在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: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

执行的生命周期不多,不会走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: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

返回打印结果

  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: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

看到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: ");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

saveinstance

在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
        } 

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

参考

Fragment Transactions &
Activity State Loss

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇