Android jetpack 之LiveData 结合ViewModel的简单使用
前言
LiveData是一个可以被观察的数据持有类,它可以感知并遵循Activity、Fragment或Service等组件的生命周期。
其中主要包含的方法有:setValue、postValue以及observe;
- setValue:更新数据必须在主线程
- postValue:更新数据可以在子线程完成
- observe:是liveData的监听数据回调
一、使用步骤
1.引入库
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
2.创建LiveData
实例化唯一实现了LiveData的MutableLivaData。
val liveData = MutableLiveData<T>()
3.赋值LiveData
liveData.setValue(T) //只能在主线程中进行赋值操作
或
liveData.postValue(T) //可在主线程也可以在子线程
4.观察LiveData事件
livedata.observe(this ) {
//监听数据有变化时会调用observe
}
二、实战示例
使用liveData与ViewModel结合使用,在Act中刚改数据在Fragmen中更新数据
1、创建一个ViewModel中包含LiveData
class LiveDataViewModel : ViewModel() {
val TAG = "LiveDataViewModel"
private val liveData = MutableLiveData<Int>()
fun addV(num:Int) {
liveData.postValue(num)
}
fun getLV(): MutableLiveData<Int> {
return liveData
}
}
2、在Act中操作VM中的LiveData
class LiveDataActivity : AppCompatActivity() {
// 实例化VM
val mVm by lazy { ViewModelProvider(this)[LiveDataViewModel::class.java] }
val tv: TextView by lazy { findViewById(R.id.testViewModelText) }
val numAct by lazy { MutableLiveData<Int>() }
var n=0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewmodel)
if (savedInstanceState == null) {
// 加载Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.container, LiveDataFragment.newInstance())
.commitNow()
}
tv.text = "获取的数据LVVM:${mVm.getLV().value} ___ ActLive:${numAct.value} __ act_num:${n}"
findViewById<Button>(R.id.testViewModelAdd).setOnClickListener {
n++
// 修改VM中的LiveData数据
numAct.value=n
mVm.addV(numAct.value?:0)
}
// 监听数据变化后更新操作
mVm.getLV().observe(
this
) {
tv.text = "Act-获取的数据:${it} ___ ActLive:${numAct.value} __ act_num:${n}"
}
findViewById<Button>(R.id.testViewModelGet).visibility = View.GONE
}
}
3、在Fragment中操作VM中的LiveData
class LiveDataFragment : Fragment() {
companion object {
fun newInstance() = LiveDataFragment()
}
//引入VM
private val viewModel: LiveDataViewModel by lazy {
ViewModelProvider(requireActivity())[LiveDataViewModel::class.java]
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_main, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.viewModelMessageGet).visibility=View.GONE
// 监听LiveData的数据
viewModel.getLV().observe(
requireActivity()
) {
view.findViewById<TextView>(R.id.viewModelMessage).text =
"LV——Fragment数据:${it}"
}
}
}
三、优点
- 避免内存泄漏:观察者被绑定到组件的生命周期上,当被绑定的组件销毁(destroy)时,观察者会立刻自动清理自身的数据。
- 实时数据刷新:当组件处于活跃状态或者从不活跃状态到活跃状态时总是能收到最新的数据。
四、LivaData数据倒罐
原因:ViewModel 将数据保留在内存中,这意味着开销要低于从磁盘或网络检索数据。ViewModel 与一个 Activity(或其他某个生命周期所有者)相关联,在配置更改期间保留在内存中,系统会自动将 ViewModel 与发生配置更改后产生的新 Activity 实例相关联。
操作:如、屏幕旋转
官网解释
解决方法
1、反射处理
1、利用反射修改observer.mLastVersion 的值,因为mLastVersion 初始的值为-1,当我们调用了其setValue或者postValue,其vesion会+1;对于每一个观察者的封装ObserverWrapper,其初始version也为-1,也就是说,每一个新注册的观察者,其version为-1;当LiveData设置这个ObserverWrapper的时候,如果LiveData的version大于ObserverWrapper的version,LiveData就会强制把当前value推送给Observer。
参考美团的处理方式
通过重写MutableLivaData
private class BusMutableLiveData<T> : MutableLiveData<T>() {
private val observerMap = HashMap<Observer<in T>, Observer<in T>>()
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
try {
hook(observer)
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun observeForever(observer: Observer<in T>) {
if (!observerMap.containsKey(observer)) {
observerMap[observer] = ObserverWrapper(observer)
}
super.observeForever(observerMap[observer])
}
override fun removeObserver(observer: Observer<in T>) {
val realObserver = if (observerMap.containsKey(observer)) {
observerMap.remove(observer)
} else {
observer
}
super.removeObserver(realObserver)
}
@Throws(Exception::class)
private fun hook(observer: Observer<in T>) {
//get wrapper's version
val classLiveData = LiveData::class.java
val fieldObservers: Field = classLiveData.getDeclaredField("mObservers")
fieldObservers.setAccessible(true)
val objectObservers: Any = fieldObservers.get(this)
val classObservers: Class<*> = objectObservers.javaClass
val methodGet = classObservers.getDeclaredMethod("get", Any::class.java)
methodGet.isAccessible = true
val objectWrapperEntry = methodGet.invoke(objectObservers, observer)
var objectWrapper: Any? = null
if (objectWrapperEntry is Map.Entry<*, *>) {
objectWrapper = objectWrapperEntry.value
}
if (objectWrapper == null) {
throw NullPointerException("Wrapper can not be bull!")
}
val classObserverWrapper: Class<*> = objectWrapper.javaClass.superclass
val fieldLastVersion: Field = classObserverWrapper.getDeclaredField("mLastVersion")
fieldLastVersion.setAccessible(true)
//get livedata's version
val fieldVersion: Field = classLiveData.getDeclaredField("mVersion")
fieldVersion.setAccessible(true)
val objectVersion: Any = fieldVersion.get(this)
//set wrapper's version
fieldLastVersion.set(objectWrapper, objectVersion)
}
}
2、使用第三方UnPeek-LivaData
implementation 'com.kunminx.arch:unpeek-livedata:7.8.0'
链接地址