通過源碼解析掌握
- ViewModel的創建過程
- ViewModel的存在哪里
- ViewModel的生命周期
- 為什么Activity旋轉屏幕后ViewModel可以恢復數據
ViewModel的創建
通過之前對ViewModel的使用,了解ViewModel的創建是通過 ==ViewModelProvider== 來創建的
MyViewModel myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
//或者直接使用工具類創建
//ViewModelProviders是一個工具類,對ViewModelProvider進行了封裝
MyViewModel myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
傳遞的是class ,說明是通過反射來創建的,那么就從ViewModelProvider入手
[ViewModelProvider.java]
public class ViewModelProvider {
private static final String DEFAULT_KEY =
"androidx.lifecycle.ViewModelProvider.DefaultKey";
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
static class OnRequeryFactory {
void onRequery(@NonNull ViewModel viewModel) {
}
}
abstract static class KeyedFactory extends OnRequeryFactory implements Factory {
@NonNull
public abstract <T extends ViewModel> T create(@NonNull String key,
@NonNull Class<T> modelClass);
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
throw new UnsupportedOperationException("create(String, Class<?>) must be called on "
+ "implementaions of KeyedFactory");
}
}
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
//ViewModelStoreOwner就是當前Activity,
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
@NonNull
@MainThread
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);
}
@SuppressWarnings("unchecked")
@NonNull
@MainThread
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的提供者,ViewModelProvider類有兩個屬性
//負責創建ViewModel的工廠
private final Factory mFactory;
//負責存儲ViewModel的存儲器
private final ViewModelStore mViewModelStore;
從構造函數來看,有三個構造函數
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
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 實例對象,獲取創建ViewModel的Factory和ViewModelStore的實例對象,ViewModelStoreOwner表示自己存儲ViewModel功能的組件,Activity和Fragment都實現了該接口
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
該接口就是獲取ViewModelStore
接下來是調用 get(@NonNull Class<T> modelClass) 方法獲取ViewModel實例對象
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) {
//從ViewModelStore中獲取,如果有則返回,如果沒有則通過Factory創建一個實例對象
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.
}
}
//通過Factory創建ViewModel實例對象
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
} else {
viewModel = mFactory.create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
這個方法主要功能:
- 獲取類的標準類名,并拼接上默認的Key
- 從ViewModelStore中查找是否有已創建的ViewModel
- 如果ViewModelStore中沒有該ViewModel的實例對象,則通過Factory反射創建一個,并保存到ViewModelStore中
從K—V模式來開,ViewModelStore就是通過HashMap來保存ViewModel的
[ViewModelStore.java]
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();
}
}
這里很簡單了,就是HashMap,在Activity或者Fragment的銷毀的時候,將map 清空
具體實現在ComponentActivity類中
[ComponentActivity.java]
public ComponentActivity() {
...
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
//不是屏幕橫豎屏切換,則清空Map
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
...
}
接下來看看Factory
/**
* Simple factory, which calls empty constructor on the give class.
*/
public static class NewInstanceFactory implements Factory {
private static NewInstanceFactory sInstance;
/**
* Retrieve a singleton instance of NewInstanceFactory.
*
* @return A valid {@link NewInstanceFactory}
*/
@NonNull
static NewInstanceFactory getInstance() {
if (sInstance == null) {
sInstance = new NewInstanceFactory();
}
return sInstance;
}
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
/**
* {@link Factory} which may create {@link AndroidViewModel} and
* {@link ViewModel}, which have an empty constructor.
*/
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
/**
* Retrieve a singleton instance of AndroidViewModelFactory.
*
* @param application an application to pass in {@link AndroidViewModel}
* @return A valid {@link AndroidViewModelFactory}
*/
@NonNull
public static AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
/**
* Creates a {@code AndroidViewModelFactory}
*
* @param application an application to pass in {@link AndroidViewModel}
*/
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
// 如果是AndroidViewModel,繼承了ViewModel并含有Application
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
}
實現了Factory的工廠類也很簡單,工廠是一個單例,沒有構造函數則通過NewInstanceFactory 反射創建
如果是AndroidViewModel則通過AndroidViewModelFactory創建
再來看一下旋轉屏幕后ViewModel是怎么恢復數據的,這塊代碼當然是在Activity里面了;這個方法就是當屏幕旋轉會調用的:
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
// 若 viewModelStore 為空,則嘗試從 getLastNonConfigurationInstance() 中獲取,mViewModelStore本身就是Activity的成員變量
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
//
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
// 依然為空,說明沒有需要緩存的,則返回 null
if (viewModelStore == null && custom == null) {
return null;
}
// 創建 NonConfigurationInstances 對象,并賦值 viewModelStore
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
看了上面代碼,也就是說Activity 在因配置更改而銷毀重建過程中會先調用 onRetainNonConfigurationInstance 保存 viewModelStore 實例。
在重建后可以通過 getLastNonConfigurationInstance 方法獲取之前的 viewModelStore 實例。
這里就類似Activity的onSaveInstanceState(Bundle)了。
總結
- ViewModel 實例對象是又ViewModelProvider提供的
- 創建ViewModelProvider實例對象需要一個ViewModelStore和Factory,ViewModelStore由ViewModlestoreOwner提供,Activity和Fragment實現該接口,Activity組件當生命周期事件為ON_DESTORY 并且不是橫豎屏切換的時候則清空Map
- ViewModelProvider主要的工作就是從ViewModelStore中查是否該實例對象已保存在map中,如果有則直接返回,如果沒有則通過Factory反射創建一個ViewModel并保存在ViewModelStore中
- ViewModelStore在Activity或者Fragment生命周期結束的時候清空掉Map中保存的ViewModel
- 屏幕旋轉保存數據的實現就類似我們的onSaveInstanceState的實現。