数据保留的原理
当Activity
或Fragment
首次创建时,它们会请求一个ViewModel
实例,通常是通过ViewModelProvider
。ViewModelProvider
负责实例化ViewModel
对象,并确保在Activity
或Fragment
的生命周期内这些对象保持不变。
- 首次创建 :如果是首次创建,
ViewModelProvider
会创建一个新的ViewModel
实例。 - 配置更改后 :如果发生配置更改(如屏幕旋转),
Activity
或Fragment
将被销毁并重新创建。这时,ViewModelProvider
会返回同一个ViewModel
实例而不是创建一个新的实例。这就是ViewModel
如何保持数据不丢失的关键所在。
ViewModel
对象是存储在由ViewModelStore
管理的一个容器中的,每个Activity
或Fragment
都有自己的ViewModelStore
。当Activity
或Fragment
实例被销毁时,系统会检查是否是因为配置更改而销毁。如果是,ViewModelStore
不会被清除,ViewModel
就会继续存在。只有当Activity
或Fragment
实例被最终销毁(例如用户完成了Activity
),ViewModelStore
才会被清除,随之ViewModel
也会被清理。
源码流程解析
ViewModel的使用一般不能离开ViewModelProvider,我们以ViewModel的使用一般不能离开ViewModelProvider实例化为入口,看一下ViewModel是怎样运行的。
kotlin
class MainActivity : AppCompatActivity() {
// 300个字段
// var number : Int = 0;
private lateinit var myViewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d("DDD", "onCreate: ")
// myViewModel = MyViewModel() 不能直接实例化,因为如果能这样写,无法对生命周期进行管控。
// 旧版本的写法,更新特别快(扩展性不强)
// ViewModelProviders.of()
// this == ViewModelStoreOwner,
myViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
.get(MyViewModel::class.java)
Activity实现了ViewModelStoreOwner,因此可以直接传入这个对象。
csharp
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
ViewModelStoreOwner里边返回了一个ViewModelStore,这个类里边,有一个hashMap,用来做数据存储。
typescript
public class ViewModelStore {
// 用map来存储ViewModel,因为一个页面是很有可能有多个ViewModel的。
private final HashMap<String, ViewModel> mMap = new HashMap();
public ViewModelStore() {
}
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = (ViewModel)this.mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return (ViewModel)this.mMap.get(key);
}
Set<String> keys() {
return new HashSet(this.mMap.keySet());
}
public final void clear() {
Iterator var1 = this.mMap.values().iterator();
while(var1.hasNext()) {
ViewModel vm = (ViewModel)var1.next();
vm.clear();
}
this.mMap.clear();
}
}
然后来看看ViewModelProvider的实例化的第二个参数,采用的Factory来实现.
ViewModel的实例化过程中,会调用owner.getViewModelStore(),这个的实现是在ComponentActivity处理的。
less
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
this.mFactory = factory;
// 这就是我们最终的成果。保存这个成员变量。
this.mViewModelStore = store;
}
kotlin
public ViewModelStore getViewModelStore() {
if (this.getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
} else {
// 构建一个ViewModelStore。
if (this.mViewModelStore == null) {
// 获取上一次状态的存储类的数据
NonConfigurationInstances nc = (NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nc != null) {
this.mViewModelStore = nc.viewModelStore;
}
if (this.mViewModelStore == null) {
this.mViewModelStore = new ViewModelStore();
}
}
return this.mViewModelStore;
}
}
当然,在Fragment中也有类似的实现。
.get(MyViewModel::class.java) 调用工厂ViewModelProvider.NewInstanceFactory(),最终会通过反射完成实例化:
typescript
@NonNull
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
try {
return (ViewModel)modelClass.newInstance();
} catch (InstantiationException var3) {
throw new RuntimeException("Cannot create an instance of " + modelClass, var3);
} catch (IllegalAccessException var4) {
throw new RuntimeException("Cannot create an instance of " + modelClass, var4);
}
}
当Activity重新创建的时候,会触发 Activity#retainNonConfigurationInstances,
最终会进入:
ini
# public final Object onRetainNonConfigurationInstance() {
Object custom = this.onRetainCustomNonConfigurationInstance();
// 如果mViewModelStore不为空的话,就会通过此来进行数据的恢复。
ViewModelStore viewModelStore = this.mViewModelStore;
NonConfigurationInstances nci;
if (viewModelStore == null) {
// 获取上一次状态的存储类的数据
nci = (NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nci != null) {
viewModelStore = nci.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
} else {
// 将这些数据存储到当前的nci中,以便下次配置变化时使用。
nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
}
这就是ViewModel可以用来做数据保存的底层原理。在ViewModel没有出来之前,我们可以自行重写 onRetainNonConfigurationInstance来实现数据的恢复。
包含关系:Activity或者Fragment包含ViewModelProvider,ViewModelProvider包含ViewModelStore,ViewModelStore包含ViewModel。
附:Acitivity与ViewModel的生命周期对应关系
只有在Acitivity被销毁之后,ViewModel才会回收。即便不可见也是存在的。