Lifecycle
Lifecycle
Lifecycle 基础
背景
用于将系统组件(Activity、Fragment 等等)的生命周期分离到 Lifecycle
类,Lifecycle 允许其他类作为观察者,观察 Activity/Fragment 组件生命周期的变化。
如 MVP 中的 Presenter,可以监听到 Activity 或 Fragment 中生命周期变化来做对应的操作。
使用
官方示例:https://github.com/googlecodelabs/android-lifecycles
引入
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
//根目录的 build.gradle
repositories {
google()
...
}
//app的build.gradle
dependencies {
def lifecycle_version = "2.2.0"
def arch_version = "2.1.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// 只有Lifecycles (不带 ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
// Saved state module for ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// lifecycle注解处理器
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
// 替换 - 如果使用Java8,就用这个替换上面的lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
//以下按需引入
// 可选 - 帮助实现Service的LifecycleOwner
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
// 可选 - ProcessLifecycleOwner给整个 app进程 提供一个lifecycle
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
// 可选 - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version"
// 可选 - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$arch_version"
}
1、定义观察者 LifecycleObserver
- Java7 及之前用注解
@OnLifecycleEvent
1
2
3
4
5
6
7
8
9
10
public interface IPresenter extends LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate(@NotNull LifecycleOwner owner);
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onDestroy(@NotNull LifecycleOwner owner);
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
void onLifecycleChanged(@NotNull LifecycleOwner owner, @NotNull Lifecycle.Event event);
}
- Java8 用
DefaultLifecycleObserver
,用的是接口默认方法,android.arch.lifecycle:common-java8:<version>
,继承了FullLifecycleObserver
接口,本身也是个接口
例如 MVP 中的 Presenter 实现该接口
- LifecycleEventObserver
2、在 Activity/Fragment 容器中添加 Observer
1
2
3
4
5
6
7
8
9
10
11
public class MainActivity extends AppCompatActivity {
private IPresenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPresenter = new MainPresenter(this);
getLifecycle().addObserver(mPresenter);//添加LifecycleObserver
}
}
每当 Activity 发生了对应的生命周期改变,Presenter 就会执行对应事件注解的方法
3、生命周期变化通知观察者
Activity 或 Fragment 生命周期变化时,就会通知 LifecycleObserver
Lifecycle 和协程
lifecycleScope 导致 ANR?
注意
addObserver 后是否需要 removeObserver?
官方回答是不需要,但是在源码中没找到 removeObserver 相关代码。
https://github.com/googlecodelabs/android-lifecycles/issues/5
LifecycleObserver 中的 dialog 内存泄漏
- 泄漏的代码:
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
37
38
39
40
41
class LifecycleDialogManager(private val act: FragmentActivity) : DefaultLifecycleObserver {
private var dialog: MiniRoomDialog? = null // 泄漏
private var alertDialog: AlertDialog? = null // 不会泄漏,dismiss时置空了
init {
act.lifecycle.addObserver(this)
}
fun showDialog() {
dialog = MiniRoomDialog() // 泄漏
AppWatcher.objectWatcher.expectWeaklyReachable(dialog!!, "MiniRoomDialog对象泄漏检测")
dialog?.show(act)
}
fun showAlertDialog() {
val builder = AlertDialog.Builder(act)
builder.setTitle("提示:")
builder.setMessage("这是一个普通对话框,")
builder.setIcon(R.mipmap.ic_launcher)
builder.setCancelable(true)
alertDialog = builder.create()
alertDialog?.setOnDismissListener {
alertDialog = null // 不会泄漏
}
alertDialog?.show()
AppWatcher.objectWatcher.expectWeaklyReachable(alertDialog!!, "AlertDialog对象泄漏检测")
}
override fun onDestroy(owner: LifecycleOwner) {
if (dialog != null && dialog!!.isVisible) {
dialog?.dismiss()
dialog = null
}
if (alertDialog != null && alertDialog!!.isShowing) {
alertDialog?.dismiss()
alertDialog = null
}
}
}
dialog 存在泄漏;alertDialog 不存在泄漏,因为在 dismiss 时,将引用置空了
- 泄漏堆栈:
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
┬───
│ GC Root: System class
│
├─ android.app.ActivityThread class
│ Leaking: NO (Lifecycle引用Dialog内存泄漏测试Activity↓ is not leaking and a class
│ is never leaking)
│ ↓ static ActivityThread.sCurrentActivityThread
├─ android.app.ActivityThread instance
│ Leaking: NO (Lifecycle引用Dialog内存泄漏测试Activity↓ is not leaking)
│ mInitialApplication instance of me.hacket.assistant.debug.DebugApp
│ mSystemContext instance of android.app.ContextImpl
│ mSystemUiContext instance of android.app.ContextImpl
│ ↓ ActivityThread.mActivities
├─ android.util.ArrayMap instance
│ Leaking: NO (Lifecycle引用Dialog内存泄漏测试Activity↓ is not leaking)
│ ↓ ArrayMap.mArray
├─ java.lang.Object[] array
│ Leaking: NO (Lifecycle引用Dialog内存泄漏测试Activity↓ is not leaking)
│ ↓ Object[].[1]
├─ android.app.ActivityThread$ActivityClientRecord instance
│ Leaking: NO (Lifecycle引用Dialog内存泄漏测试Activity↓ is not leaking)
│ activity instance of me.hacket.assistant.samples.google.architecture.
│ lifecycle.dialog.Lifecycle引用Dialog内存泄漏测试Activity with mDestroyed = false
│ ↓ ActivityThread$ActivityClientRecord.activity
├─ me.hacket.assistant.samples.google.architecture.lifecycle.dialog.
│ Lifecycle引用Dialog内存泄漏测试Activity instance
│ Leaking: NO (Activity#mDestroyed is false)
│ mApplication instance of me.hacket.assistant.debug.DebugApp
│ mBase instance of androidx.appcompat.view.ContextThemeWrapper
│ ↓ ComponentActivity.mLifecycleRegistry
│ ~~~~~~~~~~~~~~~~~~
├─ androidx.lifecycle.LifecycleRegistry instance
│ Leaking: UNKNOWN
│ Retaining 490.3 kB in 1691 objects
│ ↓ LifecycleRegistry.mObserverMap
│ ~~~~~~~~~~~~
├─ androidx.arch.core.internal.FastSafeIterableMap instance
│ Leaking: UNKNOWN
│ Retaining 490.1 kB in 1686 objects
│ ↓ SafeIterableMap.mEnd
│ ~~~~
├─ androidx.arch.core.internal.SafeIterableMap$Entry instance
│ Leaking: UNKNOWN
│ Retaining 56 B in 3 objects
│ ↓ SafeIterableMap$Entry.mPrevious
│ ~~~~~~~~~
├─ androidx.arch.core.internal.SafeIterableMap$Entry instance
│ Leaking: UNKNOWN
│ Retaining 56 B in 3 objects
│ ↓ SafeIterableMap$Entry.mKey
│ ~~~~
├─ me.hacket.assistant.samples.google.architecture.lifecycle.dialog.
│ LifecycleDialogManager instance
│ Leaking: UNKNOWN
│ Retaining 50.8 kB in 821 objects
│ act instance of me.hacket.assistant.samples.google.architecture.lifecycle.
│ dialog.Lifecycle引用Dialog内存泄漏测试Activity with mDestroyed = false
│ ↓ LifecycleDialogManager.dialog
│ ~~~~~~
╰→ me.hacket.assistant.samples.ui.动画.直播间动画方案.最小化动画.MiniRoomDialog instance
Leaking: YES (ObjectWatcher was watching this because me.hacket.assistant.
samples.ui.动画.直播间动画方案.最小化动画.MiniRoomDialog received Fragment#onDestroy()
callback and ObjectWatcher was watching this because MiniRoomDialog对象泄漏检测
and Fragment#mFragmentManager is null)
Retaining 50.8 kB in 820 objects
key = c212fc7a-01e9-4671-b7b6-1432e8b90161
watchDurationMillis = 8714
retainedDurationMillis = 3713
key = c337b0b6-0da4-4459-8375-504cac03e86d
watchDurationMillis = 9376
retainedDurationMillis = 4326
METADATA
Build.VERSION.SDK_INT: 29
Build.MANUFACTURER: Xiaomi
LeakCanary version: 2.7
App process name: me.hacket.assistant
Stats: LruCache[maxSize=3000,hits=5822,misses=64738,hitRate=8%]
RandomAccess[bytes=3535826,reads=64738,travel=27379915308,range=20594612,size=25
383126]
Heap dump reason: 7 retained objects, app is visible
Analysis duration: 3569 ms
- 分析
当前 LifecycleOwner 是个 Activity(Lifecycle引用Dialog内存泄漏测试Activity
),LifecycleDialogManager 是一个 LifecycleObserver,LifecycleOwner 中有一个 Lifecycle 实例 mLifecycleRegistry(LifecycleRegistry
是 Lifecycle 的实现子类),在我们 addObserver 时,会将 LifecycleObserver 即 LifecycleDialogManager 包装下保存在LifecycleRegistry#mObserverMap
变量中。当我们 show 了一个 dialog 时,首先 new 了一个 dialog,然后将该 dialog 的引用保存在 LifecycleDialogManager,当我们还未退出 Activity 时,将 dialog dismiss 时,由于此时LifecycleRegistry#mObserverMap
保存着 LifecycleObserver 实例,而 LifecycleDialogManager 又持有 dialog 的引用,进而导致 dialog dimiss 时,但由于还被 LifecycleDialogManager 持有着一直不能释放,进而导致该 dialog 内存泄漏了 - 解决
在 dialog dismiss 时,将其在 LifecycleObserver 中的引用置为 null 即可。 - 总结
在 LifecyleObserver 中不要持有比 LifecycleOwner 生命周期短的变量,如 Dialog;如果要持有,需要 Dialog 在 dismiss 时将 LifecycleObserver 中保存的变量给置空
使用场景
view 中获取 LifecycleOwner
用 androidX 的 ViewTreeLifecycleOwner
:ViewTreeLifecycleOwner.get(view)
Fragment/AppCompatActivity/DialogFragment
MVP 中 Presenter 添加 Lifecycle 感知 – Presenter 作为 LifecycleObserver
1
2
3
4
5
6
7
8
9
10
11
public interface IPresenter extends DefaultLifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate(@NonNull LifecycleOwner owner);
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onDestroy(@NonNull LifecycleOwner owner);
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
void onLifecycleChanged(@NonNull LifecycleOwner owner, @NonNull Lifecycle.Event event);
}
自定义 View 感知事件 – 自定义 View 作为 LifecycleObserver
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
public class CustomView extends FrameLayout implements DefaultLifecycleObserver {
@Override
public void onCreate(@NonNull LifecycleOwner owner) {
Log.d(TAG, "onCreate");
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
Log.d(TAG, "onStart");
}
@Override
public void onResume(@NonNull LifecycleOwner owner) {
Log.d(TAG, "onResume");
}
@Override
public void onPause(@NonNull LifecycleOwner owner) {
Log.d(TAG, "onPause");
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
Log.d(TAG, "onStop");
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner) {
Log.d(TAG, "onDestroy");
}
}
组件关联的时候,需要创建 DefaultLifecycleObserver 的实例,实现类 CustomView 就是 LifecycleObserver 的实例,然后将其添加到 Observer 中,就可以进行生命周期的感知了。
1
2
CustomView view = findViewById(R.id.custom);
getLifecycle().addObserver(view);
自动移除 Handler 的消息:LifecycleHandler
1
2
3
4
5
6
7
8
9
10
11
class LifecycleHandler(val owner: LifecycleOwner, looper: Looper? = null, callback: Callback? = null) : Handler(looper, callback), DefaultLifecycleObserver {
fun addObserver(): LifecycleHandler {
owner.lifecycle.addObserver(this)
return this
}
override fun onDestroy(owner: LifecycleOwner) {
removeCallbacksAndMessages(null)
owner.lifecycle.removeObserver(this)
}
}
给 ViewHolder 添加 Lifecycle 的能力
有些 App 会有长列表的页面,里面塞了各种不用样式的 Item,通常会用 RecyclerView 来实现,有时候部分 Item 需要获知生命周期事件,比如包含播放器的 Item 需要感知生命周期来实现暂停/重播的功能,借助 Lifecycle 我们可以实现。
https://github.com/AlanCheen/Flap/blob/master/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.java
将自己的组件作为 LifecycleOwner (实现自定义 LifecycleOwner)
支持库 26.1.0 及更高版本中的 Fragment 和 Activity 已实现 LifecycleOwner 接口。如果您有一个自定义类并希望使其成为 LifecycleOwner,您可以使用 LifecycleRegistry 类,但需要将事件转发到该类,如以下代码示例中所示:
- 生命周期生产者实现 LifecycleOwner,我们称之为被观察者
- 组合 LifecycleRegistry,处理生命周期的变化
- 生命周期监听者,称之为观察者,addObserver() 监听生命周期
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyActivity : Activity(), LifecycleOwner {
private lateinit var lifecycleRegistry: LifecycleRegistry
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
}
public override fun onStart() {
super.onStart()
lifecycleRegistry.markState(Lifecycle.State.STARTED)
}
override fun getLifecycle(): Lifecycle {
return lifecycleRegistry
}
}
ViewLifecycleOwner
- 让一个 view 具备 lifecycle 能力
- 在其 visible 时发送
ON_CREATE
事件,gone 或 invisible 时,发送ON_STOP事件
,onViewDetachedFromWindow 时发送ON_DESTROY
事件
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class ViewLifecycleOwnerDelegate(val view: View) : ViewLifecycleOwner,
View.OnAttachStateChangeListener {
private val mLifecycleRegistry = LifecycleRegistry(this)
init {
view.addOnAttachStateChangeListener(this)
handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
}
// Android5.1及以下onVisibilityChanged在构造方法中调用,子类在onVisibilityChanged访问成员变量会导致空指针;
// 避免在子类onVisibilityChanged调用初始化的成员变量,注意判空
fun onVisibilityChanged(visibility: Int) {
if (mLifecycleRegistry.currentState.isAtLeast(Lifecycle.State.CREATED)) {
when (visibility) {
View.VISIBLE -> {
handleLifecycleEvent(Lifecycle.Event.ON_START)
}
View.GONE -> {
handleLifecycleEvent(Lifecycle.Event.ON_STOP)
}
View.INVISIBLE -> {
handleLifecycleEvent(Lifecycle.Event.ON_STOP)
}
}
}
}
private fun handleLifecycleEvent(@NonNull event: Lifecycle.Event) {
mLifecycleRegistry.handleLifecycleEvent(event)
}
override fun getLifecycle(): Lifecycle {
return mLifecycleRegistry
}
override fun onViewAttachedToWindow(v: View?) {
handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
}
override fun onViewDetachedFromWindow(v: View?) {
if (mLifecycleRegistry.currentState.isAtLeast(Lifecycle.State.CREATED) && mLifecycleRegistry.currentState != Lifecycle.State.DESTROYED) {
handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
}
view.removeOnAttachStateChangeListener(this)
}
}
interface ViewLifecycleOwner : LifecycleOwner
让某个实现 ViewLifecycleOwner 接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class KittyGameView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : FrameLayout(context, attrs), ViewLifecycleOwner {
private val mViewLifecycleOwnerDelegate: ViewLifecycleOwnerDelegate? = null
override fun getLifecycle(): Lifecycle {
return getViewLifecycleOwnerDelegate().lifecycle
}
private fun getViewLifecycleOwnerDelegate(): ViewLifecycleOwnerDelegate {
var view = mViewLifecycleOwnerDelegate
if (view == null) {
view = ViewLifecycleOwnerDelegate(this)
}
return view
}
override fun onVisibilityChanged(changedView: View, visibility: Int) {
getViewLifecycleOwnerDelegate().onVisibilityChanged(visibility)
}
// ...
}
RecyclerView.ViewHolder
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// from mashi
open class LifecycleViewHolder(view: View?) : BaseViewHolder(view), LifecycleOwner, ViewHolderStateListener {
companion object {
private const val TAG = "LifecycleViewHolder"
private var DEBUG = false
}
private var mLifecycleRegistry: LifecycleRegistry = object: LifecycleRegistry(this) {
override fun addObserver(observer: LifecycleObserver) {
super.addObserver(observer)
if (DEBUG) Log.i(TAG,
"observer ${this@LifecycleViewHolder.hashCode()} " +
"${this.observerCount} addObserver ${observer.hashCode()}")
}
override fun removeObserver(observer: LifecycleObserver) {
super.removeObserver(observer)
if (DEBUG) Log.i(TAG,
"observer ${this@LifecycleViewHolder.hashCode()} " +
"${this.observerCount} removeObserver ${observer.hashCode()}")
}
}
override fun getLifecycle(): Lifecycle {
return mLifecycleRegistry
}
@CallSuper
override fun onViewAttachedToWindow() {
if (DEBUG) Log.i(TAG, "hash = ${hashCode()} " + " onViewAttachedToWindow")
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
}
@CallSuper
override fun onViewDetachedFromWindow() {
if (DEBUG) Log.i(TAG, "hash = ${hashCode()} " + " onViewDetachedFromWindow")
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
}
@CallSuper
override fun onRecyclerViewDetach() {
if (DEBUG) Log.i(TAG, "hash = ${hashCode()} " + " onRecyclerViewDetach ")
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
}
@CallSuper
open fun onDataBound() {
if (DEBUG) Log.i(TAG, "hash = ${hashCode()} " + " bindData " + "${mLifecycleRegistry.currentState}")
// 避免将START->STOP的状态重置为ONCREATE
if (!mLifecycleRegistry.currentState.isAtLeast(Lifecycle.State.CREATED)) {
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
}
}
@CallSuper
open fun onViewRecycled() {
if (DEBUG) Log.i(TAG, "hash = ${hashCode()} " + " onViewRecycled ")
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
}
}
Lifecycle 总结
Activity/Fragment 是个 LifecycleOwner 是生命周期的拥有者,是一个被观察者;LifecycleEventObserver 是观察者;Lifecycle 是观察者管理类,通过该类管理观察者的注册和反注册
1、Activity
Activity 的 Lifecycle 实现原理,就是在 onCreate 里面 ReportFragment.injectIfNeededIn(this);
,根据 API 是否大于等于 29,如果大于等于 29 的话就用 Application.ActivityLifecycleCallbacks
中的声明周期回调,如果小于的话,就用 ReportFragment 的生命周期回调
在生命周期回调里,会调用 LifecycleRegistry 的 handleLifecycleEvent 来做状态的移动,最终会调用你注册的 LifecycleEventObserver 的 onStateChanged,从而实现声明周期的感知
2、Fragment
Fragment 的实现原理和 Activity 的类似,只是 Fragment 没有 ReportFragment,它只是在自己的生命周期内调用 LifecycleRegistry 的 handleLifecycleEvent 来通知它的 LifecycleEventObserver 生命周期的变更