# ViewModel 源码剖析
# 示例代码
ViewModel 负责数据存储,借助 LiveData,实现异步获取数据,完成后,通知 UI 观察者,更新 UI
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. | |
List<User> requestResult = requestUsers(); | |
// Once value changes, observer will be notified. | |
users.set(requestResult); | |
} | |
} |
UI 层注册数据变更监听。注意 ViewModelProvider 构造器参数是哪个 Activity,Fragment 实例,ViewModel 实例化后,其引用寄存在该实例内。他们都实现 ViewModelStoreOwner 接口。
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. | |
// 1. ViewModel 实例挂载在 this 实例里,有点相当于是 this 实例的成员变量 | |
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class); | |
// 2. 这里的 this 参数,决定观察者的生命周期。注意,如果此参数是 activity 实例,而当前类是 fragment,则 fragment 实例内存泄漏 | |
model.getUsers().observe(this, users -> { | |
// update UI | |
}); | |
} | |
} |
注意,observe 这里第一个参数,决定观察者的生命周期。所以,如下示例代码,此参数是 activity 实例,而当前类是 fragment,则 fragment 实例内存泄漏,因为监听实例生命周期和 Activity 一致,而它持有 Fragment 实例引用,导致 Fragment 在 Activity 生命周期内无法被回收。
public class MyFragment extends Fragment { | |
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(requireActivity(), users -> { | |
// update UI | |
}); | |
} | |
} |
# 源码剖析
先从 ViewModel 实例化开始,首先要解决 ViewModel 如何实例化,并存放实例,便后续获取实例。
androidx.lifecycle.ViewModelProvider.java | |
/** | |
* Creates {@code ViewModelProvider}. This will create {@code ViewModels} | |
* and retain them in a store of the given {@code ViewModelStoreOwner}. | |
* <p> | |
* This method will use the | |
* {@link HasDefaultViewModelProviderFactory#getDefaultViewModelProviderFactory() default factory} | |
* if the owner implements {@link HasDefaultViewModelProviderFactory}. Otherwise, a | |
* {@link NewInstanceFactory} will be used. | |
*/ | |
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) { | |
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory | |
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() | |
: NewInstanceFactory.getInstance()); | |
} | |
/** | |
* Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given | |
* {@code Factory} and retain them in a store of the given {@code ViewModelStoreOwner}. | |
* | |
* @param owner a {@code ViewModelStoreOwner} whose {@link ViewModelStore} will be used to | |
* retain {@code ViewModels} | |
* @param factory a {@code Factory} which will be used to instantiate | |
* new {@code ViewModels} | |
*/ | |
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) { | |
this(owner.getViewModelStore(), factory); | |
} | |
/** | |
* Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given | |
* {@code Factory} and retain them in the given {@code store}. | |
* | |
* @param store {@code ViewModelStore} where ViewModels will be stored. | |
* @param factory factory a {@code Factory} which will be used to instantiate | |
* new {@code ViewModels} | |
*/ | |
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) { | |
mFactory = factory; | |
mViewModelStore = store; | |
} |
Activity,Fragment 实例,他们都实现 ViewModelStoreOwner 接口,看这名字,顾名思义,就是提供存放 ViewModel 实例的地方。同时,ViewModelStoreOwner 可能自带 ViewModel 构造工厂,没有的话,就使用 ViewModelProvider 内的 NewInstanceFactory 实例。
ViewModelStoreOwner 返回 ViewModelStore,内部就是一个 Map,key 是 ViewModelProvider(this).get(MyViewModel.class);
get 方法传入 ViewModel class 的 canonicalName,value 就是对应的 ViewModel 实例啦。Activity 或者 Fragment 持有 ViewModelStore 引用。
androidx.lifecycle.ViewModelProvider | |
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; | |
} |
总结下,ViewModelStoreOwner 提供负责存储 ViewModel 的类:ViewModelStore,ViewModel 由 Factory 创建,然后放在 ViewModelStore 实例内,下次直接从 ViewModelStore 通过 get 方法获取,单例。
# AndroidViewModel & ViewModel
ViewModel 不可以强引用 Context,如果确实需要,则使用 AndroidViewModel,它持有 Application 的引用。解决需要的同时,避免 Activity 泄漏。
ViewModelProvider
默认实例化的 ViewModel 由 NewInstanceFactory 创建。AndroidViewModel 由 AndroidViewModelFactory 通过作为实例化 ViewModelProvider
构造器的 Factory 参数创建。
Activity & Fragment 也同时实现 HasDefaultViewModelProviderFactory
接口。看下 SavedStateViewModelFactory
,区分是实例化 ViewModel 还是 AndroidViewModel,并增加保存状态的处理。
androidx.lifecycle.SavedStateViewModelFactory | |
@NonNull | |
@Override | |
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) { | |
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass); | |
Constructor<T> constructor; | |
if (isAndroidViewModel && mApplication != null) { | |
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE); | |
} else { | |
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE); | |
} | |
// doesn't need SavedStateHandle | |
if (constructor == null) { | |
return mFactory.create(modelClass); | |
} | |
SavedStateHandleController controller = SavedStateHandleController.create( | |
mSavedStateRegistry, mLifecycle, key, mDefaultArgs); | |
try { | |
T viewmodel; | |
if (isAndroidViewModel && mApplication != null) { | |
viewmodel = constructor.newInstance(mApplication, controller.getHandle()); | |
} else { | |
viewmodel = constructor.newInstance(controller.getHandle()); | |
} | |
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller); | |
return viewmodel; | |
} catch (IllegalAccessException e) { | |
throw new RuntimeException("Failed to access " + modelClass, e); | |
} catch (InstantiationException e) { | |
throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e); | |
} catch (InvocationTargetException e) { | |
throw new RuntimeException("An exception happened in constructor of " | |
+ modelClass, e.getCause()); | |
} | |
} |
ViewModel 就是一个壳,与 ViewModelStoreOwner 共存亡。但 Activity 因 onConfigurationChanged 重建后,会获取上一个 Activity ViewModelStore,恢复上一个 ViewModel。
androidx.activity.ComponentActivity | |
void ensureViewModelStore() { | |
if (mViewModelStore == null) { | |
NonConfigurationInstances nc = | |
(NonConfigurationInstances) getLastNonConfigurationInstance(); | |
if (nc != null) { | |
// Restore the ViewModelStore from NonConfigurationInstances | |
mViewModelStore = nc.viewModelStore; | |
} | |
if (mViewModelStore == null) { | |
mViewModelStore = new ViewModelStore(); | |
} | |
} | |
} |
# OnRequeryFactory 接口
用途:提供从 ViewModelProvider get 返回 ViewModel 实例前的回调,可以在返回前对 ViewModel 做些预处理。SavedStateViewModelFactory 实现此接口。
androidx.lifecycle.SavedStateViewModelFactory | |
@Override | |
void onRequery(@NonNull ViewModel viewModel) { | |
attachHandleIfNeeded(viewModel, mSavedStateRegistry, mLifecycle); | |
} |
androidx.lifecycle.ViewModelProvider | |
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) { | |
ViewModel viewModel = mViewModelStore.get(key); | |
if (modelClass.isInstance(viewModel)) { | |
// 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; | |
} |