最近重新学习了Jetpacl相关组件,在这里记录下
先提出几个问题
ViewModel是什么?它有什么作用
屏幕旋转或者配置变更时,如何进行Activity数据保存
ViewModel是如何做到数据保存的
ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据,ViewModel中数据会一直存活即使 activity configuration发生变化,比如横竖屏切换的时候
implementation ‘androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0’
class PictureInfoViewModel : ViewModel() {
lateinit var uriList: ArrayList<Uri>
var currentPicture: MutableLiveData<Int> = MutableLiveData()
}
class PictureInfoViewModel(application: Application) : AndroidViewModel(application) {
lateinit var uriList: ArrayList<Uri>
var currentPicture: MutableLiveData<Int> = MutableLiveData()
}
// 方式一 : 使用by关键字用委托的方式构建,使用ViewModelProvider类进行,
private val viewModel: PictureInfoViewModel by lazy {
ViewModelProvider(
this,
ViewModelProvider.NewInstanceFactory() // 这里可以用系统的也可以自己实现Factory
).get(PictureInfoViewModel::class.java)
}
// 方式二: 用ComponentActivity提供的扩展函数来构建,如果对Factory没有特别需求,推荐使用这种方式,既简单又方便
private val viewModel: PictureInfoViewModel by viewModels()
// 扩展函数的实现,传进来的Factory为不为空,为空就走默认流程了
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?: {
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}
上面讲到两种构建viewModel的方式,其实两种方式都一样,写法上的区别而已,最终都会调到ViewModelProvider(store, factory).get(viewModelClass.java)
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
// ViewModelStore其实就是一个hashMap,缓存ViewModel
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();
}
}
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;
}
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
// ComponentAcitivty中的具体实现
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.");
}
ensureViewModelStore();
return mViewModelStore;
}
// 往下继续看,如果为空,会尝试从getLastNonConfigurationInstance()里面拿到nc对象
// 再从nc里面获得viweModelstore,getLastNonConfigurationInstance是啥我们后面分析
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();
}
}
}
public ComponentActivity() {
..................
// 忽略无关代码
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
..............
}
总结下:viewModel使用Factory进行创建,并把自身缓存在acitivty的viewModelStore中,这是一个haspMap数据结果,里面能放很多ViewModel,当acitivty销毁时,通过lifecycle的监听回调销毁viewModel
先来复习下界面旋转时走的生命周期
onPause()->onStop()->onSaveInstanceState()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState()->
onResume()
由此可以得到数据恢复的方法一:重写onSaveInstanceState存储那些我们想要保留的重要的临时数据,把他存放在Bundle对象里面,下次再重新开启这个Activity的时候,会执行oncreate方法,我们就可以重onCreate方法的参数中接受这个存储数据的Bundle对象,从里面取出数据。或者从onRestoreInstanceState中取出数据也是同理
方式二 : 通过Activity提供的两个方法,onRetainNonConfigurationInstance进行保存数据,然后通过getLastNonConfigurationInstance恢复保存数据。细心的同学应该发现了,ViewModel也就是通过getLastNonConfigurationInstance获得上一次保存的数据,google已经不推荐我们进行重写,因为已经有ViewModel了嘛
具体ViewModel实现数据保存和恢复的代码
// 数据保存
public final Object onRetainNonConfigurationInstance() {
// Maintain backward compatibility.
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;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
// 数据恢复,这里就是我们上面分析创建流程时的代码,通过getLastNonConfigurationInstance获得上一次的viewModel数据
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();
}
}
}