Open yunshuipiao opened 5 years ago
假设有10个Fragment,每个fragment都打印其位置信息,从位置0开始:
但进入页面,停留在 0 位置处,打印日志如下:
D/Logger: setUserVisible0, false
D/Logger: setUserVisible1, false
D/Logger: setUserVisible0, true
D/Logger: onAttach0
D/Logger: onCreate0
D/Logger: onAttach1
D/Logger: onCreate1
D/Logger: onCreateView0
D/Logger: onActivityCreated0
D/Logger: onCreateView1
D/Logger: onActivityCreated1
得到的信息如下:
setUserVisible 方法在所有方法前调用,之后设置可见的 fragment 为 true。
重要的生命周期为:onAttach -- onCreate -- onCreateView -- onActivityCreated。此时 Fragment 变为活跃状态。
会提前加载下一个Fragment。
此时往后滑动 1 个,打印日志如下:
D/Logger: setUserVisible2, false
D/Logger: setUserVisible0, false
D/Logger: setUserVisible1, true
D/Logger: onAttach2
D/Logger: onCreate2
D/Logger: onCreateView2
D/Logger: onActivityCreated2
此时 Fragment 2 创建,共有 3 个framgent实例存在。当前为 Fragment 1, 左右各一个。
继续往后滑动一个:
D/Logger: setUserVisible3, false
D/Logger: setUserVisible1, false
D/Logger: setUserVisible2, true
D/Logger: onAttach3
D/Logger: onCreate3
D/Logger: onDestoryView0
D/Logger: onDestroy0
D/Logger: onDetach0
D/Logger: onCreateView3
D/Logger: onActivityCreated3
当前为Fragment 2, 此时 Fragment 0 被销毁,Fragment 3 创建。
滑动tab,直接点击fragment 6, 打印日志如下:
D/Logger: setUserVisible6, false
D/Logger: setUserVisible5, false
D/Logger: setUserVisible7, false
D/Logger: setUserVisible2, false
D/Logger: setUserVisible6, true
D/Logger: onAttach6
D/Logger: onCreate6
D/Logger: onAttach5
D/Logger: onCreate5
D/Logger: onAttach7
D/Logger: onCreate7
D/Logger: onCreateView6
D/Logger: onActivityCreated6
D/Logger: onCreateView5
D/Logger: onActivityCreated5
D/Logger: onCreateView7
D/Logger: onActivityCreated7
D/Logger: onDestoryView3
D/Logger: onDestroy3
D/Logger: onDetach3
D/Logger: onDestoryView2
D/Logger: onDestroy2
D/Logger: onDetach2
D/Logger: onDestoryView1
D/Logger: onDestroy1
D/Logger: onDetach1
此时变化较大,可见性方面没有变化。
Fragment 5,6,7 被创建。1,2,3被销毁。共计Fragment 实例存在。
viewpager.offscreenPageLimit = 4
可以通过上述方法修改不可见屏幕外的 fragment 的数量。
在上述的基础上,此 Adapter 在滑动过程中,其余生命周期方法一致,只是不会调用
D/Logger: onDestroy0
D/Logger: onDetach0
fragment 不会销毁。所以重新创建时:
D/Logger: setUserVisible0, false
D/Logger: setUserVisible2, false
D/Logger: setUserVisible1, true
D/Logger: onCreateView0
D/Logger: onActivityCreated0
D/Logger: onDestoryView3
只会重新调用创建view的相关方法,从而保留 fragment 的实例在内存中。
因此可以根据不同的 Fragment 数量来决定使用哪种 adapter。
在嵌套多个ViewPager的情况下, 从外层开始进行初始化, 其 fragment 实例个数与上述分析保持一致。
D/Logger: onCreateView 0
D/Logger: onCreateView 1
D/Logger: onCreateView 0-0
D/Logger: onCreateView 0-1
D/Logger: onCreateView 1-0
D/Logger: onCreateView 1-1
Activity: Lifecycle and Launch Mode
[TOC]
关于 Activty 相关的东西一直以来都是看别人总结的二手资料,从未正真的看过源码,包括官方文档的相关东西都能在源码中找到,所以 多看源码,永远不会错。
继承关系
由于 Activity 的源码太多,一个类就有 8000 行代码,所以找感兴趣,当然,每个类前面的注释特别重要,属于必读内容。
这里先不管接口,继承了 ContextThemeWrapper 类,一直往上走,继承关系如下:
Activity 是什么
英文是这样描述的:
几乎所有的 Activity 都与用户交互,所以几乎都是全屏幕,也有少量的 浮动 window 。
其子类有两个需要实现的方法
生命周期
当一个新 Activity 启动时,位于当前 Activity Stack 的顶部并且正在运行,之前的 Activity 保存在栈顶下面。
屏幕上可能会有一个或者多个可见的 Activity Stack 。
一个 Activity 只可能会有四种状态:
上面有3个关键流程需要注意以下:
完整的生命周期:start — destroy, 需要在 destory 是释放资源,停止线程的操作等。
可见生命周期:start — stop ,可见但不可交互,此时可以向用户显示 Activity 所需的资源。
比如注册
BroadcastReceiver
来监视界面的改变, stop 是取消注册。随着可见和不可见,会被调用多次。前台周期:resume — pause。
在整个生命周期中,需要实现
onPause()
来提交对数据的更改,并准备暂停与用户的交互;onStop()
来处理屏幕不可见时的问题。两点高版本的改动:
onStop()
方法返回之前,应用程序都不会因为任何情况被杀死。所以在onPause()
之后肯定会安全调用onStop()
, 做数据保存的操作。onSaveInstanceState(android.os.Bundle)
将会在onStop()
之后执行。此外,还有两个生命周期:
onRestart()
:onStop()
之后,但 Activity 重新可见之后调用onNewIntent()
: 当启动模式为SingleTop
, 并且位于栈顶重新启动时,一定在onPause
之后调用。此时getIntent()
为 旧的 intent, 可以使用setIntent()
修改。onSaveInstanceState和onRestoreInstanceState基本作用
Android系统的回收机制会在未经用户主动操作的情况下销毁activity,而为了避免系统回收activity导致数据丢失,Android为我们提供了onSaveInstanceState(Bundle outState)和onRestoreInstanceState(Bundle savedInstanceState)用于保存和恢复数据。
当activity有可能被系统回收的情况下,而且是在onStop()之前。注意是有可能,如果是已经确定会被销毁,比如用户按下了返回键,或者调用了finish()方法销毁activity,则onSaveInstanceState不会被调用。 或者也可以说,此方法只有在activity被异常终止的情况下会被调用。
onSaveInstanceState(Bundle outState)会在以下情况被调用:
onPause -> onSaveInstanceState -> onStop。
onRestoreInstanceState(Bundle savedInstanceState)只有在activity确实是被系统回收,重新创建activity的情况下才会被调用。
第5种情况屏幕方向切换时,activity生命周期如下: onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume
onCreate()里也有Bundle参数,可以用来恢复数据,它和onRestoreInstanceState有什么区别?
因为onSaveInstanceState 不一定会被调用,所以onCreate()里的Bundle参数可能为空,如果使用onCreate()来恢复数据,一定要做非空判断。
而onRestoreInstanceState的Bundle参数一定不会是空值,因为它只有在上次activity被回收了才会调用。
而且onRestoreInstanceState是在onStart()之后被调用的。有时候我们需要onCreate()中做的一些初始化完成之后再恢复数据,用onRestoreInstanceState会比较方便。
启动模式
启动模式允许您定义一个 Activity 的新实例如何与当前任务关联。你可以用两种方式定义不同的启动模式:
Using the manifest file
anduse intent flags
.standord
: 默认模式singleTop
: 栈顶复用模式, 常用于接收通知页面。singleTask
: 新开一个返回栈并创建,或者当返回栈存在时,调用onNewIntent()
。 统一时间只能存在一个该实例。虽然在不同任务栈,但返回时还是会返回之前的 Activity 。, 比如 浏览器, 多次进入走onNewIntent()
, 并且清空上面的页面。singleInstance
, 与“singleTask”相同,只是系统不向包含实例的任务启动任何其他活动。活动总是其任务的唯一成员;由这个启动的任何活动都在一个单独的任务中打开。系统应用, 比如 Launcher, 锁屏应用。