简介
ViewModel为Activity或Fragment准备数据,帮助UI处理数据等耗时任务。
ViewModel的优点
1、 ViewModel当Activity的Configuration变更(例如横竖屏切换)或者各种原因导致的销毁重建时,会自动保留对象,当Activity重建后可立即使用,不需要重新获取数据。
2、ViewModel的生命周期避免了内存泄露问题。在Activity.onDestroy时会关联ViewModel.onCleared()方法,从而在这里释放内存。ViewModel跟Activity生命周期关系:
3、ViewModel在处理Fragment共享数据方面很好用,同一个Activity下不同的Fragment可以共享同一个ViewModel对象。
ViewModel的简单使用
1、ViewModel负责获取数据
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<User>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
@Override
protected void onCleared() {
super.onCleared();
users = null;
}
}
2、这里使用了LiveData观察数据变化
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
使用非常简单,不需要自己搞接口回调更新UI数据,也不用使用Handler。
源码分析
一、ViewModel如何保证唯一关联Activity,并且重建后依然是同一个ViewModel
ViewModel基于AppCompatActivity使用才会达到这个效果,我们以AppCompatActivity源码分析
1、首先获取ViewModel是通过new ViewModelProvider(this)获取到provider,看下构造类
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
ViewModelProvider主要就是存了ViewModelStore和Factory。Factory就是一个简答的通过Class名创建一个对象。
2、然后看下ViewModelProvider.get()方法
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
ViewModel是通过mViewModelStore.get()获取的,如果没有就通过Factory创建了新的ViewModel。
3、ViewModelStore是在ViewModelProvider构造方法作为参数传入的
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
看下AppCompatActivity哪里实现了getViewModelStore()方法
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
}
这里可以看到Activity保存了唯一的ViewModelStore
4、这里我们看下getLastNonConfigurationInstance方法,这个方法是Activity的标准方法
/**
* Retrieve the non-configuration instance data that was previously
* returned by {@link #onRetainNonConfigurationInstance()}. This will
* be available from the initial {@link #onCreate} and
* {@link #onStart} calls to the new instance, allowing you to extract
* any useful dynamic state from the previous instance.
*
* <p>Note that the data you retrieve here should <em>only</em> be used
* as an optimization for handling configuration changes. You should always
* be able to handle getting a null pointer back, and an activity must
* still be able to restore itself to its previous state (through the
* normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
* function returns null.
*
* <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
* {@link Fragment#setRetainInstance(boolean)} instead; this is also
* available on older platforms through the Android support libraries.
*
* @return the object previously returned by {@link #onRetainNonConfigurationInstance()}
*/
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
大致意思就是这个方法会在Activity重建时保存一个Object,而ComponentActivity利用了这个Object存储了ViewModelStore对象。
5、ViewModelStore类结构
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());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
ComponentActivity唯一包含了ViewModelStore,ViewModelStore存储了ViewModel,ViewModelProvider通过ComponentActivity取到了ViewModelStore,从而唯一获取到了ViewModel。因为ComponentActivity重建保存了ViewModelStore,也就保存了ViewModel。
二、看下ViewModel如何把onCleared和Activity生命周期关联的
1、首先ViewModel.clear()是在ViewModelStore中被调用的
public class ViewModelStore {
......
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
2、ViewModelStore.clear是被ComponentActivity调用的
public ComponentActivity() {
......
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
......
}
这里看到,最终是通过Lifecycle生命周期监听处理的。
可以参考lifecycle讲解:
lifecycle原理分析