@OnLifecycleEnvent 被廢棄,替代方案更簡單
highlight: androidstudio theme: smartblue
近期 androidx.lifecycle 釋出了 2.4.0 版本,此次更新中 @OnLifecycleEvent
註解被廢棄,官方建議使用 LifecycleEventObserver
或者 DefaultLifecycleObserver
替代
現代的 Android 應用中都少不了 Lifecycle 的身影,正是各種 lifecycle-aware 元件的存在保證了程式的健壯性。
Lifecycle 本質是一個觀察者模式的最佳實踐,通過實現 LifecycleObserver
介面,開發者可以自自定 lifecycle-aware 元件,感知 Activity 或 Fragment 等 LifecycleOwner
的生命週期回撥。
趁新版本釋出之際,我們再回顧一下 Lifecycle 註解的使用以及廢棄後的替代方案
Lifecycle Events & States
Lifecyce 使用兩組列舉分別定義了 Event
和 State
。
- Events
- ON_CREATE
- ON_START
- ON_RESUME
- ON_PAUSE
- ON_STOP
- ON_DESTROY
-
ON_ANY
-
States
- INITIALIZED
- CREATED
- STARTED
- RESUMED
- DESTROYED
Events 對應了 Activity 等原生系統元件的生命後期回撥, 每當 Event 發生時意味著這些 LifecycleOwner 進入到一個新的 State。
作為 觀察者的 LifecycleObserver 可以感知到 被觀察者的 LifecycleOwner 其生命週期 State 變化時的 Event。定義 LifecycleObserver
有三種方式:
1. 實現 LifecycleEventObserver
介面
2. 使用 @OnLifecycleEvent
註解
實現 LifecycleEventObserver
java
public interface LifecycleEventObserver extends LifecycleObserver {
void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
LifecycleEventObserver
是一個單方法介面,在 Kotlin 中可轉為寫法更簡潔的 Lambda
進行宣告
kotlin
val myEventObserver = LifecycleEventObserver { source, event ->
when(event) {
Lifecycle.Event.ON_CREATE -> TODO()
Lifecycle.Event.ON_START -> TODO()
else -> TODO()
}
}
LifecycleEventObserver
本身就是 LifecycleObserver
的派生,使用時直接 addObserver
到 LivecycleOwner 的 Lifecycle 即可。
需要在 onStateChanged
中寫 swich / case
自己分發事件。相對於習慣重寫 Activity 或者 Fragment 的 onCreate
, onResume
等方法,稍顯囉嗦。
因此 Lifecycle 給我們準備了 @OnLifecycleEvent
註解
使用 @OnLifecycleEvent 註解
使用方法很簡單,繼承 LifecycleObserver
介面,然後在成員方法上添加註解即可
```kotlin val myEventObserver = object : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onStart() {
TODO()
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreat() {
TODO()
}
} ```
添加註冊後,到 LifecycleOwner 的 Event 分發時,會自動回撥註解匹配的成員方法,由於省去了手動 switch/case
的過程,深受開發者喜歡
註解解析過程
Event 分發時,怎麼就會回到到註解對應的方法的?
通過 addObserver
新增的 LifecycleObserver ,都會轉為一個 LifecycleEventObserver
,LifecycleOwner 通過呼叫其 onStateChanged
分發 Event
在 Lifecycling#lifecycleEventObserver
中處理轉換
```java public class Lifecycling {
@NonNull
static LifecycleEventObserver lifecycleEventObserver(Object object) {
boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
// 觀察者是 FullLifecycleObserver
if (isLifecycleEventObserver && isFullLifecycleObserver) {
return new FullLifecycleObserverAdapter((FullLifecycleObserver) object,
(LifecycleEventObserver) object);
}
// 觀察者是 LifecycleEventObserver
if (isFullLifecycleObserver) {
return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
}
if (isLifecycleEventObserver) {
return (LifecycleEventObserver) object;
}
final Class<?> klass = object.getClass();
int type = getObserverConstructorType(klass);
// 觀察者是通過 apt 產生的類
if (type == GENERATED_CALLBACK) {
List<Constructor<? extends GeneratedAdapter>> constructors =
sClassToAdapters.get(klass);
if (constructors.size() == 1) {
GeneratedAdapter generatedAdapter = createGeneratedAdapter(
constructors.get(0), object);
return new SingleGeneratedAdapterObserver(generatedAdapter);
}
GeneratedAdapter[] adapters = new GeneratedAdapter[constructors.size()];
for (int i = 0; i < constructors.size(); i++) {
adapters[i] = createGeneratedAdapter(constructors.get(i), object);
}
return new CompositeGeneratedAdaptersObserver(adapters);
}
// 觀察者需要通過反射生成一個 wrapper
return new ReflectiveGenericLifecycleObserver(object);
}
...
public static String getAdapterName(String className) {
return className.replace(".", "_") + "_LifecycleAdapter";
}
} ```
邏輯很清晰,根據 LifecycleObserver 型別不用轉成不同的 LifecycleEventObserver,
用一段虛擬碼梳理如下:
kotlin
if (lifecycleObserver is FullLifecycleObserver) {
return FullLifecycleObserverAdapter // 後文介紹
} else if (lifecycleObserver is LifecycleEventObserver) {
return this
} else if (type == GENERATED_CALLBACK) {
return GeneratedAdaptersObserver
} else {// type == REFLECTIVE_CALLBACK
return ReflectiveGenericLifecycleObserver
}
註解有兩種使用用途。
場景一:runtime 時期使用反射生成 wrapper
```java class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver { private final Object mWrapped; private final CallbackInfo mInfo;
ReflectiveGenericLifecycleObserver(Object wrapped) {
mWrapped = wrapped;
mInfo = ClassesInfoCache.sInstance.getInfo(mWrapped.getClass());
}
@Override
public void onStateChanged(LifecycleOwner source, Event event) {
mInfo.invokeCallbacks(source, event, mWrapped);
}
} ```
CallbackInfo
是關鍵,通過反射收集當前 LifecycleObserver 的回撥資訊。onStateChanged
中通過反射呼叫時,不會因為因為缺少 method
報錯。
場景二:編譯時使用 apt 生成 className + _LifecycleAdapter
除了利用反射, Lifecycle 還提供了 apt 方式處理註解。
新增 gradle 依賴:
groovy
dependencies {
// java 寫法
annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.3.1"
// kotlin 寫法
kapt "androidx.lifecycle:lifecycle-compiler:2.3.1"
}
這樣在編譯器就會根據 LifecyceObserver 類名生成一個新增 _LifecycleAdapter
字尾的類。 比如我們加了 onCreat
和 onStart
的註解,生成的程式碼如下:
```java
public class MyEventObserver_LifecycleAdapter implements GeneratedAdapter {
final MyEventObserver mReceiver;
MyEventObserver_LifecycleAdapter(MyEventObserver receiver) { this.mReceiver = receiver; }
@Override public void callMethods(LifecycleOwner owner, Lifecycle.Event event, boolean onAny, MethodCallsLogger logger) { boolean hasLogger = logger != null; if (onAny) { return; } if (event == Lifecycle.Event.ON_CREATE) { if (!hasLogger || logger.approveCall("onCreate", 1)) { mReceiver.onCreate(); } return; } if (event == Lifecycle.Event.ON_START) { if (!hasLogger || logger.approveCall("onStart", 1)) { mReceiver.onStart(); } return; } } } ```
apt 減少了反射的呼叫,效能更好,當然會犧牲一些編譯速度。
為什麼要使用註解
生命週期的 Event 種類很多,我們往往不需要全部實現,如過不使用註解,可能需要實現所有方法,產生額外的無用程式碼
上面程式碼中的 FullLifecycleObserver
就是一個全部方法的介面
```java interface FullLifecycleObserver extends LifecycleObserver {
void onCreate(LifecycleOwner owner);
void onStart(LifecycleOwner owner);
void onResume(LifecycleOwner owner);
void onPause(LifecycleOwner owner);
void onStop(LifecycleOwner owner);
void onDestroy(LifecycleOwner owner);
} ```
從介面不是 public
的( java 程式碼 ) 可以看出,官方也無意讓我們使用這樣的介面,增加開發者負擔。
遭廢棄的原因
既然註解這麼好,為什麼又要廢棄呢?
This annotation required the usage of code generation or reflection, which should be avoided.
從官方文件的註釋可以看到,註解要麼依賴反射降低執行時效能,要麼依靠 APT 降低編譯速度,不是完美的方案。
我們之所引入註解,無非是不想多實現幾個空方法。早期 Android 工程不支援 Java8 編譯,介面沒有 default 方法, 現如今 Java8 已經是預設配置,可以為介面新增 default 方法,此時註解已經失去了存在的意義。
如今官方推薦使用 DefaultLifecycleObserver
介面來定義你的 LifecycleObserver
``` java public interface DefaultLifecycleObserver extends FullLifecycleObserver {
@Override
default void onCreate(@NonNull LifecycleOwner owner) {
}
@Override
default void onStart(@NonNull LifecycleOwner owner) {
}
@Override
default void onResume(@NonNull LifecycleOwner owner) {
}
@Override
default void onPause(@NonNull LifecycleOwner owner) {
}
@Override
default void onStop(@NonNull LifecycleOwner owner) {
}
@Override
default void onDestroy(@NonNull LifecycleOwner owner) {
}
} ```
FullLifecycleObserverAdapter
, 無腦回調 FullLifecycleObserver
即可
```java
class FullLifecycleObserverAdapter implements GenericLifecycleObserver {
private final FullLifecycleObserver mObserver;
FullLifecycleObserverAdapter(FullLifecycleObserver observer) {
mObserver = observer;
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
switch (event) {
case ON_CREATE:
mObserver.onCreate(source);
break;
case ON_START:
mObserver.onStart(source);
break;
case ON_RESUME:
mObserver.onResume(source);
break;
case ON_PAUSE:
mObserver.onPause(source);
break;
case ON_STOP:
mObserver.onStop(source);
break;
case ON_DESTROY:
mObserver.onDestroy(source);
break;
case ON_ANY:
throw new IllegalArgumentException("ON_ANY must not been send by anybody");
}
}
}
``
需要注意
DefaultLifecycleObserver在 2.4.0 之前也是可以使用的, 存在於
androidx.lifecycle.lifecycle-common-java8這個庫中, 2.4.0 開始 統一移動到
androidx.lifecycle.lifecycle-common` 了 ,已經沒有 java8 單獨的擴充套件庫了。
- 探索 Jetpack Compose 核心:深入 SlotTable 系統
- 盤點 Material Design 3 帶來的新變化
- Compose 動畫邊學邊做 - 夏日彩虹
- Google I/O :Android Jetpack 最新變化(二) Performance
- Google I/O :Android Jetpack 最新變化(一) Architecture
- Google I/O :Android Jetpack 最新變化(四)Compose
- Google I/O :Android Jetpack 最新變化(三)UI
- 一文看懂 Jetpack Compose 快照系統
- 聊聊 Kotlin 代理的“缺陷”與應對
- AAB 扶正!APK 再見!
- 面試必備:Kotlin 執行緒同步的 N 種方法
- Jetpack MVVM 七宗罪之六:ViewModel 介面暴露不合理
- CreationExtras 來了,建立 ViewModel 的新方式
- Kotlin DSL 實戰:像 Compose 一樣寫程式碼
- 為什麼 RxJava 有 Single / Maybe 等單發資料型別,而 Flow 沒有?
- 使用整潔架構優化你的 Gradle Module
- 一道面試題:介紹一下 Fragment 間的通訊方式?
- 【程式碼吸貓】使用 Google MLKit 進行影象識別
- Kotlin 1.6 正式釋出,帶來哪些新特性?
- Android Dev Summit '21 精彩內容盤點