欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ViewModel

程序员文章站 2022-03-13 16:53:23
...

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

ViewModel和SavedInstanceState

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

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

相关标签: android