Android 官方架构组件 ViewModel : 对状态的持有和维护

上周留下一篇文章,要给大家介绍一下ViewModel ,上篇  “Android 官方架构组件 LiveData:你想要的观察者模式”  说道LiveData 单独使用意义不大,和ViewModel 一起使用才能 “真香”,现在,就让我们认识一下ViewModel 吧。

ViewModel ,或者说MVVM(Model-View_ViewModel),这并非一个新鲜的词汇,它最早起源于前端,代表着数据驱动视图的思想,

它就好比是一个状态存储器,存储着UI 各种各样的状态,并对状态持有和维护。

说到MVVM就不得不提Google在2015年IO大会上提出的DataBinding库,它的发布直接促进了MVVM在Android领域的发展,开发者可以直接通过将数据状态通过 伪Java代码的形式绑定在xml布局文件中,从而将MVVM模式的开发流程形成一个 闭环



       
           
       
      

通过 伪Java代码 将UI的逻辑直接粗暴的添加进xml布局文件中达到和View的绑定,DataBinding这种实现方式引起了 强烈的争论。直至如今,依然有很多开发者无法接受DataBinding,这是完全可以理解的,因为它确实 很难定位语法的错误和运行时的崩溃原因

 

所以,现在来让我们重新认识一下ViewModel,

它主要有两个优点:

1.更便于保存数据

由系统响应用户交互或者重建组件,用户无法操控。当组件被销毁并重建后,原来组件相关的数据也会丢失——最简单的例子就是屏幕的旋转,如果数据类型比较简单,同时数据量也不大,可以通过onSaveInstanceState()存储数据,组件重建之后通过onCreate(),从中读取Bundle恢复数据。但如果是大量数据,不方便序列化及反序列化,则上述方法将不适用。

ViewModel的扩展类则会在这种情况下自动保留其数据,如果Activity被重新创建了,它会收到被之前相同ViewModel实例。当所属Activity终止后,框架调用ViewModelonCleared()方法释放对应资源:

给出一张图了解一下:

Android 官方架构组件 ViewModel : 对状态的持有和维护_第1张图片

这样看来,ViewModel是有一定的 作用域 的,它不会在指定的作用域内生成更多的实例,从而节省了更多关于 状态维护(数据的存储、序列化和反序列化)的代码。

ViewModel在对应的 作用域 内保持生命周期内的 局部单例,这就引发一个更好用的特性,那就是FragmentActivity等UI组件间的通信。

ok,给大家看一个例子:

首先,导入官方依赖:

compile 'android.arch.lifecycle:extensions:1.0.0'
package app.vp.cn.framework.bean;

import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;

/**
 * author : by
 * date: 2019/1/30 0030  下午 5:02.
 * describe UserModel  类  持有LiveData 用来保存数据 这是数据和状态的容器
 */

public class UserModel extends ViewModel {

    MutableLiveData userMutableLiveData = new MutableLiveData<>();

    public void setUser(User user) {
        userMutableLiveData.setValue(user);
    }

    public MutableLiveData getMutable() {
        return userMutableLiveData;
    }

    // 当MyActivity被销毁时,Framework会调用ViewModel的onCleared() 在此进行资源清理操作
    @Override
    protected void onCleared() {
        super.onCleared();

    }

}

在Activity 中,
package app.vp.cn.framework;

import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.LinearLayout;

import app.vp.cn.framework.bean.User;
import app.vp.cn.framework.bean.UserModel;
import app.vp.cn.framework.fragment.BottomFragment;
import app.vp.cn.framework.fragment.TopFragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.ll_ac)
    LinearLayout llAc;
    @BindView(R.id.bt_acMain)
    Button btAcMain;
    private UserModel userModel;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        TopFragment topFragment = new TopFragment();
        BottomFragment bottomFragment = new BottomFragment();
        getSupportFragmentManager().beginTransaction().replace(R.id.ll_ac, topFragment).commit();
        getSupportFragmentManager().beginTransaction().replace(R.id.ll_ac2, bottomFragment).commit();
         //通过这种方式获取ViewModel 的实例
        userModel = ViewModelProviders.of(this).get(UserModel.class);
        // userModel.getMutable().postValue(new User("我是MainActivity"));
    }

    @OnClick(R.id.bt_acMain)
    public void onViewClicked() {
        userModel.getMutable().postValue(new User("我是MainActivity"));
    }
}

在Fragment 中

package app.vp.cn.framework.fragment;

import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import app.vp.cn.framework.R;
import app.vp.cn.framework.bean.User;
import app.vp.cn.framework.bean.UserModel;

/**
 * author : by
 * date: 2019/1/31 0031  下午 3:15.
 * describe
 */

public class TopFragment extends Fragment {

    private TextView tvFragOne;
    private UserModel userModel;

    //这是一个回调在主线程的looper  ()  只是一个demo
    Handler mMainHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.frag_one, container, false);
        tvFragOne = view.findViewById(R.id.tv_fragOne);
        Button bt_fragOne = view.findViewById(R.id.bt_fragOne);
        //如果是在同一个Activity中进行传值,这里的第一个参数,必须是getActivity,不能是this
        userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);

        userModel.getMutable().observe(this, new Observer() {
            @Override
            public void onChanged(@Nullable User user) {
                tvFragOne.setText(user.getUserName());
            }
        });

        tvFragOne.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                userModel.getMutable().postValue(new User("小明"));
            }
        });

        bt_fragOne.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tvFragOne.setText("我是点击设置进来的值");
            }
        });

        return view;
    }
}

//这里我设置了两个值,一个是直接给textView 设置值,一个是使用ViewModel 保存的数据给textView 设置的值,可以发现,在屏幕翻转的过程中,直接给textView设置值的textView 已经没有了,而使用ViewModel 给TextView 设置的值依旧保存着

这样,就可以在Activity 中和附属在当前Activity 上的Fragment中进行通信,并且,他们持有的ViewModel 实例是同一个ViewModel 实例,在对应的作用域内,保证只生产出对应的唯一实例,多个Fragment维护相同的数据状态,极大减少了UI组件之间的数据传递的代码成本,赶快使用起来吧。

 

本片文章参考:https://www.jianshu.com/p/59adff59ed29

 

你可能感兴趣的:(Android,ViewModel,LiveData,MVVM)