[译] Architecture Components 之 ViewModel

【目录】

1. Architecture Components 之 Guide to App Architecture

2. Architecture Components 之 Adding Components to your Project

3. Architecture Components 之 Handling Lifecycles

4. Architecture Components 之 LiveData

5. Architecture Components 之 ViewModel

6. Architecture Components 之 Room Persistence Library

示例代码连接


ViewModel

ViewModel 类是被设计用来存储和管理 UI 相关的数据,以便在配置更改(如:屏幕旋转)时数据能够保留下来。javascript

注:在 Android 项目中导入 ViewModel,请参阅添加组件到项目中html

应用程序组件(如:activity 和 fragment)具备一个由 Android Framework 管理的生命周期。Framework 可能会彻底不受控制的根据某些用户操做或设备事件来决定销毁或从新建立它们。java

因为这些对象有可能被操做系统销毁或从新建立,因此保存在它们中的任何数据都会丢失。例如:若是 activity 中有一个用户列表,当 activity 由于配置更改而从新建立时,新的 activity 必须从新获取用户列表。对于简单的数据,activity 可使用 onSaveInstanceState() 方法从 onCreate() 中的 bundle 里恢复数据,可是这种方式只适用于少许数据(如:UI 状态),不适用于大量数据(如:用户列表)。android

另外一个问题是,这些 UI 控制器(activity,fragment 等)常常须要发起一些须要必定时间才能返回的异步调用。UI 控制器须要管理这些调用而且在其被销毁时清理它们避免潜在的内存泄漏。这须要大量的维护工做,而且在因为配置更改致使对象被从新建立的状况下十分浪费资源,由于须要从新发起相同的请求。git

最后单也很重要的是,这些 UI 控制器已经须要完成响应用户操做和处理操做系统通讯的工做了。当它们还须要手动处理其资源时,将会使类变的臃肿,创造“万能 activity”(或“万能 fragment”);也就是说,一个单独的类视图本身处理应用程序的全部工做,而不是将工做委派给其它类。这将会使测试很是困难。github

将视图数据的全部权从 UI 控制器的逻辑中分离出来是简单高效的。Lifecycle 提供了一个叫 ViewModel 的新类,一个 UI 控制器的帮助类,用来为 UI 准备数据。在配置更改期间,ViewModel 会自动保留,以便其保存的数据可以当即提供给下一个 activity 或 fragment 实例。在咱们上面提到的例子中,获取并持有数据是 ViewModel 的责任,而不是 activity 或 fragment 的。app

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // 执行异步操做获取用户
    }
}复制代码

如今 activity 能够像下面这样访问列表:异步

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // 更新 UI
        });
    }
}复制代码

若是 activity 被从新建立,它将会收到由以前 activity 建立的同一个 MyViewModel 实例。当全部者 activity 结束后,Framework 会调用 ViewModelonCleared() 方法来清理资源。ide

注:因为 ViewModel 存活的比个别的 activity 和 fragment 实例,因此它决不能引用 View,或任何持有 activity context 的引用的类。若是 ViewModel 须要 Application 的 context(如:调用系统服务),能够继承 AndroidViewModel 类,能够在构造函数中接受 Application(由于 Application 继承了 Context)。函数

在 Fragment 之间共享数据

activity 中的两个或多个 fragment 须要相互通讯是很常见的。这不是个简单的事情,全部的 fragment 都须要定义一些接口秒素,而且拥有它们的 activity 必须将二者绑定在一块儿。另外,全部的 fragment 必须处理其它的 fragment 没有被建立或不可见的状况。

使用 ViewModel 能够解决这个常见的痛点。假设一个主从式 fragment 的常见状况,用户从一个 fragment 的列表里选中一项,另外一个 fragment 显示所选项的内容。

这些 fragment 可使用其 activity 限定的 ViewModel 来处理该通信。

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onActivityCreated() {
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends LifecycleFragment {
    public void onActivityCreated() {
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // 更新 UI
        });
    }
}复制代码

请注意,在获取 ViewModelProvider 时两个 fragment 都使用 getActivity() 方法。这意味着它们都将会收到被 activity 限定的同一个 SharedViewModel 实例。

这种方式的优势有:

  • activity 不须要作或知道关于该通信的任何事情。

  • 除了 SharedViewModel 协议以外 fragment 不须要了解彼此。若是其中一个消失,另外一个会照常工做。

  • 每一个 fragment 有本身的生命周期,而且不受其它 fragment 的生命周期影响。实际上,在 UI 中一个 fragment 替换另外一个 fragment,UI 的运行没有任何问题。

ViewModel 的生命周期

在获取 ViewModel 时,ViewModel 对象被传递给 ViewModelProviderLifecycle 限定。ViewModel 保留在内存中,直到限定它的 Lifecycle 永久消失(当 activity 结束或 fragment 被分离)。

相关文章
相关标签/搜索