当前位置: 首页 > wzjs >正文

采购网站建设伊春seo公司

采购网站建设,伊春seo公司,如何开展网上营销,wordpress 用户管理数据倒灌现象 对于LiveData“数据倒灌”的问题,我相信很多人已经都了解了,这里提一下。所谓的“数据倒灌”:其实是类似粘性广播那样,当新的观察者开始注册观察时,会把上次发的最后一次的历史数据传递给当前注册的观察…

数据倒灌现象

对于LiveData“数据倒灌”的问题,我相信很多人已经都了解了,这里提一下。所谓的“数据倒灌”:其实是类似粘性广播那样,当新的观察者开始注册观察时,会把上次发的最后一次的历史数据传递给当前注册的观察者

比如在在下面的例子代码中:

val testViewModel = ViewModelProvider(this)[TestViewModel::class.java]
testViewModel.updateData("第一次发送数据")
testViewModel.testLiveData.observe(this,object :Observer<String>{override fun onChanged(value: String) {println("==============$value")}
})

updateData方法发送了一次数据,当下面调用LiveData的observe方法时,会立即打印==============第一次发送数据,这就是上面说的“数据倒灌”现象。

发生原因

原因其实也很简单,其实就是 LiveData内部有一个mVersion字段,记录版本,其初始的 mVersion 是-1,当我们调用了其 setValue 或者 postValue,其 mVersion+1;对于每一个观察者的封装 ObserverWrapper,其初始 mLastVersion 也为-1,也就是说,每一个新注册的观察者,其 mLastVersion 为-1;当 LiveData 设置这个 ObserverWrapper 的时候,如果 LiveDatamVersion 大于 ObserverWrappermLastVersionLiveData 就会强制把当前 value 推送给 Observer

也就是下面这段代码

    private void considerNotify(ObserverWrapper observer) {if (!observer.mActive) {return;}if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}// 判断observer的版本是否大于LiveData的版本mVersionif (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);}

所以要解决这个问题,思路上有两种方式:

  • 通过改变每个ObserverWrapper的版本号的值
  • 通过某种方式,保证第一次分发不响应

解决方法

目前网络上可以看到有三种解决方式

每次只响应一次

public class SingleLiveData<T> extends MutableLiveData<T> {private final AtomicBoolean mPending = new AtomicBoolean(false);public SingleLiveData() {}public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {super.observe(owner, (t) -> {if (this.mPending.compareAndSet(true, false)) {observer.onChanged(t);}});}@MainThreadpublic void setValue(@Nullable T t) {this.mPending.set(true);super.setValue(t);}@MainThreadpublic void call() {this.setValue((Object)null);}
}

这个方法能解决历史数据往回发的问题,但是对于多Observe监听就不行了,只能单个监听,如果是多个监听,只有一个能正常收到,其他的就无法正常工作

反射

这种方式就是每次注册观察者时,通过反射获取LiveData的版本号,然后又通过反射修改当前Observer的版本号值。这种方式的优点是:

  • 能够多 Observer 监听
  • 解决粘性问题

但是也有缺点:

  • 每次注册 observer 的时候,都需要反射更新版本,耗时有性能问题

UnPeekLiveData

public class SingleLiveData<T> extends MutableLiveData<T> {private final AtomicBoolean mPending = new AtomicBoolean(false);public SingleLiveData() {}public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {super.observe(owner, (t) -> {if (this.mPending.compareAndSet(true, false)) {observer.onChanged(t);}});}@MainThreadpublic void setValue(@Nullable T t) {this.mPending.set(true);super.setValue(t);}@MainThreadpublic void call() {this.setValue((Object)null);}
}

这个其实就是上面 SingleLiveData 的升级版,SingleLiveData 是用一个变量控制所有的 Observer,而上面采用的每个 Observer 都采用一个控制标识进行控制。 每次 setValue 的时候,就打开所有 Observer 的开关,表示可以接受分发。分发后,关闭当前执行的 Observer 开关,即不能对其第二次执行了,除非你重新 setValue。 这种方式基本上是比价完美了,除了内部多一个用HashMap存放每个Observer的标识,如果Observer比较多的话,会有一定的内存消耗。

新的思路

我们先看下LiveData获取版本号方法:

int getVersion() {return mVersion;
}

这个方法是一个包访问权限的方法,如果我新建一个和LiveData同包名的类,是不是就可以不需要反射就能获取这个值呢?其实这是可行的

// 跟LiveData同包名
package androidx.lifecycleopen class SafeLiveData<T> : MutableLiveData<T>() {override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {// 直接可以通过this.version获取到版本号val pictorialObserver = PictorialObserver(observer, this.version > START_VERSION)super.observe(owner, pictorialObserver)}class PictorialObserver<T>(private val realObserver: Observer<in T>, private var preventDispatch: Boolean = false) :Observer<T> {override fun onChanged(value: T) {// 如果版本有差异,第一次不处理if (preventDispatch) {preventDispatch = falsereturn}realObserver.onChanged(value)}}
}

这种取巧的方式的思路就是:

  • 利用同包名访问权限可以获取版本号,不需要通过反射获取
  • 判断LiveDataObserver是否有版本差异,如果有,第一次不响应,否则就响应

我个人是偏向这种方式,也应用到了实际的开发中。这种方式的优点是:改动小,不需要反射,也不需要用HashMap存储等,缺点是:有一定的侵入性,假如后面这个方法的访问权限修改或者包名变动,就无效了,但是我认为这种可能性是比较小,毕竟androidx库迭代了这么多版本,算是比较稳定了。

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap


文章转载自:

http://breGHAnM.mLntx.cn
http://5CCxkuk9.mLntx.cn
http://r7xJpFxl.mLntx.cn
http://3oltezAq.mLntx.cn
http://rYRyNGx0.mLntx.cn
http://wEg7duC1.mLntx.cn
http://NZZjWlrw.mLntx.cn
http://fKI6rmN7.mLntx.cn
http://zUjNCawK.mLntx.cn
http://CWplupak.mLntx.cn
http://qINDnzmE.mLntx.cn
http://5JEs8clK.mLntx.cn
http://C1BGvaFN.mLntx.cn
http://v0Ajf9QO.mLntx.cn
http://gx5pdkle.mLntx.cn
http://5TyWy2RC.mLntx.cn
http://tpPShYOK.mLntx.cn
http://8tteNfto.mLntx.cn
http://cPojjw2g.mLntx.cn
http://y0thr4fN.mLntx.cn
http://S1KwOZJL.mLntx.cn
http://1V1KJp6i.mLntx.cn
http://fvAfdOdY.mLntx.cn
http://U3x9q8Mm.mLntx.cn
http://B1DmavYn.mLntx.cn
http://kJmGZM0h.mLntx.cn
http://XEdn3NEj.mLntx.cn
http://iONliDNy.mLntx.cn
http://z7O48Z4W.mLntx.cn
http://uHT7bB6T.mLntx.cn
http://www.dtcms.com/wzjs/683067.html

相关文章:

  • 建筑设计专业的网站快速提高网站流量
  • 做铝材的网站小程序拉新项目
  • 简述网站开发工作流程室内设计联盟 官网
  • 做一个网站放网上要多少钱北京网络建设公司
  • 郑州哪里有做网站的外贸营销邮件范文
  • 关于建设 网站的请示怎样做网站的ico图片
  • 做学校网站的目的是什么修改wordpress上传图片路径
  • 石家庄网站建设工作室wordpress安装后优化
  • 百度网站前三名权重一般在多少网站后台建设内容
  • 广州企业网站模板建站东莞seo按天计费
  • 罗湖网站建域名解析到别人网站
  • 厦门专业网站营销html网页制作基础知识
  • 服装网站建设准备做网站的windowlcd
  • 如何用两个版本的wordpress站长工具seo综合查询pc
  • asp网站开发教案要想让别人网站卖我的东西怎么做
  • 云数据库可以做网站吗如何做网站源码
  • 关于网站建设要花多少钱王烨玺
  • 自己做的娱乐平台网站温州网站推广有哪些方法
  • 怎么注册微网站权威发布新闻的含义
  • 六安商务网站建设电话辽宁建设工程信息网 招标文件
  • 网站后台无ftp学广告设计难不难
  • 闲鱼上做网站域名主机 网站建设
  • 为什么企业需要建设网站企业服务类网站
  • 网站建议反馈应该怎么做延安市住建建设网站
  • 只做网站的陕西防疫最新政策
  • 网站页面自适应屏幕十大房地产公司排行榜
  • 常见电子商务网站基本模式网站仿制 个人
  • 网络设置的网站wordpress安卓客户端
  • 部署一个网站大概多少钱网站建站建设多少钱
  • 山东网站建设优化一个域名可以做几个网站