标题起的有点大啊,不要在意
我想我不是应该不是第一个自己写 LiveData 的,18年初开始使用 AAC 的这些组件,我觉得 viewModule 不实用,拿 viewModule 当 P 用不是能很好满足需求,LiveData 用了一段时间,尼玛坑死我了,反倒是让我费了不少事,死来想起还是自己写一个 LiveData 吧,自己写的才是最合适自己的
AAC 组件里最有意义的我认为是 LiveData , LiveData 在继 RX 之后深刻的告诉了我们数据流的概念,让我们看到了数据和流最佳的结合方式,这种变化是非常适应时下发展潮流的,但是奈何 LiveData 有些坑让我弃用他了
LiveData 的坑: - 我就不上代码了,用过的都知道
其实自己写个 LiveData 出来非常简单,easy+轻松,核心就是用 PublishSubject 做热发射,热发射不熟悉的朋友可以看我的文章: 我学 rxjava 2(3)- 热发射
在注册的时候用户要是传 Lifecycle ,那么就在 Lifecycle 身上注册一个观察者,页面 onDes 关闭时使用管道解绑,同时一提供一个 map 保存管道,用于用户自行解绑
什么时候响应数据这是用户的自己问题,用户自行判断要不要激活操作,我们都来到 Lifecycle 的时代了, Lifecycle 自身就提供了页面状态的 API,判断起来也不麻烦
// 获取页面状态 lifecycle.currentState // lifecycle 类里有提供状态的枚举 public enum State { DESTROYED, INITIALIZED, CREATED, STARTED, RESUMED; } 复制代码
LiveData 提供变换,但是变换只能变换一个,并且变换得到的 LiveData 不能发射数据,必要使用原始的 LiveData 才行,并且变换 API 不是在 LiveData 身上的,而是一个辅助类,这就用着很不爽了,我们都熟悉了 Rxjava 这么久了,不是链式的 API 我们都 diss 他,这点 Google 有点落后了
// Transformations.map() LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName }); // Transformations.switchMap() LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) ); 复制代码
这里针对变换的问题,我觉得既然 Rxjava 已经实现的很好了,何必在多一手呢,再说再怎么写也肯定不如 rx 不是,所以提供一个方法直接把 subject 抛出来,缺点是就没有自动解绑的功能了,优点是不影响我们发送数据,我们还是用的 subject 发射数据,我测试过了没问题的
为了结构规整,我设计了3层 API,根接口,abs 抽象基类,具体实现,为啥这么麻烦呢,一是为了练手培养代码规范,二是这样设计方便扩展不是
/** * 作者 : BloodCrown * 时间 : 2019-05-05 16:03 * 描述 : 自定义 LiveData 跟接口 * * 1. 提供获取设置数据的接口 * 2. 发送数据的接口 */ interface IMyLiveData<T> { /** * 获取数据 */ fun getValue(): T? /** * 设置数据 */ fun setValue(t: T) /** * 发送 */ fun sendValue(t: T) } 复制代码
/** * 作者 : BloodCrown * 时间 : 2019-05-05 16:09 * 描述 : 自定义 LiveData 的抽象基类 * * 1. 实现根接口,提供数据存储,获取功能 * 2. 发送数据应该是具体实现关心的 * */ abstract class AbsMyLiveData<T> : IMyLiveData<T> { // 数据对象 private var mValue: T? = null override fun getValue(): T? { return mValue } override fun setValue(t: T) { this.mValue = t } } 复制代码
/** * 作者 : BloodCrown * 时间 : 2019-05-05 15:58 * 描述 : * 1. 自定义的 LiveData,为了是去掉 LiveData 一些不合时宜的设定 * 2. 自己写的才能百分百按照自己的设想去做 * * 成员变量描述: * 1. subject 对外提供的 PublishSubject 用于热发射 * 2. disposableList map 集合,用来存储管道对象,因为有的订阅没有页面级别的生命周期 * * 功能: * 1. sendValue 发送数据 * 2. addObserver 注册观察者 * lifecycle != null -> 会在注册观察者的同时,在 Lifecycle.Event.ON_DESTROY 时会解除绑定 * tag != null -> 会把管道对象保存到 map 集合里,用于自助解除注册 */ class MyLiveData<T> : AbsMyLiveData<T>() { // 核心数据数据被观察者 var subject = PublishSubject.create<T>() // 保存管道的 map 集合 var disposableList: MutableMap<String, Disposable> = mutableMapOf() /** * 发送数据 */ override fun sendValue(data: T) { if (data == null) return setValue(data) subject.onNext(data) } /** * 注册观察者,考虑了没有页面级别的生命周期的情况 * * lifecycle != null -> 会在注册观察者的同时,在 Lifecycle.Event.ON_DESTROY 时会解除绑定 * tag != null -> 会把管道对象保存到 map 集合里,用于自助解除注册 */ fun addObserver(tag: String? = null, lifecycle: Lifecycle? = null, observer: (data: T) -> Unit) { var disposable = subject.subscribe { observer(it) } if (tag != null) disposableList.put(tag, disposable) if (disposable != null) lifecycle?.addObserver(object : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun destroy() { if (!disposable.isDisposed) disposable.dispose() disposableList.remove(tag) if (tag != null) disposableList.remove(tag) } }) } /** * 手动解除注册,只适用于在注册时没有传入 lifecycle 的朋友 */ fun removeOberver(tag: String) { if (tag == null) return var disposable = disposableList.get(tag) if (disposable == null) return if (!disposable?.isDisposed) disposable?.dispose() disposableList.remove(tag) } /** * 用于用户自行变换扩展,不过这样就不能自行解绑了,需要用户手动进行解绑操作 */ fun getObservable(): PublishSubject<T> { return subject } } 复制代码
// 创建 MyLiveData 对象 var liveData = MyLiveData<String>() // 注册多个监视器 liveData.addObserver("AA", this.lifecycle) { Log.d("AA", "MyLiveData 接受到数据11: $it") } liveData.addObserver("AA", this.lifecycle) { Log.d("AA", "MyLiveData 接受到数据22: $it") } // 发射数据 liveData.sendValue("AA") // 手动解绑 liveData.removeOberver("AA") 复制代码