ViewModel

来源:互联网 发布:ps下载中文版免费 mac 编辑:程序博客网 时间:2024/06/16 06:20

ViewModel是用来保存和操作UI相关的数据的,这样即使configuration发生改变,数据仍然可以存在。

引入ViewModel的原因有三点:

  1. Activity和Fragment等App组件的生命周期都是由系统控制的,是开发者不可控的,保存在其中的数据就有丢失的危险。虽然可以通过onSaveInstanceState()来保存数据,可是这个回调只适合用来保存少量数据比如UI状态,对于一些大量数据比如列表数据就不合适了。

  2. 而且Activity和Fragment中都可能进行一些异步操作,这就需要在销毁的时候去清空回调避免内存泄露。或者界面重建后还要重新获取数据,也会浪费资源。

  3. UI控制器本身就负责处理用户交互和系统交互,如果还需要处理数据问题,就会导致职责过多。

所以有必要从UI控制器中抽离出数据的控制权。Lifecycle库提供了ViewModel类用来给UI提供数据。ViewModel不受configuration改变的影响。

ViewModel的示例:

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() {        // do async operation to fetch users    }}

Activity中的使用:

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

如果Activity重建了,仍然可以接收到之前Activity所创建的ViewModel。如果该Activity销毁了,ViewModel的onCleared()会被调用,清空资源。

注意:因为ViewModel独立于Activity和Fragment,所以不能引用任何View,或者任何引用了Context 的对象。如果ViewModel需要一个Application类型的Context,可以继承于AndroidViewModel类,构造方法中会有一个Application对象。

在Fragment间分享数据

Fragment间经常需要分享数据,通常是定义接口,然后通过Activity联系在一起。但是Fragment间的生命周期又可能存在不同步,问题就变得比较复杂了。

假设现在有个列表Fragment,还有一个内容Fragment,点击列表Fragment某一项会更新内容Fragment,使用ViewModel可以比较方便地处理数据问题。可以通过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 onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);        itemSelector.setOnClickListener(item -> {            model.select(item);        });    }}public class DetailFragment extends LifecycleFragment {    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);        model.getSelected().observe(this, { item ->           // update UI        });    }}

这样做的好处是:

  • Activity不用再负责两个Fragment之间的联系
  • Fragment只需要知道ViewModel,不需要知道其他的Fragment,耦合性降低
  • 每个Fragment的生命周期相互独立互不影响。

ViewModel的生命周期

这里写图片描述

ViewModel和SavedInstanceState

ViewModel在Activity的configuration改变过程中可以保持数据不变,但是如果系统把应用杀死掉就没办法了。

如果用户长时间离开应用再进来,应用进程可能已经被系统杀掉了,此时系统会负责恢复之前保存的SavedInstanceState。在onSaveInstanceState()中保存的数据是放在系统进程内存中的,Android系统只允许存放少量的数据,所以最好不要存放一些自定义类的对象进去,可以把自定义对象保存到数据库中,onSaveInstanceState中只保留对象的某个字段比如id,然后再使用ViewModel根据这个id去获取完整的数据。