------《Jetpack之LiveData加ViewModle结合使用》
一、LiveData介绍:
????????首先来句简单的:观察监听了数据的变化,方便了很多通知操作。 ????????LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
二、LiveData优点
确保界面符合数据状态 ????????LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。 不会发生内存泄漏 ????????观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。 不会因 Activity 停止而导致崩溃 ????????如果观察者的生命周期处于非活跃状态(如返回堆栈中的 activity),它便不会接收任何 LiveData 事件。 不再需要手动处理生命周期 ????????界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。 数据始终保持最新状态 ????????如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。 适当的配置更改 ????????如果由于配置更改(如设备旋转)而重新创建了 activity 或 fragment,它会立即接收最新的可用数据。 共享资源 ????????您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。
三、直接代码举例说明,看看怎么用
1、简单的监听操作:
????????通过点击屏幕按钮,改变后端ViewModel数据。通过LiveData监听数据更新UI LiveDataView数据类
class LiveDataModel:ViewModel() {
val currentNum: MutableLiveData<Int> by lazy {
MutableLiveData<Int>(0)
}
val age: MutableLiveData<Int> by lazy {
MutableLiveData<Int>(1)
}
}
live_data_activity.xml布局页面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="@+id/imageButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="upOnclick"
app:srcCompat="@drawable/ic_baseline_thumb_up_50" />
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="30dp"
android:text="0000"
android:background="@color/white"/>
<ImageButton
android:id="@+id/imageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="upDown"
app:srcCompat="@drawable/ic_baseline_thumb_down_50" />
</LinearLayout>
LiveDataModelActivity
class LiveDataModelActivity : AppCompatActivity() {
private val viewModel: LiveDataModel by viewModels()
private lateinit var viewBindingData: LiveDataActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBindingData = LiveDataActivityBinding.inflate(layoutInflater)
setContentView(viewBindingData.root)
viewBindingData.textView.text = viewModel.currentNum.value.toString()
viewModel.currentNum.observe(this, Observer {
viewBindingData.textView.text = it.toString()
})
}
fun upOnclick(view: View) {
viewModel.currentNum.postValue(viewModel.currentNum.value?.plus(1))
}
fun upDown(view: View) {
viewModel.currentNum.postValue(viewModel.currentNum.value?.minus(1))
}
}
效果
2、两个Fragment共同监听到数据的变化减少Fragment通信:
????????两个Fragment界面都有一个seekBar通过LiveData监听。当拉动其中一个Fragment中seekBar,另一个Fragment中seekBar也跟着改变。 LiveDataModel
class LiveDataModel:ViewModel() {
val currentNum: MutableLiveData<Int> by lazy {
MutableLiveData<Int>(0)
}
val age: MutableLiveData<Int> by lazy {
MutableLiveData<Int>(1)
}
}
LiveDataModelFragment(第一个Fragment)
class LiveDataModelFragment : Fragment() {
companion object {
fun newInstance() = LiveDataModelFragment()
}
private lateinit var viewBindingData: FragmentLiveDataModelBinding
private val viewModel: LiveDataModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewBindingData = FragmentLiveDataModelBinding.inflate(inflater, container, false)
viewModel.currentNum.observe(viewLifecycleOwner, Observer {
viewBindingData.seekBar1.progress = it
})
viewBindingData.seekBar1.setOnSeekBarChangeListener(object : OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
viewModel.currentNum.value = progress
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
return viewBindingData.root
}
}
????????注意:setValue只可以在主线程中调用。postValue可以在主线程或者子线程中调用,数据会从子线程派送到主线程更新, ????????如果调用多次postValue更新数据,则在主线程执行更新前,LiveData的value只会保存最后一次的post值。 fragment_live_data_model.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SeekBar
android:id="@+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
LiveDataModel2Fragment(第二个Fragment)
class LiveDataModel2Fragment : Fragment() {
companion object {
fun newInstance() = LiveDataModel2Fragment()
}
private val viewModel: LiveDataModel by activityViewModels()
private lateinit var viewBinding : FragmentLiveDataModel2Binding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewBinding = FragmentLiveDataModel2Binding.inflate(inflater, container, false)
viewModel.currentNum.observe(viewLifecycleOwner, Observer {
viewBinding.seekBar2.progress = it
})
viewBinding.seekBar2.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
viewModel.currentNum.value = progress
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
return viewBinding.root
}
}
fragment_live_data_model2.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SeekBar
android:id="@+id/seekBar2"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
LiveDataModelActivity2
class LiveDataModelActivity2: AppCompatActivity(){
private lateinit var viewBinding: LiveDataModelActivity2Binding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = LiveDataModelActivity2Binding.inflate(layoutInflater)
setContentView(viewBinding.root)
}
}
live_data_model_activity2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment1"
android:name="LiveDataModelFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment2"
android:name="LiveDataModel2Fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
四、结尾:
????????通常情况下LiveData都是配合viewModel使用,在某个具体的ViewModel类中定义LiveData数据,然后在对应的Activity或Fragment中观察LiveData数据的变化,LiveData的使用使得我们不再将数据保存在Activity或Fragment中,减轻了Activity或Fragment的工作量,使得Activity或Fragment只负责界面的管理和显示,而不在保存数据也不会受到数据的影响。 ????????下一篇文章讲介绍:ViewModel + LiveData + DataBinding的结合使用
|