Jetpack-ViewModel

402 阅读3分钟

作用存储和管理UI相关的数据,并且与声明周期关联。ViewModel保证数据在配置改变时能够存活,如屏幕旋转。

引入的原因

  1. 如果系统销毁或者重新创建UI组件,那么存储的与UI相关的瞬时数据就会丢失。举例来说,你的应用可能在Activity中存储了一个用户列表。当Activity因为配置改变重建时,新的Activity需要重新获取用户列表。针对简单的数据,Activity可以用onSaveInstanceState()方法存储并在onCreate()重建这些数据,但是这个方法只是适用于少量的可以被序列化和反序列化的数据,而不适用于大量的数据例如用户或者位图的列表。
  2. 另一个问题是UI组件会经常需要异步调用,它们需要花费一些时间。UI组件需要管理这些异步调用,并且确保系统能够在组件被销毁时能够回收这些调用,以避免内存泄漏。这些管理需要大量的维护工作,同时这些对象在配置改变时会重新创建,这是一种资源浪费,因为这些对象已经创建了,但是又必须重新创建。
  3. 像Activity和Fragment这样的UI组件的首页目的是展示UI数据,响应用户行为,以及处理操作系统的行为,如权限申请。UI组件也需要负责从数据库或者网络加载数据,这会使类膨胀。将过多的责任分配给UI组件会导致一个类需要独立处理很多工作,而不是将这些工作委托给其他类。把过多的工作分配给UI组件也会导致测试变得困难。

使用:

定义ViewModel

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

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }

    static class User {
        String name;
        int age;
    }
}

在Activity中获取一个实例

UserViewModel model = null;
model = new ViewModelProvider(this).get(UserViewModel.class);
model.getUsers().observe(this, new Observer<List<UserViewModel.User>>() {
	@Override
    public void onChanged(List<UserViewModel.User> users) {
    }
});

在多个Fragment中共享ViewModel

//通过activity的ViewModelStore获取ViewModel
new ViewModelProvider(getActivity()).get(UserViewModel.class);

类图:

关键类:

ViewModel:数据管理类,以及处理Activity和Fragment对数据的交互操作

public abstract class ViewModel {
    //为ViewModel存储一些数据
    private final Map<String, Object> mBagOfTags = new HashMap<>();
    //onDestroy时标记数据已被清除
    private volatile boolean mCleared = false;
}

ViewModelStore:存储ViewModel

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

ViewModelProvider:获取ViewModel

public class ViewModelProvider {
    //ViewModel的创建工厂
    private final Factory mFactory;
    //存储ViewModel
    private final ViewModelStore mViewModelStore;
    
    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }
    //获取对应的ViewModel对象
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        //如果ViewModelStore中不存在,则使用Factory创建
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }
}

Factory:创建ViewlMode实例

public interface Factory {
    @NonNull  //创建ViewModel实例
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}

实现Factory接口的有KeyedFactory,NewInstanceFactory,AndroidViewModelFactory等实例创建类

Activity的重建时的数据恢复过程:

数据保存过程

  1. 在ComponentActivity的onSaveInstanceState()中保存:

  2. SavedStateRegistryController中调用SavedStateRegistry进行保存

  3. SavedStateRegistry执行保存逻辑

    ①AbstractSavedStateViewModelFactory创建的对象最终会被添加到mComponents中

    ②在数据恢复时,mRestoredState会从取出保存的components。当调用AbstractSavedStateViewModelFactory的create方法时,会从mRestoredState中获取对应的bundle,并remove

    如何去使用这些数据的逻辑有点复杂,可以看AbstractSavedViewModelFactory的create方法:

数据恢复过程

  1. ComponentActivity的onCreate执行恢复:
  2. SavedStateRegistryController中调用SavedStateRegistry的performRestore进行恢复:
  3. SavedStateRegistry执行恢复逻辑
    取出保存时key为SAVED_COMPONENTS_KEY对应的bundle