Android知识总结
一、什么是ViewModel
ViewModel
类指在以注重生命周期的方式存储和管理界面相关的数据。ViewModel
类让数据可在发生屏幕旋转等配置更改后继续留存。在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信。
由于 ViewModel 生命周期可能长与Activity 生命周期,所以为了避免内存泄漏,Google 禁止在 ViewModel 中持有 Context 、Activity 或 View 的引用。如果一定需要使用 Context, 可以继承 AndroidViewModel
类,内部维护了一个 ApplicationContext
。
Android中的ViewModel是一个可以用来存储UI相关的数据的类。ViewModel 一般要配合 LiveData
、DataBinding
一起使用。
特点
1)、通过定义我们可以得出ViewModel不会随着Activity的屏幕旋转而销毁;
在对应的作用域内,保正只生产出对应的唯一实例,保证UI组件间的通信
2)、重点说一下ViewModel和onSaveInstanceState的关系对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。
ViewModel存储大量数据,不用序列化与反序列化
onSaveInstanceState存储少量数据
相辅相成,不是替代
进程关闭是onSaveInstanceState的数据会保留,而ViewModel销毁
二、ViewModel中各个类
-
ViewModelStoreOwner
:是一个接口,用来获取一个ViewModelStore对象 -
ViewModelStore
:存储多个ViewModel,一个ViewModelStore的拥有者( Activity )在配置改变, 重建的时候,依然会有这个实例 -
ViewModel
:一个对 Activity、Fragment 的数据管理类,通常配合 LiveData 使用 -
ViewModelProvider
:创建一个 ViewModel 的实例,并且在给定的ViewModelStoreOwner中存储 ViewModel
三、源码分析
- 1)、ViewModelProvider
ViewModelProvider构造方法
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
- 通过 ViewModelStoreOwner获取ViewModelStore对象并给 mViewModelStore赋值
- 给mFactory赋值,这里赋值的是NewInstanceFactory这个对象
ViewModelProvider的 get 方法
private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";
public T get(@NonNull Class modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
//用来获取对应 ViewModel 实例的,保证了同一个 Key 取出是同一个 ViewModel
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
//ViewModelProvider.java
public T get(@NonNull String key, @NonNull Class modelClass) {
//从ViewModelStore中,根据 key,取一个 ViewModel
ViewModel viewModel = mViewModelStore.get(key);
//判断取出来的 ViewModel 实例和传进来的是否是一个,是同一个,直接返回此缓存中实例
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);
}
//把新创建的ViewModel用ViewModelStore存储起来,以备下次使用,最后返回新创建的ViewModelStore
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
- 2)、ViewModelStore的源码
public class ViewModelStore {
//声明一个 Map 来存储ViewModel
private final HashMap mMap = new HashMap<>();
//存储ViewModel
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
//取出 ViewModel
final ViewModel get(String key) {
return mMap.get(key);
}
Set keys() {
return new HashSet<>(mMap.keySet());
}
- 3)、NewInstanceFactory
通过反射,直接创建了ViewModel对象
//ViewModelProvider.java 中的 AndroidViewModelFactory.java
public T create(@NonNull Class 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);
}
}
- 4)、ViewModelStoreOwner
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
一个接口,里面一个方法返回了ViewModelStore对象,它的实现类在 AndroidX 中ComponentActivity和 Fragment。
public class ComponentActivity extends androidx.core.app.ComponentActivity implements ViewModelStoreOwner,XXX{
private ViewModelStore mViewModelStore;
@NonNull
@Override
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;
}
//创建了一个ViewModelStore并返回了
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
}
四、总结
-
1)、分析为啥ViewModel不会随着Activity的屏幕旋转而销毁
首先知道的是 ViewModel 不被销毁,是在一个 ViewModelStore 的 Map 中存着呢,所以要保证ViewModelStore不被销毁。
主要是通过onRetainNonConfigurationInstance方法把ViewModelStore缓存;在NonConfigurationInstances中,在getViewModelStore取出ViewModelStore。用NonConfigurationInstances
对ViewModelStore
存储和读取。
- onRetainNonConfigurationInstance方法存储
static final class NonConfigurationInstances {
Object custom;
//存储 ViewModel
ViewModelStore viewModelStore;
}
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
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;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
//1把ViewModel存储在 NonConfigurationInstances 对象中
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
- getViewModelStore方法获取
@NonNull
@Override
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) {
//1获取了NonConfigurationInstances一个对象,不为空从其身上拿一个ViewModelStore,这个就是之前保存的ViewModelStore
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
当 Activity 重建时还会走到getViewModelStore
方法,这时候就是在NonConfigurationInstances
拿一个缓存的ViewModelStore。
-
2)、onCleared方法在什么调用
ComponentActivity的构造方法
public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//生命周期为销毁状态
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
//清楚 ViewModel
getViewModelStore().clear();
}
}
}
});
}
在ComponentActivity的构造方法中,我们看到,在 Activity 的生命周期为 onDestory的时候,并且当前不是,配置更改(比如横竖屏幕切换)就会调用ViewModelStore 的 clear 方法,进一步回调用 ViewModel 的onCleared方法。
-
3)、为什么在对应的作用域内,保正只生产出对应的唯一实例
ViewModelStore的 get
方法,是根据key
来取值的,如果 key相同,那取出来的ViewModel就是一个。
ViewModelStore的源码
public class ViewModelStore {
//声明一个 Map 来存储ViewModel
private final HashMap mMap = new HashMap<>();
//存储ViewModel
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
//取出 ViewModel
final ViewModel get(String key) {
return mMap.get(key);
}
Set keys() {
return new HashSet<>(mMap.keySet());
}
//表明要清空存储的数据,还会调用到ViewModel的 clear 方法,也就是最终会调用带 ViewModel 的onCleared()方法
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
注意在从 Map中去 ViewModel 的时候是根据 Key,也就是拼接的那个字符串DEFAULT_KEY + ":" + canonicalName。这也就解释为什么在对应的作用域内,保正只生产出对应的唯一实例。
private static final String DEFAULT_KEY =
"androidx.lifecycle.ViewModelProvider.DefaultKey";
五、ViewModel简单使用
5.1 继承ViewMode,实现自定义ViewModel。
class MyViewModel : ViewModel() {
private var users: MutableLiveData? = null
fun getUsers(): LiveData? {
if (users == null) {
users = MutableLiveData()
setName()
}
return users
}
fun setName() {
users?.value = "onexzgj"
}
}
5.2 使用ViewModel
class ViewModelActivity : AppCompatActivity() {
lateinit var viewmodel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_model)
setTitle("ViewModel的使用")
viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)
viewModel.getUsers()?.observe(this, Observer {
Log.d("ViewModel", it)
})
}
}