@OnLifecycleEvent 遭废弃,推荐使用 DefaultLifecycleObserver 替代

news/2024/7/3 13:21:22

近期 androidx.lifecycle 发布了 2.4.0 版本,此次更新中 @OnLifecycleEvent 注解被废弃,官方建议使用 LifecycleEventObserver 或者 DefaultLifecycleObserver 替代

现代的 Android 应用中都少不了 Lifecycle 的身影,正是各种 lifecycle-aware 组件的存在保证了程序的健壮性。

Lifecycle 本质是一个观察者模式的最佳实践,通过实现 LifecycleObserver 接口,开发者可以自自定 lifecycle-aware 组件,感知 Activity 或 Fragment 等 LifecycleOwner 的生命周期回调。

趁新版本发布之际,我们再回顾一下 Lifecycle 注解的使用以及废弃后的替代方案

Lifecycle Events & States

Lifecyce 使用两组枚举分别定义了 EventState

  • 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

public interface LifecycleEventObserver extends LifecycleObserver {
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}

LifecycleEventObserver 是一个单方法接口,在 Kotlin 中可转为写法更简洁的 Lambda
进行声明

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 的 onCreateonResume 等方法,稍显啰嗦。

因此 Lifecycle 给我们准备了 @OnLifecycleEvent 注解

使用 @OnLifecycleEvent 注解

使用方法很简单,继承 LifecycleObserver 接口,然后在成员方法上添加注解即可

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 中处理转换

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,

用一段伪代码梳理如下:

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

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 依赖:

dependencies {
    // java 写法
    annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.3.1"
    // kotlin 写法
    kapt "androidx.lifecycle:lifecycle-compiler:2.3.1"
}

这样在编译器就会根据 LifecyceObserver 类名生成一个添加 _LifecycleAdapter 后缀的类。 比如我们加了 onCreatonStart 的注解,生成的代码如下:

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 就是一个全部方法的接口

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

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 即可

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 单独的扩展库了。


http://www.niftyadmin.cn/n/2071159.html

相关文章

Jetpack Compose 动态权限申请(Permission Request)

在 Jetpack Compose 动态申请权限可以使用两种方法 rememberLancherForActivityResultAccompanist 的 Permissions 接下来分贝展示一下两种用法 代码环境如下: Kotlin 1.5.2Jetpack Compose 1.0.2Android Studio Chipmunk | 2021.2.1 要使用 Accompanist 需要额外引入 de…

Kotlin 1.6 正式发布,都有哪些新特性?

11月16日&#xff0c;Kotlin 1.6 正式对外发布。接下来就一起看一下在这个版本中都有哪些新的语法特性 更安全的when语句&#xff08;exhaustive when statements&#xff09;挂起函数类型可作父类 &#xff08;suspending functions as supertypes &#xff09;普通函数转挂起…

【Android】实战图像识别:Compose + MLKit + CameraX

MLKit 是 Google 提供的移动端机器学习库&#xff0c;可以在 Andorid 或 iOS 上低成本地实现各种 AI 能力&#xff0c;例如图像、文字、人脸识别等等&#xff0c;而且很多能力可以在手机端离线完成。 https://developers.google.com/ml-kit 下面通过代码示例展示 MLKit 的以下功…

Jetpack Compose 易犯错误之:在 LazyColumn 中访问 LazyListState

我们在使用 LazyColumn 或者 LazyRow 时&#xff0c;应该避免在 LazyListScope 中访问 LazyListState&#xff0c;这可能会造成隐藏的性能问题&#xff0c;看下面的代码&#xff1a; Composable fun VerticalList(items: List<String>, onReachedBottom: () -> Unit)…

Compose Multiplatform 正式版将于年内发布

近日&#xff0c;JetBrains 公司发布了 Compose Multiplatform 的 Beta 版本&#xff0c;这距离此前 Alpha 版本的发布才过去两个多月。 这个版本中包含了许多新的改进&#xff0c;在桌面端与Web端分别增加了新的 API &#xff0c;并对已有的部分 APIs 进行了稳定。Beta 版的发…

对标 VSCode?JetBrains 下一代编辑器 Fleet

11 月 29 日 JetBrains 官方发布了全新的轻量级编辑器 Fleet&#xff0c;并号称是基于20年IDE开发经验打造的“新一代 IDE”。 Fleet 的定位更加纯粹&#xff0c;聚焦编辑器功能而非替代现有的 IDE 产品。据推测 Fleet 的推出主要是 JetBrains 为了对抗微软的 VSCode &#xff…

10个问题带你看懂 Compose Multiplatform 1.0

近日 JetBrains 正式发布了 Compose Multiplatform 1.0 版&#xff0c;这标志其在生产环境中使用的时机已经成熟。相信有不少人对它还不太熟悉&#xff0c;本文通过下面 10 个热门问题带大家认识这一最新的跨平台技术。 FAQ&#xff1a; 与 Jetpack Compose 的关系? 是否会取代…

Jetpack MVVM 七宗罪之四: 使用 LiveData/StateFlow 发送 Events

久违的 “ Jetpack MVVM 七宗罪 ” 系列&#xff0c;今日再开。本系列主要盘点 MVVM 架构中各种常见错误写法&#xff0c;并针对性的给出最佳实践&#xff0c;帮助大家掌握 Jetpack 组件最正确的使用姿势。 Jetpack MVVM 七宗罪之一: 拿 Fragment 当 LifecycleOwnerJetpack MVV…