前语
ViewModel 和 LiveData 作为JetPack 中架构组件中重要的组件,调配好运用能大大提升开发效率。
ViewModel
ViewModel 具有生命周期认识,会主动存储和管理 UI 相关的数据,即便设备装备发生变化后数据还会存在,ViewModel的呈现会让让Activity专心于视图控制器的人物,业务逻辑交给ViewModel,很好地将视图与逻辑分离开来。不止于此,ViewModel还能在Fragment之间通讯。
ViewModel 在Activity 之间通讯
ViewModel 能在Framgment 通讯,这很好理解,由于他们有一起的载体Activity,就能创立相同的ViewModel实例:
private val shareViewModel by lazy {
ViewModelProvider(requireActivity()).get(ShareViewModel::class.java)
}
每点击一次HomeFragment我都会延迟更新数据。
class ShareViewModel :ViewModel() {
val data = MutableLiveData<String>()
var count = 0
fun getData(){
Handler(Looper.getMainLooper()).postDelayed({
count++
data.value = "from the activity$count"
},2000)
data.value = "from the activity$count"
}
}
然后每个Fragment 监听自己的数据源就能够:
shareViewModel.data.observe(viewLifecycleOwner, Observer {
textView.text = it
})
可是好像实际开发中,跨Activity共享数据的状况更多,这个时候又该怎样处理呢?
ViewModelProvider接纳的是ViewModelStoreOwner子类目标,Activity 和 Fragment都完成了ViewModelStoreOwner接口。想要跨Activity共享数据,咱们让Application完成ViewModelStoreOwner接口,经过Application来创立ViewModel不就能完成跨Activity通讯的问题,代码如下:
class MyApp : Application(), ViewModelStoreOwner {
private val TAG = "MyApp"
private val appViewModelStore: ViewModelStore by lazy {
ViewModelStore()
}
override fun onCreate() {
super.onCreate()
AppScope.init(this)
}
override fun onTerminate() {
super.onTerminate()
appViewModelStore.clear()
}
override fun getViewModelStore(): ViewModelStore {
return appViewModelStore
}
}
其中 AppScope:
object AppScope {
private lateinit var myApp: MyApp
fun init(application: MyApp){
myApp = application
}
/**
* 获取进程共享的ViewModel
*/
fun <T : ViewModel?> getAppScopeViewModel(modelClass: Class<T>): T {
return ViewModelProvider(myApp).get(modelClass)
}
}
这里咱们做个小Demo,SecActivity 发动修改页面ThirdActivity,修改成功后,数据回来 SecActivity。 它们运用一起的EditViewModel,创立方法如下:
private val editViewModel: EditViewModel by lazy {
AppScope.getAppScopeViewModel(EditViewModel::class.java)
}
监听数据变化
editViewModel.inputData.observe(this, Observer {
it.let {
tv?.text = it
}
})
运转一把:
进入修改页面后,修改5689,关闭页面,数据确实传递到了SecActivity,共享数据成功,可是也带来了新的问题,从头进入SecActivity,依然接纳了原来了的数据,这是LiveData支持粘性事情导致的,接下来咱们谈谈LiveData。
LiveData
LiveData 天然生成支持粘性事情,google 规划LiveData 并不是为了粘性而规划,但却有粘性的效果。
LiveData 撤销粘性事情
LiveData支持粘性事情的原因是 observer version 与 LiveData 的version没有保持一致性,Observer 每次的初始值为-1,这样由于
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
只要咱们重写Observer,让它的Version和LiveData的version保持一致,将不会把把历史数据回调新的注册者,也就撤销了粘性事情,从头界说WrapperObserver类:
/**
* Observer 包装类
* 经过改变mLastVersion的值就能做到非粘性事情
*
*/
class WrapperObserver<T>(
var liveData: NoStickyLiveData<T>,
var observer: Observer<in T>,
sticky: Boolean, observerForever: Boolean = false
) : Observer<T> {
private val TAG = "WrapperObserver"
//符号该liveData已经发射几回数据了,用以过滤老数据重复接纳
private var mLastVersion = if (sticky) {
-1
} else {
liveData.getVersion()
}
override fun onChanged(t: T) {
if (mLastVersion >= liveData.getVersion()) {
return
}
mLastVersion = liveData.getVersion()
observer?.onChanged(t)
}
}
自界说LiveData:
class NoStickyLiveData<T>(
private val eventName: String = "default",
private val map: ConcurrentHashMap<String, NoStickyLiveData<T>>? = null,
private val sticky: Boolean = false
) : MutableLiveData<T>() {
private val TAG = "StickyLiveData"
private var mVersion = 0
/**
* 记录 绑定的Observer
*/
private val mHashMap = ConcurrentHashMap<String, Observer<*>>()
fun getVersion(): Int {
return mVersion
}
override fun setValue(value: T) {
mVersion++
super.setValue(value)
}
override fun postValue(value: T) {
mVersion++
super.postValue(value)
}
override fun observeForever(observer: Observer<in T>) {
val observerExit = mHashMap[eventName]
if (observerExit != null) {
removeObserver(observerExit as Observer<in T>)
}
val wrapperObserver = WrapperObserver(this, observer, sticky, true)
mHashMap[eventName] = wrapperObserver
super.observeForever(wrapperObserver)
}
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
observerSticky(owner, observer, sticky)
}
private fun observerSticky(owner: LifecycleOwner, observer: Observer<in T>, sticky: Boolean) {
super.observe(owner, WrapperObserver(this, observer, sticky))
owner.lifecycle.addObserver(LifecycleEventObserver { source, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
map.let {
if (!sticky) {
it?.remove(eventName)
}
}
}
})
}
private fun observerSticky(observer: Observer<in T>, sticky: Boolean) {
super.observeForever(WrapperObserver(this, observer, sticky))
}
}
监听:
editViewModel.inputDataNoSticky.observe(this, Observer {
it.let {
tv?.text = it
}
})
效果如下图:
LiveData定制事情总线
LiveData强大的事情分发才能,能够依据LiveData来做一个事情总线,用来全局分发事情。 并且支持粘性事情和非粘性事情两种方法。 发送事情:
LiveDataBus.withSticky<String>("edit").setValue("********")
监听:
LiveDataBus.withSticky<String>("edit").observe(this, Observer {
it.let {
tv?.text = it
}
})
LiveDataBus 源码:
/**
* 消息总线
* 跨 activity
*/
object LiveDataBus {
private val mHashMap = ConcurrentHashMap<String, NoStickyLiveData<*>>()
/**
* 不带粘性事情
*/
fun <T> with(eventName: String): NoStickyLiveData<T> {
var liveData = mHashMap[eventName]
if (liveData == null) {
liveData =
NoStickyLiveData(
eventName,
mHashMap as ConcurrentHashMap<String, NoStickyLiveData<T>>
)
mHashMap[eventName] = liveData
}
return liveData as NoStickyLiveData<T>
}
/**
* 带粘性事情的
*/
fun <T> withSticky(eventName: String): NoStickyLiveData<T> {
var liveData = mHashMap[eventName]
if (liveData == null) {
liveData =
NoStickyLiveData(
eventName,
mHashMap as ConcurrentHashMap<String, NoStickyLiveData<T>>,
true
)
mHashMap[eventName] = liveData
}
return liveData as NoStickyLiveData<T>
}
}
LiveDataBus 粘性事情:
LiveDataBus 非粘性事情:
总结
ViewModel和LiveData是JetPack中重量级组件,运用频率之高,熟练掌握必将大大简化咱们的开发使命。 源码:github.com/ThirdPrince…