[TOC]
# 1. 說明
`LifeCycle`它持有組件的生命周期狀態信息,主要用于`Activity`、`Fragment`、`Service`和`Application`的生命周期管理,其他類可以觀察到這些狀態,進而有利于代碼的解耦。而且在配置更改后可以輕松避免內存泄漏,以及將數據加載到界面中。
比如在Activity 生命周期的狀態和事件:

# 2. Lifecycle
在`Lifecycle`中存在**兩類角色**:
* 具有生命周期的組件,比如`Activity`、`Fragment`、`Service` 等任何具有生命周期的組件,通常被稱為`LifecycleOwner`,也即是被觀察者。
* `LifecycleObserver`,即觀察者,需要感知生命周期方法。
很明顯,也就是觀察者模式。由于在上述組件中已經實現了`LifecycleObserver`接口,比如在`Activity`中:
~~~java
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ContextAware,
LifecycleOwner,
...
~~~
并實現了其`getLifecycle`方法,故而在觀察者模式中被觀察者已經由系統實現,我們所需要做的也就是實現觀察者類,也即是自定義類,實現`LifecycleObserver`接口,然后設置觀察即可。
## 2.1 LifecycleObserver
而該接口又只是一個空接口,即僅用作標識:
~~~java
public interface LifecycleObserver {
}
~~~
## 2.2 LifecycleOwner
LifecycleOwner 是一個接口,用來表示類具有`Lifecycle`。其聲明如下:
~~~java
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
~~~
可以看見只有一個方法,也就是getLifecycle(),
可以通過調用Lifecycle類的addObserver()方法并傳遞觀察器的實例來添加觀察器,比如下面的代碼:
~~~kotlin
class MyObserver : DefaultLifecycleObserver {
? ? override fun onResume(owner: LifecycleOwner) {
? ? ? ? connect()
? ? }
? ? override fun onPause(owner: LifecycleOwner) {
? ? ? ? disconnect()
? ? }
}
myLifecycleOwner.getLifecycle().addObserver(MyObserver())
~~~
# 3. 案例
比如下面的案例:
## 3.1 案例一:使用LifeCycle解耦頁面組件
學習視頻地址:[LifeCycle](https://www.bilibili.com/video/BV1Ry4y1t7Tj?p=2&spm_id_from=pageDriver)
不使用LifeCycle的時候,通過Chronometer計時器來做一個簡單的計時操作,滿足下面條件:
* 當`Activity`可見的時候,繼續計時;
* 當`Activity`不可見的時候,且還沒有被Destory的時候,就暫停當前計時;
### 3.1.1 借助生命周期方法
~~~
class MainActivity : AppCompatActivity() {
// 繼承自TextView的一個計時器類
private lateinit var chronometer: Chronometer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
chronometer = findViewById(R.id.chronometer)
}
private var elapsedtime = 0L
// 可見
override fun onResume() {
super.onResume()
// 設置計時器的起始時間為“當前”系統時間
// SystemClock.elapsedRealtime() 從設備開機到現在的時間
chronometer.base = SystemClock.elapsedRealtime() - elapsedtime
chronometer.start()
}
// 不可見
override fun onStop() {
super.onStop()
elapsedtime = SystemClock.elapsedRealtime() - chronometer.base
chronometer.stop()
}
}
~~~
上面設置`chronometer.base`,主要是用于設置計時器的“當前起始時間”,主要是為了確保暫停后開始的基準時間可以略過中間暫停事件,確保計時器在`Activity`可見后可以連續計時。但是,很顯然,這樣多余了很多額外的周期函數方法,使用比較麻煩。而使用`LifeCycle`可以對其進行最大程度簡化。而且在組件化開發中,基本的原則就是:**能不麻煩別人的事情就盡量自己做**。需要暴露更少的方法來完成其功能。
### 3.1.2 借助LifeCycle
首先封裝一下Chronometer這個類,聲明其實現了LifecycleObserver接口:
~~~
class MyChronometer: Chronometer, LifecycleObserver {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
private var elapsedtime = 0L
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun startChronometer(){
// 設置計時器的起始時間為“當前”系統時間
base = SystemClock.elapsedRealtime() - elapsedtime
start()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopChronometer(){
elapsedtime = SystemClock.elapsedRealtime() - base
stop()
}
}
~~~
將前面案例中的代碼添加到其中,并為其指定了對應的`Lifecycle`事件方法。對應的將`xml`中修改為我們自定義的`MyChronometer`類,然后調用:
~~~
class MainActivity1 : AppCompatActivity() {
// 繼承自TextView的一個計時器類
private lateinit var chronometer: MyChronometer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
chronometer = findViewById(R.id.chronometer)
// 為Activity的lifecycle添加一個監聽
lifecycle.addObserver(chronometer)
}
}
~~~
就可以看見一樣滿足要求的計時器。這兩個案例做一個簡單的對比,很明顯第二種寫法更加利于系統組件和普通組件的**代碼解耦**。這里可以總結一下上面的使用流程:
* 自定義一個類,實現了`LifecycleObserver`接口;
* 在`Activity`或者`Fragment`中進行添加觀察者,以**監聽**對應的生命周期函數;
## 3.2 案例二:使用LifeCycleService解耦Service組件
視頻地址:https://www.bilibili.com/video/BV1Ry4y1t7Tj?p=3&t=863.3
該案例以模擬獲取GPS為案例,具體為在后臺開啟一個Service,然后在這個Service中注冊觀察者對象,在這個觀察者對象中可以觀察到Activity的onStart、onStop等事件。也就可以自動完成進入這個Activity就開始獲取地理位置的更新,退出這個Activity就停止獲取位置。
### 3.2.1. 基礎版本
如果獲取用戶地理位置的功能沒有獨立封裝為一個組件,那么我們如果需要考慮頁面聲明周期,那么就需要按照下面的形式,因為非自定義組件并不能主動感知聲明周期的變化。
~~~kotlin
class LocationActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityLocationBinding>(
this,
R.layout.activity_location
)
}
override fun onResume() {
super.onResume()
// 開始獲取用戶地理位置
startGetLocation()
}
override fun onPause() {
super.onPause()
// 停止獲取
stopGetLocation()
}
}
~~~
### 3.2.2. 使用Service
上面的第一種方式明顯的缺點就是耦合度很高,所以為了減少耦合度,而又不影響對生命周期的監聽,就可以使用`LifeCycle`來進行改寫。故而我們可以自定義一個類,然后使用`LifecycleObserver`來標識這個類為`LifeCycle`的一個觀察者類,在這個類中完成自定義控件,即具體功能。
~~~kotlin
class MyLocationObserver(context: Context): LifecycleObserver {
private var mCtx : Context = context
private lateinit var myLocationListener: MyLocationListener
private lateinit var locationManager: LocationManager
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private fun startGetLocation(){
Log.e("TAG", "startGetLocation: ")
// 獲取LocationManager
locationManager = mCtx.getSystemService(Context.LOCATION_SERVICE) as LocationManager
// 權限
if (ActivityCompat.checkSelfPermission(
mCtx,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
mCtx,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
// 添加監聽
myLocationListener = MyLocationListener()
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 2f, myLocationListener)
}
inner class MyLocationListener: LocationListener{
override fun onLocationChanged(location: Location) {
Log.e("TAG", "onLocationChanged: ${ location }" )
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private fun stopGetLocation(){
Log.e("TAG", "stopGetLocation: ", )
// 移除
locationManager.removeUpdates(myLocationListener)
}
}
~~~
當頁面生命周期發生變化時,這些使用`@OnLifecycleEvent`標識過的方法便會被自動調用。那么在調用的時候,由于`Activity`或者`Service`均已經實現了被觀察者`LifecycleOwner`的接口,故而這里直接調用實現這個接口的`getLifecycle`方法,得到`Lifecycle`對象,然后添加觀察者:
~~~kotlin
lifecycle.addObserver(MyLocationObserver(this))
~~~
注意到,本小節的標題為使用`Service`,這里我們可以使用比較經典的寫一個類繼承自`Service`,根據自己所使用的啟動方式,即`startService`或者`bindService`來復寫對應的`onStartCommand`或者`onBind`方法。然后在`Activity`中進行`startService`或者`bindService`。比如:
~~~kotlin
class MyService: LifecycleService() {
private var _observer: MyLocationObserver = MyLocationObserver(this)
init {
lifecycle.addObserver(_observer)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.e("TAG", "onStartCommand: ")
// 注冊觀察者
val myLocationObserver = MyLocationObserver(this)
lifecycle.addObserver(myLocationObserver)
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
lifecycle.removeObserver(_observer)
}
}
~~~
然后在主`Activity`中啟動服務:
~~~kotlin
class LocationActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityLocationBinding>(
this,
R.layout.activity_location
)
// 啟動服務
startService(Intent().apply {
setClass(this@LocationActivity, MyService::class.java)
})
}
}
~~~
運行可以看見結果:

然后可以使用`adb devices`查看一下設備:

然后可以使用`adb`命令修改模擬位置:
```
adb -s emulator-5554 emu geo fix 101.49612 41.24010
```

就可以發現日志進行了更新:

## 3.3. 案例三:監聽應用程序的生命周期
在`LifeCycle`中提供了`ProcessLifecycleOwner`來實現監聽應用程序的聲明周期。同樣的,這里還是自定義一個類,繼承自`LifecycleObserver`:
~~~kotlin
class MyApplicationObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private fun onCreate() {
Log.e("TAG", "application onCreate.")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private fun onStart() {
Log.e("TAG", "application onStart.")
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
private fun onResume() {
Log.e("TAG", "application onResume.")
}
}
~~~
然后在`Activity`中使用:
~~~
class LocationActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityLocationBinding>(
this,
R.layout.activity_location
)
// 添加應用程序生命周期觀察者對象
ProcessLifecycleOwner.get().lifecycle.addObserver(MyApplicationObserver())
}
}
~~~
就可以監聽到應用程序的生命周期變化。

- ProcessLifecycleOwner是針對整個應用程序的監聽,與Activity數量無關;
- Lifecycle.Event.ON_CREATE只會被調用一次,而Lifecycle.Event.ON_DESTROY永遠不會被調用。