欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > 一种全局数据变化而且是多个的通知实现

一种全局数据变化而且是多个的通知实现

2024/10/24 8:26:57 来源:https://blog.csdn.net/jzlhll123/article/details/140556897  浏览:    关键词:一种全局数据变化而且是多个的通知实现

有个需求:
从activityA,打开activityB, activityC 或者还存在viewpager上的其他Fragment。甚至activityB,又打开了activityBA。
在这些界面上,大家都有相同的数据Bean(name, info, isFavourite)去展示成卡片列表。
这种情况下,当操作了某个界面的Bean数据,更新当前自己是很容易的;但是当想更新其他界面,其他activity就比较麻烦了。

这里给出一个实现方案。

interface ICrossNotify<T> {@MainThreadfun onCrossNotify(data:List<T>?)
}
 
/*** @date :2024/7/18 19:34* @description: 跨activity通知。* 必须把它变成一个单例(或存储在单例里面,唯一。但可以多个实例。)** 用法在Activity或者Fragment* 1. onCreate()里面调用callOnCreate(this)* 2. 然后,给它实现ICrossNotify接口。一切就已经完成。** 更新数据,调用changeData,必须保证是主线程。** 内部会针对,监听的前后,分别通知不同的时机的数据。*/
class CrossActivityNotifyListObserver<T : Any>(private val mainHandler:Handler) : DefaultLifecycleObserver{//value的左边代表是否监听后,有更新过。右边代表更新后的值。private data class CrossActivityNotifyListInfo<T>(var isResumed:Boolean,val data: ArrayList<T> = ArrayList(4))private val TAG = "crossNotify"private val callbackList = HashMap<LifecycleOwner, CrossActivityNotifyListInfo<T>>(8)/*** 如果你希望数据进行去重,比如Info(a, b, c),其中以a字段如果相同就认为是同一份数据,* 本类中将会进行去重。避免多次操作同一个对象。*/var distinct:((a:T, b:T)->Boolean)? = null/*** 每次resume都调用本函数。内部做了处理。*/fun callOnCreate(owner: LifecycleOwner) {//如果不存在,就将入监听列表if (owner !is ICrossNotify<*>) {throw IllegalArgumentException("Do not call callOnCreate() because owner is not ICrossNotify!")}owner.lifecycle.addObserver(this)callbackList[owner] = CrossActivityNotifyListInfo(isResumed = true)if (BuildConfig.DEBUG) Log.d(TAG, "callOnCreate add owner $owner")}/*** 暂定必须,不得为空。* 会帮你运行在主线程。*/fun notify(d:T) {if (BuildConfig.DEBUG) {Log.d(TAG, "changeData $d")}if (!isMainThread) {mainHandler.post {changeDataMainThread(d)}} else {changeDataMainThread(d)}}private fun changeDataMainThread(d: T) {callbackList.forEach { (owner, info) ->addWithDistinct(info, d)if (info.isResumed) {if (BuildConfig.DEBUG) Log.d(TAG, "changeData owner $owner isResumed onDateChanged")owner.asOrNull<ICrossNotify<T>>()?.onCrossNotify(fetchAndClear(info))} else {if (BuildConfig.DEBUG) Log.d(TAG, "changeData owner $owner isNotResumed just save")}}}override fun onResume(owner: LifecycleOwner) {super.onResume(owner)//如果已经存在,就把当前的通知出来。val info = callbackList[owner]!!info.isResumed = trueif (info.data.isNotEmpty()) {if (BuildConfig.DEBUG) Log.d(TAG, "onResumeCall exist $owner onDataChanged ${info.data}")val outList = fetchAndClear(info)owner.asOrNull<ICrossNotify<T>>()?.onCrossNotify(outList)} else {if (BuildConfig.DEBUG) Log.d(TAG, "onResumeCall exist $owner no change.")}}private fun addWithDistinct(info: CrossActivityNotifyListInfo<T>, data:T) {distinct?.let { dist->var size = info.data.sizewhile (size > 0) { //倒序遍历移除size--if (dist(info.data[size], data)) {info.data.removeAt(size)}}}info.data.add(data)}private fun fetchAndClear(info: CrossActivityNotifyListInfo<T>): List<T>? {if (info.data.isEmpty()) {return null}val outList = ArrayList<T>(info.data)info.data.clear()return outList}override fun onPause(owner: LifecycleOwner) {super.onPause(owner)callbackList[owner]?.isResumed = falseif (BuildConfig.DEBUG) Log.d(TAG, "onPause owner $owner")}override fun onDestroy(owner: LifecycleOwner) {super.onDestroy(owner)callbackList.remove(owner)if (BuildConfig.DEBUG) Log.d(TAG, "onDestroy owner remove $owner")}
}

在全局的某个单例中定义全局单例变量:


val changeData = CrossActivityNotifyListObserver<Pair<String, Boolean>>(mainHandler).also {it.distinct = { a, b->a.first == b.first}}

在更新数据的时候,changeData.notify(bean)。

想监听的activity、fragment,在onCreate函数中调用callOnCreate,并让它实现ICrossNotify即可。

这个简易的框架的目的是当onResume状态下,就把当前通知的单条变化直接通知到;
非resume状态下,就收集后,等待resume一来就发送。

代码设计为避免了粘性数据,即从某个界面监听开始,后续的变化它才会接受到。而且提供了计算去重distinct 的逻辑,比如Bean(name, info, isFavourite), 你可以判断a.name == b.name 就认为它是相同的,就允许覆盖。

简易好用。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com