放弃官方,拥抱自我,自定义 LiveData 才是最合适的

栏目: Android · 发布时间: 5年前

内容简介:标题起的有点大啊,不要在意我想我不是应该不是第一个自己写 LiveData 的,18年初开始使用 AAC 的这些组件,我觉得 viewModule 不实用,拿 viewModule 当 P 用不是能很好满足需求,LiveData 用了一段时间,尼玛坑死我了,反倒是让我费了不少事,死来想起还是自己写一个 LiveData 吧,自己写的才是最合适自己的AAC 组件里最有意义的我认为是 LiveData , LiveData 在继 RX 之后深刻的告诉了我们数据流的概念,让我们看到了数据和流最佳的结合方式,这种变

标题起的有点大啊,不要在意

放弃官方,拥抱自我,自定义 LiveData 才是最合适的

我想我不是应该不是第一个自己写 LiveData 的,18年初开始使用 AAC 的这些组件,我觉得 viewModule 不实用,拿 viewModule 当 P 用不是能很好满足需求,LiveData 用了一段时间,尼玛坑死我了,反倒是让我费了不少事,死来想起还是自己写一个 LiveData 吧,自己写的才是最合适自己的

AAC 组件里最有意义的我认为是 LiveData , LiveData 在继 RX 之后深刻的告诉了我们数据流的概念,让我们看到了数据和流最佳的结合方式,这种变化是非常适应时下发展潮流的,但是奈何 LiveData 有些坑让我弃用他了

LiveData 的坑: - 我就不上代码了,用过的都知道

  • 必须在主线程发送数据
  • 注册观察者必须要传 Lifecycle,有时候我们并不是都在页面级别使用的,比如说拿 LiveData 当 RXbus 用,虽然有不用传 Lifecycle 的方法 observeForever,但是穿与不穿 Lifecycle 居然是2个 api 我觉得用着不爽
  • LiveData 最大的问题,同时也是我最不能接受的:LiveData 无法判断值是不是新值,只要 LiveData 设置过数据了,那么不管你是不是第一次注册观察者或者页面重新激活显示时,都会收到消息没,这就不能忍了,这不就是乱发射数据嘛,完全不能准确的表达我发射数据的动作,老的数据也发,很多时候我并不需要你现在的数据,这让我很为难,为了处理这个问题,浪费了不少精力,反倒是麻烦了,就像我讨厌有的 Google API 的命名,什么垃圾玩意,什么名都敢起,有的时候查字典看翻译我都不知道是干嘛的

自定义 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 发射数据,我测试过了没问题的

自定义 LiveData 代码

为了结构规整,我设计了3层 API,根接口,abs 抽象基类,具体实现,为啥这么麻烦呢,一是为了练手培养代码规范,二是这样设计方便扩展不是

放弃官方,拥抱自我,自定义 LiveData 才是最合适的
  • 根接口 - 就是设置,获取,发射数据,使用泛型接受数据类型
/**
 * 作者 : BloodCrown
 * 时间 : 2019-05-05 16:03
 * 描述 : 自定义 LiveData 跟接口
 *
 *  1. 提供获取设置数据的接口
 *  2. 发送数据的接口
 */
interface IMyLiveData<T> {

    /**
     * 获取数据
     */
    fun getValue(): T?

    /**
     * 设置数据
     */
    fun setValue(t: T)

    /**
     * 发送
     */
    fun sendValue(t: T)
}
复制代码
  • abs 抽象基类 - 填充数据对象
/**
 * 作者 : 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")
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

凸优化

凸优化

Stephen Boyd、Lieven Vandenberghe / 王书宁、许鋆、黄晓霖 / 清华大学出版社 / 2013-1 / 99.00元

《信息技术和电气工程学科国际知名教材中译本系列:凸优化》内容非常丰富。理论部分由4章构成,不仅涵盖了凸优化的所有基本概念和主要结果,还详细介绍了几类基本的凸优化问题以及将特殊的优化问题表述为凸优化问题的变换方法,这些内容对灵活运用凸优化知识解决实际问题非常有用。应用部分由3章构成,分别介绍凸优化在解决逼近与拟合、统计估计和几何关系分析这三类实际问题中的应用。算法部分也由3章构成,依次介绍求解无约束......一起来看看 《凸优化》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具