2.2 Lifecycle的基本使用
2.2.1 使用Lifecycle优化广告引导页的需求
什么是Lifecycle呢?Lifecycle是Jetpack架构组件中用来感知生命周期的组件,使用Lifecycle可以帮助开发者写出与生命周期相关且更简洁、更易维护的代码。这单纯从定义上可能并不好理解,接下来通过优化上面所述广告引导页的功能来展示Lifecycle的具体使用方法。
首先在项目中添加Lifecycle组件的依赖项,代码如下:
dependencies { ... def lifecycle_version = "2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" ... }
接着在广告管理类AdvertisingManage中实现LifecycleObserver接口,代码如下:
object AdvertisingManage:LifecycleObserver { ... }
通过LifecycleObserver的源码可以看出,LifecycleObserver是一个空接口,所以开发者不需要实现额外的方法。
然后通过OnLifecycleEvent注解将方法与生命周期绑定,比如,要在Activity onCreate的生命周期中执行AdvertisingManage类的onStart方法,且在onDestroy的生命周期中执行onCancel方法,那么可以采用如下代码:
/** * 开始计时 */ @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun start() { Log.d(TAG, "开始计时") countDownTimer?.start() } /** * 停止计时 */ @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onCancel() { Log.d(TAG, "停止计时") countDownTimer?.cancel() countDownTimer = null }
当然仅这样还不行,还要在Activity中通过addObserver方法注册Advertising-Manage,此时应该将之前在Activity生命周期中主动调用的方法移除。修改后Activity的代码如下:
class AdvertisingActivity : AppCompatActivity() { //跳过广告按钮 lateinit var btnIngore: Button //广告时间 lateinit var tvAdvertisingTime: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_advertising) val advertisingManage = AdvertisingManage() lifecycle.addObserver(advertisingManage) btnIngore = findViewById(R.id.btn_ignore) tvAdvertisingTime = findViewById(R.id.tv_advertising_time) advertisingManage.advertisingManageListener = object : AdvertisingManage.AdvertisingManageListener { override fun timing(second: Int) { tvAdvertisingTime.text = "广告剩余$second秒" } override fun enterMainActivity() { MainActivity.actionStart(this@AdvertisingActivity) finish() } } //跳过广告点击事件 btnIngore.setOnClickListener { MainActivity.actionStart(this@AdvertisingActivity) finish() } }
再次运行程序,打印日志如图2-3所示。
图2-3 打印日志
从图2-3中可以看到,最终结果与之前的结果无异,但是使用Lifecycle改造后的实现方式极大简化了Activity中的代码逻辑,这种方式也使得业务功能与Activity业务逻辑分离。
现在回过头来看OnLifecycleEvent的注解方法,其中,Lifecycle.Event的枚举如下:
public enum Event { /** * Constant for onCreate event of the {@link LifecycleOwner}. */ ON_CREATE, /** * Constant for onStart event of the {@link LifecycleOwner}. */ ON_START, /** * Constant for onResume event of the {@link LifecycleOwner}. */ ON_RESUME, /** * Constant for onPause event of the {@link LifecycleOwner}. */ ON_PAUSE, /** * Constant for onStop event of the {@link LifecycleOwner}. */ ON_STOP, /** * Constant for onDestroy event of the {@link LifecycleOwner}. */ ON_DESTROY, /** * An {@link Event Event} constant that can be used to match all events. */ ON_ANY; }
上述代码中,前面几个状态分别对应Activity的生命周期,最后一个ON_ANY状态则表示可对应Activity的任意生命周期。
再来看注册的方法lifecycle.addObserver(AdvertisingManage),为什么它可以直接调用getLifecycle方法呢?那是因为getLifecycle是接口LifecycleOwner的实现方法。LifecycleOwner的源码如下:
public interface LifecycleOwner { /** * Returns the Lifecycle of the provider. * * @return The lifecycle of the provider. */ @NonNull Lifecycle getLifecycle(); }
通过追溯源码可以发现,当前Activity继承的是androidx.core.app.Component-Activity,而ComponentActivity实现了LifecycleOwner接口,所以开发者可以直接调用getLifecycle方法。实现ComponentActivity类的源码如下:
public class ComponentActivity extends Activity implements LifecycleOwner, KeyEventDispatcher.Component { ... }
除了ComponentActivity之外,在ComponentActivity的子类androidx.fragment.app.FragmentActivity、androidx.appcompat.app.AppCompatActivity以及androidx.fragment.app.Fragment中都是可以直接使用Lifecycle的,这是AndroidX帮助开发者完成的。
如果当前Activity继承的是没有实现LifecycleOwner接口的android.app.Activity,会发生什么呢?为了便于测试,这里直接将当前Activity的继承修改为android.app.Activity,之后你会看到lifecycle.addObserver(AdvertisingManage)这行代码报错了,这就是因为android.app.Activity没有实现getLifecycle方法,这时,自定义LifecycleOwner就派上用场了。
2.2.2 自定义LifecycleOwner
使用getLifecycle方法的前提是当前父类实现了LifecycleOwner接口,因此若需要在没有实现LifecycleOwner接口的类中使用该方法,则需要自定义LifecycleOwner。
首先,让继承自Activity类的页面实现LifecycleOwner接口并重写getLifecycle方法,修改后的代码如下:
class AdvertisingActivity : Activity(), LifecycleOwner { //跳过广告按钮 lateinit var btnIngore: Button //广告时间 lateinit var tvAdvertisingTime: TextView lateinit var lifecycleRegistry: LifecycleRegistry override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_advertising) val advertisingManage = AdvertisingManage() lifecycle.addObserver(advertisingManage) btnIngore = findViewById(R.id.btn_ignore) tvAdvertisingTime = findViewById(R.id.tv_advertising_time) advertisingManage.advertisingManageListener = object : AdvertisingManage.AdvertisingManageListener { override fun timing(second: Int) { tvAdvertisingTime.text = "广告剩余$second秒" } override fun enterMainActivity() { MainActivity.actionStart(this@AdvertisingActivity) finish() } } //跳过广告点击事件 btnIngore.setOnClickListener { MainActivity.actionStart(this@AdvertisingActivity) finish() } } override fun getLifecycle(): Lifecycle { return lifecycleRegistry } }
如此,就实现了与继承AppCompatActivity时同样的效果。这样一来就可以通过注解方法主动执行对应生命周期的方法了。如果开发者想主动获取当前Activity的生命周期状态,又该如何做呢?
开发者可以使用Lifecycle的getCurrentState方法,从源码可以看出,getCurrentState会返回如下种类的State:
public enum State { DESTROYED, INITIALIZED, CREATED, STARTED, RESUMED; }
State种类状态返回值与Activity生命周期的对应关系如图2-4所示。
图2-4 State返回值与Activity生命周期的对应关系
如果getCurrentState返回的值是STARTED,则说明当前Activity已经执行了onStart方法,但是还未执行onResume方法,其他返回值可以此类推。Lifecycle的使用场景有很多,比如,在下载文件的需求中,想要节省流量,那么可以在App处于后台时停止下载,当App置于前台时又能自动恢复下载。这个功能的具体实现就交给读者去尝试了。接下来看看在实际项目中Lifecycle还可以解决哪些常见的问题。