@OnLifecycleEnvent 被废弃,替代方案更简单

简介: @OnLifecycleEnvent 被废弃,替代方案更简单

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

image.png

现代的 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

image.png

作为 观察者的 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 单独的扩展库了。

目录
相关文章
|
8天前
|
Kubernetes Shell Docker
ChaosBlade设置问题之无法设置加压时间如何解决
ChaosBlade 是一个开源的混沌工程实验工具,旨在通过模拟各种常见的硬件、软件、网络、应用等故障,帮助开发者在测试环境中验证系统的容错和自动恢复能力。以下是关于ChaosBlade的一些常见问题合集:
|
8月前
|
编解码 移动开发 Java
JDK9优化了哪些功能以及新增了哪些特性功能|JDK各个版本的特性分析
JDK9优化了哪些功能以及新增了哪些特性功能|JDK各个版本的特性分析
|
8月前
|
存储 监控 Java
JDK10优化了哪些功能以及新增了哪些特性功能|JDK各个版本的特性分析
JDK10优化了哪些功能以及新增了哪些特性功能|JDK各个版本的特性分析
|
5月前
|
应用服务中间件 数据安全/隐私保护
请教一个问题,阿里云的edas每次发版,都会有几个版本的deployment的版本存在,怎么设置自动只保留5个版本的啊?
请教一个问题,阿里云的edas每次发版,都会有几个版本的deployment的版本存在,怎么设置自动只保留5个版本的啊?
32 2
|
Prometheus Kubernetes Cloud Native
Flagger(应用自动发布)介绍和原理剖析
## 简介 [Flagger](https://github.com/weaveworks/flagger)是一个能使运行在k8s体系上的应用发布流程全自动(无人参与)的工具, 它能减少发布的人为关注时间, 并且在发布过程中能自动识别一些风险(例如:RT,成功率,自定义metrics)并回滚. ## 主要特性 ![features](https://intranetproxy.ali
4324 0
|
SQL 前端开发 Java
9-TDengine低版本分页offset出现bug,如何平滑升级版本、迁移数据
9-TDengine低版本分页offset出现bug,如何平滑升级版本、迁移数据
531 0
9-TDengine低版本分页offset出现bug,如何平滑升级版本、迁移数据
|
Java 编译器 Android开发
@OnLifecycleEnvent 被废弃,替代方案更简单
近期 androidx.lifecycle 发布了 2.4.0 版本,此次更新中 @OnLifecycleEvent 注解被废弃,官方建议使用 DefaultLifecycleOvserver
401 0
@OnLifecycleEnvent 被废弃,替代方案更简单
|
消息中间件 容灾 关系型数据库
核心特性—全局日志变更
MySQL binlog是MySQL记录变更数据的“二进制日志”,它可以看做是一个消息队列,队列中按顺序保存了MySQL中详细的增量变更信息,通过消费队列中的变更条目,下游系统或工具实现了与MySQL的实时数据同步,这样的机制也称为CDC(Change Data Capture,增量数据捕捉)。
107 0
核心特性—全局日志变更
|
区块链
升级bitcoin0.18后对应接口废弃问题解决方案
升级bitcoin0.18后对应接口废弃问题解决方案
98 0
|
NoSQL Java Redis
Sentinel更新发布 v1.8.2 自适应提高、新增多种支持配置
面向云原生微服务的高可用流控防护组件(A powerful flow control component enabling reliability, resilience and monitoring for microservices. )