MVVM怎么进行基本使用
这里只说拿着别人的mvvm怎么快速让自己进入开发状态,mvvm怎么搭建后面会详细说明,现在这个demo的架构里面可能有些没用的东西,不过也能拿着用,后面会把这套好好整理下再对每个点详细的进行说明(demo的github地址在文章末尾)。另外,
xml文件
注意点
①最外层的父布局必须是layout ,且这个父布局不能设置长宽属性,否则会膨胀
②data标签内的variable需要加这两个属性:
name:就是名字,任意写,作用是为了在Activity里作为标识给Activity绑定viewmodel
type:对应viewmodel的全路径,匹配好viewmodel之后,系统会自动生成这个xml文件的databinding
③data标签下面就是真正的布局,跟以往一样。
<layout xmlns:android="http://schemas.android.com/apk/res/android"
android:fitsSystemWindows="true"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.sz.mangosteeneg.ui.viewmodel.TestMvvmViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
。。。。。。
使用viewmodel简单的设置文本点击事件等
以TextView为例,
①text属性为android:text="@{viewModel.txt}"
viewmodel为data标签中name属性内容,调用了viewmodel类中的txt对象,viewmodel类中的写法在下面会介绍
②点击事件的xml设置android:onClick="@{viewModel.click}"
click为viewmodel中的方法。就是在xml文件中设置点击事件,只不过引用到了viewmodel中。
<TextView
android:id="@+id/tv_t"
android:onClick="@{viewModel.click}"
android:text="@{viewModel.txt}"
android:textSize="20sp"
android:textColor="#333333"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:layout_height="40dp"/>
示例xml的全部代码
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
android:fitsSystemWindows="true"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.sz.mangosteeneg.ui.viewmodel.TestMvvmViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rl"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toTopOf="@+id/tv_t"
android:layout_width="match_parent"
android:layout_height="0dp"/>
<TextView
android:id="@+id/tv_t"
android:onClick="@{viewModel.click}"
android:text="@{viewModel.name}"
android:textSize="20sp"
android:textColor="#333333"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:layout_height="40dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
viewmodel
*继承项目中的ViewModel的父类
viewmodel一般只进行数据的数理,除了处理数据别的最好啥都别干(当然,要是你对viewmodel了解非常深当我没说)。也最好不要吧对应Activity的对象(上下文)给塞过来。会造成内存泄漏
点击事件及文本改变
①文本改变
在viewmodel中声明一个容器对象,然后xml中设置好
//文本内容
public ObservableField<String> txt = new ObservableField<>();
一般是在网络请求完成之后设置数据,调用set方法即可:txt.set(“…”);
//假装自己是个网络请求
public void reqJiade(){
List<String> list = new ArrayList<>();
for(int i=0;i<200;i++){
list.add("扫地欧尼"+i);
}
liveString.setValue(list);
txt.set("文本改变");
}
②点击事件,xml中用viewmodel调用这个方法即可,注意不用带()
//文本的点击事件
public void click(View view){
ToastUtils.showShort("文本被点击");
}
livedata监听数据
livedata本质上是观察者模式。被观察者是数据的获取这个动作,并将获到的数据对象传递给观察者。
①声明数据要传递数据的类型的livedata,注意用public因为Activity还要用
public MutableLiveData<CityAreasBean> liveAddress = new MutableLiveData<>();
public MutableLiveData<List<String>> liveString = new MutableLiveData<>();
②数据请求成功之后使用对应的livedata对象调用setValue()方法储存数据,也是注意用public(这里用一个假的网络请求代替下)
//假装自己是个网络请求
public void reqJiade(){
List<String> list = new ArrayList<>();
for(int i=0;i<200;i++){
list.add("扫地欧尼"+i);
}
//请求成功后再调用set方法
liveString.setValue(list);
txt.set("文本改变");
}
③Activity调用viewmodel中的请求网络的方法,并设置好对应livedata的监听。下文的Activity中详细说明
完整的ViewModel类代码
public class TestMvvmViewModel extends BaseAppViewModel {
public MutableLiveData<CityAreasBean> liveAddress = new MutableLiveData<>();
public MutableLiveData<List<String>> liveString = new MutableLiveData<>();
//文本内容
public ObservableField<String> txt = new ObservableField<>();
//获取地址数据
public void reqAddress(){
sendHttp(getRetrofitClient().getcityaddress(), new BaseObserver<CityAreasBean>() {
@Override
protected void onSuccess(CityAreasBean o) {
if(o.isSuccess()){
liveAddress.setValue(o);
}else {
ToastUtils.showShort(o.getResultMsg());
}
}
});
}
//假装自己是个网络请求
public void reqJiade(){
List<String> list = new ArrayList<>();
for(int i=0;i<200;i++){
list.add("扫地欧尼"+i);
}
//请求成功后调用set方法
liveString.setValue(list);
txt.set("文本改变");
}
//文本的点击事件
public void click(View view){
ToastUtils.showShort("文本被点击");
}
public TestMvvmViewModel(@NonNull Application application) {
super(application);
}
}
activity类
绑定databinding和viewmodel
①绑定xml对应的databinding和viewmodel,我这里是使用的泛型,根据自己项目中的形式来就行。(databinding是根据xml文件名生成的,例如我的xml是:activity_test,对应的databinding就是ActivityTestBinding)
public class TestMvvmActivity extends AppBaseActivity<ActivityTestBinding, TestMvvmViewModel>
②同步Activity和viewmodel的生命周期,一般都是封装到基类里的,这里根据封装方式调用即可。也是跟着自己项目中的形式来
@Override
public int initVariableId() {
return BR.viewModel;
}
③创建Databinding和viewmodel对象,我这里是用的两个方法。别人项目中多是直接创建对象的方式
//获取databinding和viewmodel的两个方法
public ActivityTestBinding getBinding(){
return (ActivityTestBinding) binding;
}
public TestMvvmViewModel getVM(){
return (TestMvvmViewModel)viewModel;
}
④别的内容就跟mvc,mvp写法一样了。不过mvvm中获取控件对象可以不用findbyid或者eventbus。用databinding对象去调控件id即可(eg:我的TextView的id为:tv_t,我调用这个控件:getBinding().tvT)
⑤这个activity中就写了个Recyclerview列表。以下是完整的Activity代码
完整的Activity代码
public class TestMvvmActivity extends AppBaseActivity<ActivityTestBinding, TestMvvmViewModel> {
@Override
public int initContentView(Bundle savedInstanceState) {
return R.layout.activity_test;
}
//数据源,适配器
private AddressAdapter addressAdapter;
private List<String> list = new ArrayList<>();
@Override
public void initData() {
super.initData();
showFullScreen(true);
//初始化
first();
//监听
monitor();
//请求网络
// getVM().reqAddress();
getVM().reqJiade();
}
private void first(){
getBinding().rl.setLayoutManager(new LinearLayoutManager(this));
addressAdapter = new AddressAdapter(R.layout.item_txt_center,list);
getBinding().rl.setAdapter(addressAdapter);
if(getBinding().rl.getItemDecorationCount() == 0){
getBinding().rl.addItemDecoration(new MyDecoration());
}
//空布局
View view = View.inflate(this,R.layout.no_layout,null);
addressAdapter.setEmptyView(view);
}
private void monitor(){
//监听网络请求的结果(接口地址我删了,请求不出来)
getVM().liveAddress.observe(this,res -> {
// setRecyclerView(res);
});
//假装的网络请求
getVM().liveString.observe(this,list1 -> {
setRecyclerView(list1);
});
}
//设置列表
private void setRecyclerView(List<String> list){
addressAdapter.setNewData(list);
}
//获取databinding和viewmodel的两个方法
public ActivityTestBinding getBinding(){
return (ActivityTestBinding) binding;
}
public TestMvvmViewModel getVM(){
return (TestMvvmViewModel)viewModel;
}
@Override
public int initVariableId() {
return BR.viewModel;
}
//recyclerview工具类
class MyDecoration extends RecyclerView.ItemDecoration{
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0,10,0,10);
}
}
}
引用文本
链接: 代码demo.