浅谈MVVM架构(JectPack ViewModel + LiveData + DataBinding)

最近要新启动一个项目,准备使用MVVM架构搭建;在之前的文章中,提到过MVVM架构,在当前主流的框架中,渐渐的数据驱动UI、声明式UI(例如JetPack新出的Compose组件)会成为主流,在这里先谈一下MVVM架构的思路。

1 LiveData ViewModel DataBinding

以上3个组件是JectPack中的热门组件,也是MVVM的核心;LiveData具备感知数据变化的能力,可以动态更新UI数据;ViewModel有从始而终的生命周期,可感知App的生命周期;DataBinding实现数据与UI的绑定,真正实现了数据驱动UI。

在MVVM架构中,M代表数据层,主要负责数据的获取;V代表View层,主要就是XML布局以及Activity、Fragment;VM层就是ViewModel,用于存储UI的数据,承接View层和Model层的引用。

ViewModel层

public class MyViewModel extends ViewModel {

    //待监听的数据
    private MutableLiveData<User> allUser;
    //持有Model层的引用
    private Model model;

    public MyViewModel(){
        allUser = new MutableLiveData<>();
        model = new Model(this);
    }

    public void update(){
        if(allUser != null){

            //做耗时操作请求网络数据
            model.loadData();
//            allUser.setValue(user);
        }
    }

    public MutableLiveData<User> getUser(){

        return allUser;
    }
}

Model层

public class Model {
    
    //持有VM层的引用
    private MyViewModel viewModel;

    public Model(MyViewModel myViewModel){
        this.viewModel = myViewModel;

    }
    public void loadData(){
        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    Thread.sleep(2 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //等待2s获取数据
                User user = new User("你好","12345");
                //Cannot invoke setValue on a background thread
//                allUser.setValue(user);
                //post的区别
                viewModel.getUser().postValue(user);
            }
        }).start();
    }
}

View层

<?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="user"
            type="com.example.mvvmdemo.model.User" />
        <variable
            name="viewModel"
            type="com.example.mvvmdemo.viewmodel.MyViewModel"/>
        <variable
            name="onClick"
            type="android.view.View.OnClickListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewModel.user.username}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tv_pwd"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tv_name"
            android:text="@{viewModel.user.password}" />

        <Button
            android:id="@+id/btn_update"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tv_pwd"
            android:onClick="onClick"
            android:text="更新数据"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View层要用到的数据,在layout标签下用variable展示

//获取ViewModel层的实例
 viewModel = new ViewModelProvider(this).get(MyViewModel.class);
 //View层和ViewModel层绑定
 ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
 //设置ViewModel
 viewDataBinding.setViewModel(viewModel);
 viewDataBinding.setLifecycleOwner(this);
 //单击事件监听
 viewDataBinding.setOnClick(this::onClick);

在Activity中,需要通过ActivityMainBinding 将所需要的的数据绑定在一起,例如ViewModel、单击监听等。

2 MVVM架构设计

BaseModel:主要做一些公共的操作,或者初始化操作

public class BaseModel<VM extends BaseViewModel>{

    protected VM mViewModel;

    public BaseModel(VM mViewModel){

        this.mViewModel = mViewModel;
    }
}

BaseViewModel:持有Model层的引用

public abstract class BaseViewModel<M extends BaseModel,T extends LiveData> extends ViewModel {

    //在ViewModel层,需要持有Model层的引用
    protected M model;
    protected T data;

    public BaseViewModel(){
        model = getModelInstance();
        data = createLiveData();
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    protected abstract T createLiveData();

    protected abstract M getModelInstance();
}

BaseActivity

public abstract class BaseActivity<VM extends BaseViewModel,VDB extends ViewDataBinding>
        extends AppCompatActivity implements View.OnClickListener {

    protected VM mViewModel;

    protected VDB mViewDataBinding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(getLayoutId());
        this.mViewModel = getViewModelInstance();
//        new ViewModelProvider(this).get(mViewModel.getClass());
        this.mViewDataBinding = DataBindingUtil.setContentView(this,getLayoutId());
        //具体的绑定工作
        initBinding();
        initData();
    }

    protected abstract void initData();

    protected abstract void initBinding();

    protected abstract VM getViewModelInstance();

    protected abstract int getLayoutId();
}

各类的具体实现

public class MainActivity extends BaseActivity<UserViewModel,ActivityMainBinding> {

    @Override
    protected void initData() {

    }

    @Override
    protected void initBinding() {
        mViewDataBinding.setViewModel(mViewModel);
        mViewDataBinding.setLifecycleOwner(this);
        mViewDataBinding.setOnClick(this::onClick);
    }

    @Override
    protected UserViewModel getViewModelInstance() {
        return new UserViewModel();
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    public void onClick(View v) {
		//ViewModel执行获取数据的请求
        mViewModel.update();
    }
}
public class UserViewModel extends BaseViewModel<UserModel, MutableLiveData<User>> implements IContract.VM {


    @Override
    protected MutableLiveData<User> createLiveData() {
        return new MutableLiveData<>();
    }

    @Override
    protected UserModel getModelInstance() {
    	//实例化具体的Model类
        return new UserModel(this);
    }


    @Override
    public void update() {
        //通知Model层更新数据
        if(model != null){

            model.update();
        }

    }
}

public class UserModel extends BaseModel<UserViewModel> implements IContract.M {


    public UserModel(UserViewModel mViewModel) {
        super(mViewModel);
    }

    @Override
    public void update() {

        //耗时操作更新数据
        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    Thread.sleep(2 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //等待2s获取数据
                User user = new User("你好","12345");
                //Cannot invoke setValue on a background thread
//                allUser.setValue(user);
                //post的区别
                mViewModel.getData().postValue(user);
            }
        }).start();
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,下面是一个简单的示例: 首先,在build.gradle文件中添加以下依赖项: ```groovy // ViewModel and LiveData implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' // Data Binding implementation 'androidx.databinding:databinding-runtime:4.0.1' ``` 接下来,创建一个名为MainActivity的Activity,并在其布局文件中添加两个Fragment的占位符: activity_main.xml: ```xml <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"/> </layout> ``` MainActivity.java: ```java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); // 加载第一个Fragment getSupportFragmentManager().beginTransaction() .replace(R.id.container, new FirstFragment()) .commit(); } } ``` 接下来,创建一个名为FirstFragment的Fragment,并在其布局文件中使用DataBinding绑定数据: first_fragment.xml: ```xml <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.text}" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Next" android:onClick="@{viewModel::onNextClicked}" /> </LinearLayout> </layout> ``` FirstFragment.java: ```java public class FirstFragment extends Fragment { private FirstViewModel viewModel; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // 使用DataBinding绑定布局文件 FirstFragmentBinding binding = DataBindingUtil.inflate(inflater, R.layout.first_fragment, container, false); // 创建ViewModel实例 viewModel = ViewModelProviders.of(this).get(FirstViewModel.class); // 将ViewModel与布局文件中的变量绑定 binding.setViewModel(viewModel); // 设置LifecycleOwner,以便LiveData知道何时更新UI binding.setLifecycleOwner(this); return binding.getRoot(); } } ``` 下面是FirstViewModel.java: ```java public class FirstViewModel extends ViewModel { private MutableLiveData<String> textLiveData = new MutableLiveData<>(); public FirstViewModel() { // 初始化LiveData的默认值 textLiveData.setValue("Hello, World!"); } public LiveData<String> getText() { return textLiveData; } public void onNextClicked() { // 更新LiveData的值 textLiveData.setValue("Next Clicked!"); } } ``` 最后,创建另一个名为SecondFragment的Fragment,并在MainActivity中添加一个方法来加载它: second_fragment.xml: ```xml <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.text}" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Previous" android:onClick="@{viewModel::onPreviousClicked}" /> </LinearLayout> </layout> ``` SecondFragment.java: ```java public class SecondFragment extends Fragment { private SecondViewModel viewModel; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // 使用DataBinding绑定布局文件 SecondFragmentBinding binding = DataBindingUtil.inflate(inflater, R.layout.second_fragment, container, false); // 创建ViewModel实例 viewModel = ViewModelProviders.of(this).get(SecondViewModel.class); // 将ViewModel与布局文件中的变量绑定 binding.setViewModel(viewModel); // 设置LifecycleOwner,以便LiveData知道何时更新UI binding.setLifecycleOwner(this); return binding.getRoot(); } } ``` 下面是SecondViewModel.java: ```java public class SecondViewModel extends ViewModel { private MutableLiveData<String> textLiveData = new MutableLiveData<>(); public SecondViewModel() { // 初始化LiveData的默认值 textLiveData.setValue("Goodbye, World!"); } public LiveData<String> getText() { return textLiveData; } public void onPreviousClicked() { // 更新LiveData的值 textLiveData.setValue("Previous Clicked!"); } } ``` 最后,在MainActivity中添加一个方法来加载SecondFragment: ```java private void loadSecondFragment() { getSupportFragmentManager().beginTransaction() .replace(R.id.container, new SecondFragment()) .commit(); } ``` 现在,你的MVVM Android项目就完成了!你可以使用LiveDataViewModel来管理数据,并使用DataBinding将数据绑定到UI上。Lifecycle组件可确保UI在活动和片段之间正确地进行管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Awesome_lay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值