Android Jetpack组件-ViewModel使用

707 阅读2分钟

这是我参与 8 月更文挑战的第 15 天,活动详情查看: 8月更文挑战

背景

Activity 和 Fragment 之类的界面控制器主要用于显示界面数据、对用户操作做出响应或处理操作系统通信(如权限请求)。如果要求界面控制器也负责从数据库或网络加载数据,那么会使类越发膨胀。为界面控制器分配过多的责任可能会导致单个类尝试自己处理应用的所有工作,而不是将工作委托给其他类。以这种方式为界面控制器分配过多的责任也会大大增加测试的难度。

从界面控制器逻辑中分离出视图数据所有权的操作更容易且更高效

简介

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。

导入依赖包

//viewmodel
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

实现ViewModel

写一个类并继承ViewModel,如果需要提前初始化变量,可重写无参的构造方法, 提前进行初始化

注意ViewModel 绝不能引用视图、Lifecycle或可能存储对Activity上下文的引用的任何类。

public class TestViewModel extends ViewModel {
    public TestViewModel(){
        // TODO 在创建ViewModel时初始化所需变量
    }
}
  • 获取ViewModel对象 ViewModel的创建方法和普通创建对象的方式不太一样,普通创建对象是通过关键字new,而ViewModel是通过创建ViewModelProvider对象来get对应的ViewModel对象,示例如下
TestViewModel viewModel = new ViewModelProvider(this).get(TestViewModel.class);

ViewModelProviders会去判断当前ViewModel是否存在,如果存在则直接返回,否则它会去创建一个ViewModel,并返回。

带参的ViewModel

google不推荐引用Activity上下文,但有的时候因为需求原因可能必须要一个上下文,这个时候可以使用AndroidViewModel

public class TestAndroidViewModel extends AndroidViewModel {
    public TestAndroidViewModel(Application application) {
        super(application);
    }

    public static class Factory extends ViewModelProvider.NewInstanceFactory {

        private Application mApp;

        public Factory(Application mApp) {
            this.mApp = mApp;
        }

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            return (T) new TestAndroidViewModel(mApp);
        }
    }
}

在程序中创建方式如下

TestAndroidViewModel.Factory factory = new TestAndroidViewModel.Factory(getApplication());
TestAndroidViewModel androidViewModel = factory.create(TestAndroidViewModel.class);

这个时候就可以在ViewModel通过Application进行操作

在Fragment之间共享ViewModel

Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的现象。使用ViewModel可以对其进行共享数据,我们只需要在ViewModelProvider传入的是同一个Activity对象,ViewModelProvider便会根据当前Activity对象去检索是否有ViewModel对象,从而实现Fragment之间共享ViewModel

TestViewModel viewModel = new ViewModelProvider(requireActivity()).get(TestViewModel.class);