Android Jetpack 架构组件之 Lifecycle (二) 使用

Lifecycle 使用

在 上篇文章 Lifecycle(一) 起源中已经通过一个例子让大家简单的认识到:

将依赖于生命周期的代码直接写在ActivityFragment 会导致代码条理性很差并且会扩散错误。

通过Lifecycle可以将依赖组件的代码从生命周期方法移入组件本身中。
也就是说,组件内部可以感知到Activity 或者Fragment的生命周期

这篇文章具体展开说一下Lifecycle 的用法

预备知识

Lifecycle 中的事件和状态

Lifecycle 通过两个枚举类型:Event 和 State 来 对应 Android 视图组件的生命周期:

    // 事件
    public enum Event {
            ON_CREATE,
            ON_START,
            ON_RESUME,
            ON_PAUSE,
            ON_STOP,
            ON_DESTROY,
            ON_ANY
        }
    //状态
    /**
     * Lifecycle states. You can consider the states as the nodes in a graph and
     * {@link Event}s as the edges between these nodes.
     */
    public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        STARTED,
        RESUMED;

        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }

官方注释告诉我们

你可以将 States 想成一张图中的点,将 Event 想成是图中连接这些点的边。

也就是这一张图:


image

至于这张图的箭头和状态是怎么来的,可以在源码中(LifecycleRegister)找到答案:

static State getStateAfter(Event event) {
        switch (event) {
            case ON_CREATE:
            case ON_STOP:
                return CREATED;
            case ON_START:
            case ON_PAUSE:
                return STARTED;
            case ON_RESUME:
                return RESUMED;
            case ON_DESTROY:
                return DESTROYED;
            case ON_ANY:
                break;
        }
        throw new IllegalArgumentException("Unexpected event value " + event);
    }

逻辑很清楚的可以对应到图中的状态与事件的转换,另外还有两个方法:downEvent(State state) upEvent(State state)也说明了上图中的关系,读者有兴趣的话可以自己查看源码

  • 每一个 Event 映射到Activity或者Fragmnet的其中一个生命周期的回调
  • 每一个 State 反应了由 Lifecycle 跟踪组件的当前状态

⚠️ 不要把Lifecycle想得很神奇,其实质就是简单的观察者模式,首先在视图控制器中注册观察者,Android源码会在生命周期变化后去分发对应生命周期的事件,由LifecycleRegister去调用自己实现的LifecycleEventObserver(上面通过注解方法实现的LifecycleObserve最终也会被解析成LifecycleEventObserver)中的onStateChanged方法。具体原理会在Lifecycle第三篇说到

LifecycleOwner

public interface LifecycleOwner {
    
    @NonNull
    Lifecycle getLifecycle();
}

单一方法的接口,顾名思义:可以将实现了这个接口的类理解为 具有Lifecycle的组件。可以很容易的想到ActivityFragment 已经实现了这个接口:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
       ...
public class Fragment implements 
        LifecycleOwner,
        ViewModelStoreOwner
        ...

所以在使用Lifecycle时可以在Activity或Fragment中直接调用接口方法getLifecycle()

lifecycle.addObserver(NetStateManager)

添加观察者

除此之外,我们也可以通过实现LifecycleOwner来自定义,在Lifecycle系列文章的最后会实现一个自定义LifeOwner帮助大家更好理解

LifecycleObserver

使用Lifecycle的第一步就是要实现LifecycleObserver

object ContentPlayer : LifecycleObserver{

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun prepare(context: Context) {
        //播放器的准备工作
    }
    
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun unAttach() {
        //释放当前持有的Activity资源
    }
    
    //  开始播放
    fun Play(content: String) {
        ...
    }
    ...
}

通过方法注释,明确指定该方法被调用的时机。在上面的例子中,如果在Acitivity中添加ContentPlayer观察者,那么perpare()方法会在Activity创建时调用,unAttach()会在Activity销毁时调用。

实现LifecycleObserver不是只有这一种方法。已经提供了几种内置实现供我们选择:比如官方已经内置实现了LifecycleObserverLifecycleEventObservser


object ContentPlayer : LifecycleEventObserver {
    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        when (event) {
            Lifecycle.Event.ON_CREATE -> TODO()
            Lifecycle.Event.ON_START -> TODO()
            Lifecycle.Event.ON_RESUME -> TODO()
            Lifecycle.Event.ON_PAUSE -> TODO()
            Lifecycle.Event.ON_STOP -> TODO()
            Lifecycle.Event.ON_DESTROY -> TODO()
            Lifecycle.Event.ON_ANY -> TODO()
        }
    }
}

每当视图控制器的状态发生改变,都会将事件回调给onStateChanged(),在不同的事件分支中实现自己想要实现的逻辑。

实际上在使用第一种使用注解的方法的情况下,在运行时LifecycleRegister这个类会通过反射或者apt来将LifecycleObserver转化成LifecycleEventObservser,所以有些情况下为了避免反射带来的消耗,可以优先考虑实现LifecycleEventObservser

添加观察者

最后只需要在Activity的onCreated方法完成最后一步:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        lifecycle.addObserver(ContentPlayer)
    }

最后需要考虑一种情况:如果在Observser中观察了ON_CREATE事件,而我们在ActivityonResume才注册观察者,还能收到发生在onResume()之前的ON_CREATE事件吗?

object Observer : LifecycleObserver{

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate(context: Context) {
        
        Log.d(TAG, "观察onCreate 事件")
        
    }
    
    @OnLifecycleEvent(Lifecycle.Event.ON_Start)
    fun onStart(context: Context) {
        
        Log.d(TAG, "观察onStart 事件")
        
    }
    
    ...
}

然后在ActivityonResume时才注册观察者

override fun onResume(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        lifecycle.addObserver(Observser)
    }

答案是:可以。所以大家放心使用


image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355