Android MVVM-编程思想2(入门实战MVVM,DataBinding,ViewModel,LiveData)

Posted 0 and 1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MVVM-编程思想2(入门实战MVVM,DataBinding,ViewModel,LiveData)相关的知识,希望对你有一定的参考价值。

前言

通过一个小案例,帮助大家了解MVVM。最终实现一个MVVM通用框架。代码:github。(如有错误之处,请在评论区指出,谢谢。如果感觉写的不错,请点赞,关注,谢谢。)

上一个小节,只是理论介绍了MVVM,DataBinding,ViewModel,LiveData,这一小节,讲解一下他们的使用方式。如果已经对这些基础知识很了解,可以直接看下一节。

目录:

Android MVVM-编程思想1(入门介绍MVVM,DataBinding,ViewModel,LiveData)
Android MVVM-编程思想2(入门实战MVVM,DataBinding,ViewModel,LiveData)
Android MVVM-编程思想3(封装基类BaseMvvmActivity,BaseMvvmFragment)

DataBinding 使用

首先开启app模块的gradle配置文件android 节点下开启

 dataBinding 
        enabled true
    
(1)最简单的使用JDK定义好的类型
xml直接使用
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="title"
            type="String" />
    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="@color/colorAccent"
            android:gravity="center"
            android:text="@=title"
            android:textColor="#ffffff"
            android:textSize="18sp" />
    </LinearLayout>
</layout>

UserActivity 中使用,DataBindingUtil.setContentView(this, R.layout.activity_user),AndroidStudio 构建之后会自动根据XML中的配置生成绑定关系。并返回管理类ActivityUserBinding

  ActivityUserBinding binding = DataBindingUtil.setContentView(this, 	R.layout.activity_user);
  binding.setTitle("DataBinding绑定演示");
(2)如何使用自定义的类?

定义一个类User
普通的类,跟JDK内部的类一样,只是残疾版的绑定,什么意思? Model中的数据可以显示到View上。Model 的数据变动不会实时变化到View上。如何实现数据驱动,如何实现双向绑定?,继续看,后面会讲

User类
public class User 
    private String name;

    private String sex;
    private int age;

    public User(String name, String sex, int age) 
        this.name = name;
        this.sex = sex;
        this.age = age;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    @Bindable
    public String getSex() 
        return sex;
    

    public void setSex(String sex) 
        this.sex = sex;
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        this.age = age;
    

XML中使用
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="title"
            type="String" />

        <variable
            name="user"
            type="chongchong.wei.mvvm_aac.base.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:background="@color/colorAccent"
            android:gravity="center"
            android:text="@=title"
            android:textColor="#ffffff"
            android:textSize="18sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text='@"名称:"+user.name'
            android:textSize="18sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text="@user.name"
            android:textSize="18sp" />

        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@=user.name" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="center"
            android:text='@""+user.age'
            android:textSize="18sp" />

        <Button
            android:id="@+id/mButton"
            android:layout_width="100dp"
            android:layout_height="40dp"
            android:text="模拟请求网络" />
    </LinearLayout>
</layout>

UserActivity类
public class UserActivity extends AppCompatActivity 
    ActivityUserBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
        binding.setTitle("DataBinding绑定演示");
        binding.setUser(new User("小明", "男", 16));

        binding.mButton.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                requestHttp();
            
        );
    

    /**
     * 模拟请求网络刷新数据
     */
    private void requestHttp() 
        binding.getUser().setName("改变Name");//User没有继承BaseObservable ,View不会变化
    

(3)实现User数据变化,View自动更改,加上注解@Bindable,set方法手动更新notifyPropertyChanged

实现数据变化自动驱动 UI 刷新的方式有三种:BaseObservable、ObservableField、ObservableCollection

BaseObservable 提供了 notifyChange() 和 notifyPropertyChanged() 两个方法,前者会刷新所有的值域,后者则只更新对应 BR 的 flag,该 BR 的生成通过注释 @Bindable 生成,可以通过 BR notify 特定属性关联的视图
下面学习一下第一种方式:

User类
public class User extends BaseObservable 
    @Bindable
    private String name;
    @Bindable
    private String sex;
    @Bindable
    private int age;

    public User(String name, String sex, int age) 
        this.name = name;
        this.sex = sex;
        this.age = age;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
        notifyPropertyChanged(chongchong.wei.mvvm_aac.BR.name);
    


    public String getSex() 
        return sex;
    

    public void setSex(String sex) 
        this.sex = sex;
        notifyPropertyChanged(chongchong.wei.mvvm_aac.BR.sex);
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        this.age = age;
        notifyPropertyChanged(chongchong.wei.mvvm_aac.BR.age);
    


双向数据绑定如何实现?

双向绑定的意思即为当数据改变时同时使视图刷新,而视图改变时也可以同时改变数据
需求:界面上有两个控件,EditText 用于获取用户输入,TextView 用于把用户输入展示出来,绑定变量的方式比单向绑定多了一个等号:@=user.name

 <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@=user.name" />

这里只是简单介绍DataBinding 的作用和使用方式。还有很多其他场景的使用方式,大家去官网自己查看吧。本系列的目的是搭建MVVM框架,所以就不在这上面讲解过多了。

ViewModel使用

ViewModel 其实就是MVVM中的VM 层 ,一般和LiveData 一起使用,根据官方介绍,VeiwModel是具有生命周期感知的。验证一下
UserVM

public class UserVM extends ViewModel 
    @Override
    protected void onCleared() 
        super.onCleared();
        Log.i("weicc_mvvm_", "onCleared");
    

UserActivity中使用
public class UserActivity extends AppCompatActivity 
    ActivityUserBinding binding;
    UserVM userVM;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
        binding.setTitle("DataBinding绑定演示");
        userVM = ViewModelProviders.of(this).get(UserVM.class);
        binding.setUserVM(userVM);
        Log.i("weicc_mvvm_", "onCreate_hashcode:" + ViewModelProviders.of(this).get(UserVM.class).hashCode());
    

    @Override
    protected void onStart() 
        super.onStart();
        Log.i("weicc_mvvm_", "onStart_hashcode:" + ViewModelProviders.of(this).get(UserVM.class).hashCode());
    

    @Override
    protected void onResume() 
        super.onResume();
        Log.i("weicc_mvvm_", "onResume_hashcode:" + ViewModelProviders.of(this).get(UserVM.class).hashCode());
    

    @Override
    protected void onPause() 
        super.onPause();
        Log.i("weicc_mvvm_", "onPause_hashcode:" + ViewModelProviders.of(this).get(UserVM.class).hashCode());
    

    @Override
    protected void onStop() 
        super.onStop();
        Log.i("weicc_mvvm_", "onStop_hashcode:" + ViewModelProviders.of(this).get(UserVM.class).hashCode());
    

    @Override
    protected void onDestroy() 
        super.onDestroy();
        Log.i("weicc_mvvm_", "onDestroy_hashcode:" + ViewModelProviders.of(this).get(UserVM.class).hashCode());
    

    @Override
    public void onConfigurationChanged(Configuration newConfig) 
        super.onConfigurationChanged(newConfig);
        Log.i("weicc_mvvm_", "onConfigurationChanged_hashcode:" + ViewModelProviders.of(this).get(UserVM.class).hashCode());
    

启动运行,然后旋转屏幕–》点击back销毁。可以看出旋转屏幕不会重建ViewModel。
打印:

2019-12-20 15:59:43.502 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onCreate_hashcode:86643892
2019-12-20 15:59:43.503 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onStart_hashcode:86643892
2019-12-20 15:59:43.506 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onResume_hashcode:86643892
2019-12-20 15:59:49.704 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onConfigurationChanged_hashcode:86643892
2019-12-20 15:59:49.707 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onPause_hashcode:86643892
2019-12-20 15:59:49.718 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onStop_hashcode:86643892
2019-12-20 15:59:49.719 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onDestroy_hashcode:86643892
2019-12-20 15:59:49.764 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onCreate_hashcode:86643892
2019-12-20 15:59:49.766 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onStart_hashcode:86643892
2019-12-20 15:59:49.771 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onResume_hashcode:86643892
2019-12-20 15:59:53.086 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onPause_hashcode:86643892
2019-12-20 15:59:53.299 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onStop_hashcode:86643892
2019-12-20 15:59:53.302 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onCleared
2019-12-20 15:59:53.302 11594-11594/chongchong.wei.mvvm_aac I/weicc_mvvm_: onDestroy_hashcode:231874846

LiveData 使用

UserActivity代码
public class UserActivity extends AppCompatActivity 
    ActivityUserBinding binding;

    MutableLiveData<User> mutableLiveData;
    User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        Log.i("weicc_mvvm_", "onCreate");
        setContentView(R.layout.activity_user);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
        binding.setTitle("DataBinding绑定演示");
        user = new User();
        user.setName("小明");
        user.setAge(12);
        user.setSex("男");
        mutableLiveData = new MutableLiveData();
        mutableLiveData.setValue(user);
        mutableLiveData.observe(this, new Observer<User>() 
            @Override
            public void onChanged(User user) 
                binding.setUser(user);//user没有继承BaseObservable 需要手动刷新数据到界面
                Log.i("weicc_mvvm_", "监听user改变:" + user.toString());
            
        );
        binding.mButton.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                requestHttp();
            
        );
    

    /**
     * 模拟请求网络刷新数据
     */
    private void requestHttp() 
        Log.i("weicc_mvvm_", "点击button的时候改变name");
        user.setName("改变name");
        mutableLiveData.postValue(user);

    

    @Override
    protected void onStop() 
        super.onStop();
        Log.i("weicc_mvvm_", "onStop的时候改变name");
        user.setName("改变name");
        mutableLiveData.postValue(user);
    


日志分析:LiveData onStop的数据改变不会推送,所以并不会监听到,正如LiveData官方说明的一样,是具有生命周期感知的观察者。
优势:1,当Activity不在屏幕上时(不可见),LiveData不会出发没必要的界面更新;2,当Activity被销毁时,LiveData将自动清空与Observer的连接

2019-12-20 16:46:42.312 22352-22352/chongchong.wei.mvvm_aac IAndroid MVVM-编程思想1(入门介绍MVVM,DataBinding,ViewModel,LiveData)

Android MVVM-编程思想1(入门介绍MVVM,DataBinding,ViewModel,LiveData)

《Android构建MVVM》系列 之 MVVM架构快速入门

Android MVVM-编程思想3(封装基类BaseMvvmActivity,BaseMvvmFragment)

Android MVVM-编程思想3(封装基类BaseMvvmActivity,BaseMvvmFragment)

Android MVP-编程思想1(什么是MVC-MVP-MVVM模式?)