理论
ViewModel + LiveData + DataBinding可以有效的将数据与UI组件分离,提高代码的可维护性和可读性
1.ViewModel使用要点
ViewModel是视图View和数据模型Model之间的沟通桥梁,借助ViewModel,视图 与 数据模型实现了解耦,同时还能保证视图 与 数据模型之间 保持通信。这样Activity的代码量减少了,只需要维护视图View相关内容,增加了代码的可维护性。
并且我们不需要再关心屏幕旋转导致数据丢失的问题,因为ViewModel的生命周期与Activity或Fragment的生命周期相互独立,ViewModel不会受到Activity组件销毁的影响。如果由于屏幕旋转导致的Activity销毁重建,与之绑定的ViewModel会在销毁的时候解绑,Activity重建时重新绑定。
ViewModel使用步骤:
- 首先,创建自定义ViewModel视图模型类,继承androidx.lifecycle.ViewModel类,该类就是要设置到视图(也就是xml)中的数据模型。
- 与DataBinding结合使用时,在DataBinding布局中设置的就是该视图模型类对象
- 该ViewModel类中,还使用了LiveData,可以实时监听数据改变,以更新UI组件
scala
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> number;
public MyViewModel() {
number = new MutableLiveData<>();
number.setValue(0);
}
public MutableLiveData<Integer> getNumber() {
return number;
}
}
然后在Activity中,获取视图模型:
- 创建ViewModelProvider对象,传入如下两个参数:
- ViewModelStoreOwner对象,就是本Activity组件
- ViewModelProvider.Factory对象,通过调用ViewModelProvider.AndroidViewModelFactory方法获取
- 调用ViewModelProvider的get方法,获取自定义ViewModel类
csharp
MyViewModel viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MyViewModel.class);
- 最后,将视图模型中的数据设置到视图组件中: 与DataBinding结合使用时,将ViewModel对象设置到DataBinding布局中
2.LiveData使用要点
LiveData是一个可被观察的数据容器类,它可以包含任何类型的数据。它将数据包装起来,使数据成为观察者,当数据发生变化时,观察者能够获得通知。
LiveData是基于ViewModel的,是对ViewModel数据维护的一个补充:
在Activity中使用代码可以将ViewModel初始数据 设置给 视图组件,进行 初始状态显示,如果 在运行过程中,ViewModel中的数据发生了改变,如何将变化应用到视图组件中,在视图中显示最新的数据内容,此时就用到了LiveData组件
在ViewModel的基础上,通过引入LiveData,可以将 运行过程中ViewModel中的Model模型数据改变 通知 视图View,让视图组件显示最新的数据内容
在ViewModel中使用了LiveData后,必须调用LiveData的observer方法为LiveData设置androidx.lifecycle.Observer监听器,如果监听到了LiveData数据变化,直接回调监听器的 Observer监听器的onChanged方法,在该方法中执行更新视图的操作
LiveData使用:
- 1.首先,在自定义ViewModel类中,定义MutableLiveData成员:
-
- 然后,在DataBinding布局中,设置该自定义ViewModel类型实例对象作为绑定的数据
- 3.最后,在Activity组件中 获取DataBinding布局对应的ActivityMainBinding实例对象,为Activity设置布局文件 以及 设置LiveData在DataBinding中观察者生命周期所有者
在最后调用的activityMainBinding.setLifecycleOwner()方法,设置LiveData在DataBinding布局中的观察者的生命周期所有者
LiveData如果要生效,需要为其设置 androidx.lifecycle.Observer观察者,如果监听到了LiveData数据变化,直接回调监听器的 onChanged函数
DataBinding布局生成对应的ViewDataBinding类,调用 activityMainBinding.setLifecycleOwner()方法,传入的LifecycleOwner实例对象,该对象就算LiveData的观察者,如果不设置,LiveData发生数据改变后,则不会通知UI组件进行数据更新
Activity继承了AppCompatActivity,最底层的ComponentActivity实现了LifecycleOwner接口,因此可以将Activity作为LifecycleOwner设置给ViewDataBinding数据绑定类
3.DataBinding使用要点
DataBinding的主要作用就是 绑定下面两个元素:
-
数据模型model/视图模型viewModel
-
视图View DataBinding中除了绑定数据模型Model之外,还可以直接绑定视图模型ViewModel,这是DataBinding+ViewModel组合用法。
-
如果ViewModel中使用了LiveData变量,则变成了DataBinding+ViewModel+LiveData组合用法
使用步骤:
- 将普通布局转换为DataBinding布局文件
- 使用 < data > 标签配置数据模型对象
- 加载数据绑定布局 获取数据模型 设置数据模型对象 设置LiveData在DataBinding中观察者生命周期所有者
实践
1.ViewModel + LiveData代码
定义ViewModel视图模型类,该类继承了 androidx.lifecycle.ViewModel类
在该自定义ViewModel类中,定义了MutableLiveData成员,这是LiveData实现,用于在运行过程中,一旦ViewModel数据发生改变,就通知View视图组件,更新数据显示。
LiveData生效 需要为MutableLiveData设置androidx.lifecycle.Observer监听器,当数据发生改变时,就会回调监听器中的androidx.lifecycle.Observer的onChanged回调函数
typescript
public class MainViewModel extends ViewModel {
private MutableLiveData<Integer> number;
public MainViewModel() {
number = new MutableLiveData<>();
number.setValue(0);
}
public MutableLiveData<Integer> getNumber() {
return number;
}
public void setNumber(MutableLiveData<Integer> number) {
this.number = number;
}
public void plus() {
number.setValue(number.getValue() + 1);
}
public void minus() {
number.setValue(number.getValue() - 1);
}
public void reset() {
number.setValue(0);
}
}
2.DataBinding代码
DataBinding布局文件代码:
ini
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewmodel"
type="com.wzj.databindingdemo.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewmodel.number}"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->viewmodel.plus()}"
android:text="+1"
app:layout_constraintRight_toLeftOf="@id/btn_minus"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView" />
<Button
android:id="@+id/btn_minus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->viewmodel.minus()}"
android:text="-1"
app:layout_constraintLeft_toRightOf="@id/btn_plus"
app:layout_constraintRight_toLeftOf="@id/btn_reset"
app:layout_constraintTop_toBottomOf="@id/textView" />
<Button
android:id="@+id/btn_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{()->viewmodel.reset()}"
android:text="reset"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toRightOf="@id/btn_minus"
app:layout_constraintTop_toBottomOf="@id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
3.Activity代码
在Activity中,需要完成三个任务:
- 加载DataBinding布局,需要获取DataBinding布局对应的ViewDataBinding类,
- 为DataBinding布局配置ViewModel实例对象,先获取ViewModel实例,然后设置给DataBinding布局
- 设置LiveData观察者,在ViewDataBinding类中,可以直接调用ViewDataBinding的setLifecycleOwner函数将本Activity组件设置为LiveData的观察者即可
scala
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
MainViewModel viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MainViewModel.class);
activityMainBinding.setViewmodel(viewModel);
//设置LiveData在DataBinding中观察者生命周期所有者
activityMainBinding.setLifecycleOwner(this);
}
}
执行结果: