Jetpack Architecture - Lifecycle

简介

在 Android 系统中,有很多系统组件具备生命周期,比如ActivityFragmentService...很多时候,我们都必须在系统组件的相应生命周期中执行自定义组件的相关逻辑,这样其实我们自定义的组件就与 Android 系统组件耦合在一起了。当我们有很多自定义组件都需要嵌入到系统组件的生命周期时,系统组件的代码就会急剧膨胀且严重与普通组件产生耦合,不利于功能扩展,违背设计模式开闭原则...

究其原因,非常简单,就是我们自定义的组件无法感知宿主系统组件生命周期,因此才会产生耦合。Android 开发团队也意识到这个问题,于是在 Jetpack Architecture 中,提供了一种可以感知系统组件生命周期的组件:Lifecycle,借助该组件,我们的普通组件就具备感知宿主系统组件生命周期能力,这样就解耦了普通组件与系统组件之间的耦合。

Lifecycle的基本原理是:采用观察者模式,系统组件作为被观察者(LifecycleOwner),我们自定义的普通组件作为观察者(LifecycleObserver),只需在感兴趣的系统组件注册自定义普通组件,则当相应宿主系统组件生命周期发生变化时,普通组件就能感知到。

目前Lifecycle可以感知的系统组件(即已实现LifecycleOwner接口的系统组件)包括:ActivityFragmentServiceApplication,具体感知方法参见下文。

依赖引入

Lifecycle位于 AndriodX appcompat 包中,具体依赖添加如下:

implementation 'androidx.appcompat:appcompat:1.2.0'

感知 Activity

Activity应当是最常被普通组件进行感知的系统组件,其具体生命周期感知方法如下步骤所叙:

  1. 首先自定义一个普通组件,让其实现接口LifecycleObserver,作为观察者,具备生命周期感知能力:

    inline val <reified T> T.TAG: String
        get() = T::class.java.simpleName
    
    class MyComponent : LifecycleObserver {
    
        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        fun init() {
            Log.v(TAG, "initialize...")
        }
    
        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        fun release() {
            Log.v(TAG, "release...")
        } 
    }
    

    这里我们的自定义普通组件为MyComponent,由于其实现了LifecycleObserver接口,因此其实一个观察者,相应系统组件的生命周期感知通过注解OnLifecycleEvent进行指定,完整的生命周期感知事件定义枚举类Lifecycle.Event中,具体内容如下表所示:

    生命周期事件 描述
    ON_CREATE 对应onCreate事件
    ON_START 对应onStart事件
    ON_RESUME 对应onResume事件
    ON_PAUSE 对应onPause事件
    ON_STOP 对应onStop事件
    ON_DESTROY 对应onDestroy事件
    ON_ANY 对应上述所有事件

    Lifecycle中除了通过注解@OnLifecycleEvent监听宿主组件生命周期外,还可通过继承DefaultLifecycleObserverFullLifecycleObserver,只需覆写相应的生命周期方法即可,此处不再赘述。
    :默认情况下,基于注解的方式采用的是反射进行回调,效率相对差些,因此最好添加一个编译期处理器lifecycle-compiler,消除反射调用。使能编译期注解处理只需为模块的build.gradle配置如下内容即可:

    // 导入编译期注解处理器
    apply plugin: 'kotlin-kapt'
    
    dependencies {
        def lifecycle_version = "2.2.0"
    
        // Annotation processor
        kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
    }
    

    此时,被@OnLifecycleEvent注解的方法就不能声明为private的。

  2. 在系统组件(此处是Activity)中注册自定义普通组件:

    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            // 注册组件:MyComponent
            this.lifecycle.addObserver(MyComponent())
        }
    }
    

    在 AndroidX 中,其ComponentActivity已经默认实现了LifecycleOwner

    package androidx.activity;
    ...
    public class ComponentActivity extends androidx.core.app.ComponentActivity implements
            LifecycleOwner,
            ViewModelStoreOwner,
            SavedStateRegistryOwner,
            OnBackPressedDispatcherOwner {
    
        private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
        ...
        @NonNull
        @Override
        public Lifecycle getLifecycle() {
            return mLifecycleRegistry;
        }
    }
    

    AppCompatActivity间接继承自ComponentActivity,所以我们自定义的MainActivity默认可被观察。
    :如果项目仍未迁移到 AndroidX,还是采用 Support 库,那么可以让自定义Activity继承SupportActivity,因为SupportActivity本身已实现了接口LifecycleOwner

  3. 以上,就完成了自定义普通组件感知Activity生命周期,运行程序后关闭应用,可看到如下日志:

    $ adb logcat -v time | rg MyComponent
    03-14 23:28:06.049 V/MyComponent(14836): initialize...
    03-14 23:29:51.886 V/MyComponent(14836): release...
    

    说明我们自定义组件已经成功感知到MainActivity的生命周期了。

感知 Fragment

在 AndroidX 新版本中,Fragment同样以默认实现了接口LifecycleOwner

package androidx.fragment.app;
...
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
        ViewModelStoreOwner, SavedStateRegistryOwner {
    ...
    LifecycleRegistry mLifecycleRegistry;
    ...
    @Override
    @NonNull
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
    ...
}

因此,感知Fragment的生命周期与感知Activity生命周期方法如出一辙,这里简单介绍下:

  1. 首先创建一个Fragment,并设置相应布局:

    • Fragment布局文件:
    <!--layout/fragment_mine.xml-->
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="This is a Fragment"
            android:textSize="24sp" />
    
    </LinearLayout>
    
    • 自定义Fragment
    class MyFragment : Fragment() {
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            return inflater.inflate(R.layout.fragment_mine, container, false)
        }
    }
    
  2. MainActivity布局中添加该自定义Fragment

    <!--layout/activity_main.xml-->
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <fragment
            <!-- 不能省略 id -->
            android:id="@+id/myfragment"
            <!-- 指定加载的 Fragment -->
            android:name="com.yn.jetpackarchdemo.fragment.MyFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
    
  3. 将自定义组件MyComponent注册到MyFragment中,这里通过在Fragment.onAttach(..)方法内进行注册:

    class MyFragment : Fragment() {
    
        override fun onAttach(context: Context) {
            super.onAttach(context)
            // 注册
            this.lifecycle.addObserver(MyComponent())
        }
    
        override fun onCreateView(...): View? {...}
    }
    

    以上,就完成了自定义组件感知Fragment生命周期全过程。

感知 Service

如果要实现感知Service生命周期,解耦Service和自定义普通组件,可使用LifecycleService

package androidx.lifecycle;
...
public class LifecycleService extends Service implements LifecycleOwner {

    private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);
    ...
    @Override
    @NonNull
    public Lifecycle getLifecycle() {
        return mDispatcher.getLifecycle();
    }
}

可以看到,LifecycleService继承了Service并且实现了LifecycleOwner

  1. 首先,在使用LifecycleService前,需要先添加依赖

    def lifecycle_version = '2.3.0'
    implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
    
    
  2. 创建一个普通组件且实现LifecycleObserver,使能观察者身份。这里我们直接使用上文的MyComponent即可。

  3. 创建一个MyService类,继承LifecycleService,这样我们定义的系统组件就可以作为一个被观察者,其他普通组件通过向MyService注册即可感知MyService生命周期:

    class MyService : LifecycleService() {
    
        init {
            // 注册
            this.lifecycle.addObserver(MyComponent())
        }
    }
    

    记得在 AndroidManifest.xml 中注册MyService

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.yn.jetpackarchdemo">
    
        <application
            ...
            <service android:name=".service.MyService" />
        </application>
    
    </manifest>
    
  4. 其实以上就已经完成了,这里为了能进行测试,我们修改下MainActivity的布局:

    <!-- layout/activity_main.xml -->
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/startServiceBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="startService" />
    
        <Button
            android:id="@+id/stopServiceBtn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="stopService" /> 
    </LinearLayout>
    

    这里定义了两个按钮,分别用于启动Service和停止Service,具体代码如下:

    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            // 启动 Service
            this.startServiceBtn.setOnClickListener {
                this.startService(Intent(this, MyService::class.java))
                Toast.makeText(this, "startService done!", Toast.LENGTH_SHORT).show()
            }
    
            // 退出 Service
            this.stopServiceBtn.setOnClickListener {
                this.stopService(Intent(this, MyService::class.java))
                Toast.makeText(this, "stopService done!", Toast.LENGTH_SHORT).show()
            }
        }
    }
    

    运行程序,依序点击以上两个按钮,就可看到效果。

感知 Application

很多时候,我们可能想要知道当前应用程序是处于前台还是后台,或者当应用在进行前后台切换时,普通组件能感知到,此时,可以借助ProcessLifecycleOwner,该类是Lifecycle提供的可让我们感知应用程序生命周期的组件(也即感知Application生命周期),具体操作步骤如下:

  1. 首先,导入相关依赖:

    def lifecycle_version = '2.3.0'
    implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
    
  2. 自定义一个普通组件,实现接口LifecycleObserver,并覆写相应生命周期方法:

    private const val TAG = "MyAppComponent"
    
    class MyAppComponent : LifecycleObserver {
    
        // ON_CREATE 在整个应用程序运行期间只会调用一次
        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        fun onCreate() {
            Log.v(TAG, "onCreate")
        }
    
        // 程序处于前台
        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onStart() {
            Log.v(TAG, "onStart")
        }
    
        // 程序处于前台
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        fun onResume() {
            Log.v(TAG,"onResume")
        }
    
        //程序处于后台
        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        fun onPause() {
            Log.v(TAG,"onPause")
        }
    
        // 程序处于后台
        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onStop() {
            Log.v(TAG,"onStop")
        }
    
        // Application 不会分发该事件,因此 ON_DESTROY永远不会被调用
        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        fun onDestroy() {
            Log.v(TAG, "onDestroy")
        }
    }
    
  3. 自定义一个Application类,并使用ProcessLifecycleOwner注册相应普通组件,完成监听绑定:

    class MyApplication : Application() {
        override fun onCreate() {
            super.onCreate()
            ProcessLifecycleOwner.get().lifecycle.addObserver(MyAppComponent())
        }
    }
    

    记得在 AndroidManifest.xml 中注册我们自定义的Applicatioin

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.yn.jetpackarchdemo">
    
        <application
            android:name=".MyApplication"
            ...
        /application>
    </manifest>
    
  4. 以上,就完成了对应用程序生命周期的感知。

借助ProcessLifecycleOwner,我们就能很方便感知到应用程序前后台切换动作,当程序首次启动时,会依次触发ON_CREATEON_STARTON_RESUME生命周期事件,此时程序处于前台;当程序从前台切到后台时,会依次触发ON_PAUSEON_STOP事件(注:这两个事件响应会相对迟缓,因为必须让步于屏幕旋转而导致的Activity重新创建问题,即屏幕旋转不会导致这两个事件被误触发);后续如果程序从后台又重新返回前台时,此时就只会依序触发ON_STARTON_RESUME事件。因此,在应用程序的整个运行期间,ON_CREATE只会被调用一次(首次启动时),ON_DESTROY永远不会被调用。

主动获取系统组件当前生命周期

上文我们所介绍的普通组件都是被动的感知系统组件生命周期,其实Lifecycle也提供了相应方法来让我们主动获取当前生命周期,该接口为Lifecycle.getCurrentState(),其返回一个State枚举实例,表示当前系统组件的生命周期,具体内容如下:

@SuppressWarnings("WeakerAccess")
public enum State {
    DESTROYED,

    INITIALIZED,

    STARTED,

    RESUMED;

    // 当前状态是否大于或等于参数状态
    public boolean isAtLeast(@NonNull State state) {
        return compareTo(state) >= 0;
    }
}

Lifecycle维护并追踪记录了系统组件生命周期状态相关信息,在系统组件整个生命周期流程过程中,Lifecycle分别对应的生命周期状态维护如下图所示:

States and events that comprise the Android activity lifecycle

简单来说,当获取的生命周期状态为CREATED时,表示系统组件的onCreate方法已执行结束(即ON_CREATE事件结束),但onStart()方法还未执行。同理,当获取生命周期状态为STARTED时,说明系统组件的onStart()方法以运行结束,但onResume()方法仍未执行...

为普通组件添加主动查询生命周期方法其实很简单,只需将系统组件的Lifecycle实例传递给普通组件即可:

// 普通组件
class MyComponent(private val lifecycle: Lifecycle) : LifecycleObserver {...}

// 系统组件
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 注册
        this.lifecycle.addObserver(MyComponent(this.lifecycle))
}

当普通组件覆写的相应生命周期方法内,存在回调函数时,此时运行回调函数前,就很有必要主动查询下当前系统组件所处生命周期状态,避免因生命周期不当而导致相关执行出错:

class MyComponent(private val lifecycle: Lifecycle) : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun init() {
        thread {
            // 模拟耗时任务
            Thread.sleep(TimeUnit.SECONDS.toMillis(2))
            if(this.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
                // do something
            }
        }.start()
    }
}

自定义生命周期可被感知的系统组件

前面介绍的所有系统组件都是默认已内置了生命周期感知共享功能,而如果我们自己想手动实现一个生命周期可被感知的组件,其实也很简单,执行为自定义系统组件提供一个Lifecycle即可,具体示例如下所示:

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

Android 系统自带的Activity本身不具备生命周期被感知功能,我们只需为其添加一个Lifecycle实例,维护与分发其生命周期即可:

  1. 首先为MyActivity创建一个Lifecycle实例,负责维护与管理其生命周期相关信息。这里使用的是LifecycleRegistry,该类继承自Lifecycle,并实现了相应的生命周期状态管理与维护逻辑,方便我们使用。

  2. MyActivity每个生命周期函数中,LifecycleRegistry都进行了标记,以实现生命周期被感知功能。

  3. 最后,MyActivity实现了接口LifecycleOwner,该接口是一个单抽象方法接口,其抽象方法为getLifecycle(),作用就是返回系统组价的内置Lifecycle,方便外部普通组件进行注册(被动感知生命周期)与主动查询状态等操作。

参考

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

推荐阅读更多精彩内容