@OnLifecycleEvent 被废弃,替代方案是?

刘望舒

共 3229字,需浏览 7分钟

 ·

2021-11-08 15:41

 BATcoder技术群,让一部分人先进大厂

大家,我是刘望舒,腾讯TVP,著有三本业内知名畅销书,连续四年蝉联电子工业出版社年度优秀作者,百度百科收录的资深技术专家。

前华为架构师,现独角兽技术负责人


想要加入 BATcoder技术群,公号回复BAT 即可。


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



耗时2年,Android进阶三部曲第三部《Android进阶指北》出版!

『BATcoder』做了多年安卓还没编译过源码?一个视频带你玩转!

『BATcoder』我去!安装Ubuntu还有坑?

重生!进阶三部曲第一部《Android进阶之光》第2版 出版!

为了防止失联,欢迎关注我的小号

  微信改了推送机制,真爱请星标本公号👇
浏览 95
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报