LiveData和ViewModel源码分析
本文于
1290
天之前发表,文中内容可能已经过时。
[TOC]
ViewModel ViewModel的定义 ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
历史方式的缺点 :
对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。
需要处理异步调用,内存泄漏等问题
使界面控制器类越发膨胀
ViewModel将数据存储和界面控制进行分离,独立出来 ViewModel 存在的时间范围是从您首次请求 ViewModel 直到 Activity 完成并销毁。
ViewModel生命周期
ViewModel在onCreate中初始化,在finish()后会调用onCleared()方法,
所以ViewModel生命周期长于Activity,ViewModel不持有UI的引用,通过观察者通知界面更新
ViewModel在Fragment之间共享数据 为什么能在Fragment中共享数据? 因为在Fragment中初始化ViewModel时传入的宿主Activity,ViewModelStore中取出当前Activity对应的ViewModel对象,返回给Fragment,这样他们获取的是同一个ViewModel实例,数据当然也会共享
ViewModel源码分析 构造函数 我们通常使用这种方式初始化ViewModel
1 2 3 4 5 6 7 ProgressViewModel processViewModel = new ViewModelProvider (this ).get(ProcessViewModel.class);public ViewModelProvider (@NonNull ViewModelStoreOwner owner) { this (owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory() : NewInstanceFactory.getInstance()); }
从ViewModelStoreOwer中获取ViewModelStore,ViewModelStore是从AppCompatActivity->FragmentActivity->ComponentActivity中获取,本质还是new ViewModelStore()。 Factory在AppCompatActivity和Fragment中的是HasDefaultViewModelProviderFactory,具体实现是SavedStateViewModelFactory
1 2 3 4 public ViewModelProvider (@NonNull ViewModelStore store, @NonNull Factory factory) { mFactory = factory; mViewModelStore = store; }
将ViewModelStore和Factory进行赋值
get方法 进入get方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @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); } @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 { if (viewModel != null ) { } } if (mFactory instanceof KeyedFactory) { viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass); } else { viewModel = (mFactory).create(modelClass); } mViewModelStore.put(key, viewModel); return (T) viewModel; }
我们可知 Factory放入具体实现是SavedStateViewModelFactory,SavedStateViewModelFactory又继承于KeyedFactory,我们看下create方法,值得一提的是,这里的mFactory是AndroidViewModelFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @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) { constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE); } else { constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE); } if (constructor == null ) { return mFactory.create(modelClass); } SavedStateHandleController controller = SavedStateHandleController.create( mSavedStateRegistry, mLifecycle, key, mDefaultArgs); try { T viewmodel; if (isAndroidViewModel) { 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类型,获取不同的构造方法,通过反射实现ViewModel的初始化,然后使用mViewModelStore.put(key, viewModel); 将viewModel以key的形式存入ViewModelStore 进入ViewModelStore:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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()); } public final void clear () { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } }
内部实现就是一个HashMap,Key为String,value为ViewModel,put后新放入的ViewModel覆盖新的ViewModel,这里的key强调一下,统一格式为androidx.lifecycle.ViewModelProvider.DefaultKey:com.zz.chatright.ChatViewModel
SavedState 在源码分析中我们看到构造函数中都包含了一个SavedStateHandleController类,这里保存了数据类,使其不受生命周期影响,例如发生屏幕旋转等。
SaveStateHandle: 内部存储数据格式为*Map<String, Object>,亦存在 Map<String, SavingStateLiveData<?>>*完成值的通知
SaveStateHandleController: 将SaveStateHandle同Lifecycle生命周期进行绑定
SavedStateRegistry: 管理 SavedStateProvider 列表的组件,此注册表绑定了其所有者的生命周期(即 activity 或 fragment)
SavedStateProvider: 保存状态的组件,此状态将在以后恢复并使用
activity 的状态保存分为 view 状态和成员状态
继承关系
如何保证viewModel的唯一性? 通过反射进行初始化操作,带入的是Application的Context对象,这样就保证不会持有Activity或者Fragment的引用。然后会将创建出来的实例对象存储在ViewModelStore(内部HashMap)中,每次使用都会去ViewModelStore中查看是否存在,如果存在,则直接使用,不需要实例化 key就是DEFAULT_KEY + “:” + canonicalName(viewmModel类名路径,eg:com.zz.test.MyViewModel)
为什么viewModel能管理生命周期,并且不受重建情况的影响 2.0以前:创建了一个无view的HolderFragment同步Activity的生命周期,并关联ViewModelStore,而且设置setRetainInstance(true)时,会保证屏幕切换时生命周期不会改变,让fragment在Activity重建时存活下来
2.0以后:运用了androidx新库,用到了AppCompatActivity的父类ComponentActivity,重写onRetainNonConfigurationInstance()方法保存了ViewModelStore,Activity通过onRetainNonConfigurationInstance()方法获取ViewModelStore实例,保证了ViewModel不会随着Activity的重建而重建。 不论是Activity还是Fragment都实现了LifecycleOwner,所以生命周期通过Lifecycles组件感知每个页面的生命周期
onRetainNonConfigurationInstance()和onSaveInstanceState的调用时机是一样的,但是onRetainNonConfigurationInstance()的Bundle数据不限制大小,所以更倾向这个
当Activity因为配置需要重建时,系统会调用onRetainNonConfigurationInstance()方法,将ViewModelStore存储在NonConfigurationInstances中,最终交给ActivityClientRecord类,因为ActivityClientRecord不受Activity重建的影响,所以NoConfigurationInstances也不受Activity重建的影响
ViewModel同onSaveInstanceState()的区别 使用场景 在Activity变得“容易”销毁时,就会触发onSaveInstanceState()
当按下HOME键后,系统就会触发调用
当长按HOME键,选择运行其他程序时
按电源键息屏的时候
从Activity A中启动一个新的Activity
横竖屏切换时
而使用ViewModel恢复数据 则 只有在 因配置更改界面销毁重建 的情况。
存储方式 ViewModel存储在内存中,onSaveInstanceState()是序列化到磁盘中存储的
存储大小 ViewModel存储大小限制时app的可用内存 onSaveInstanceState()因为使用了序列化和反序列化,那么通过Bundle存储大小限制为1M
LiveData LiveData的定义
当在onStart后,onResume,onPause都是STARTED/RESUMED的,即为活跃的(onActive),当在onStop后,则为非活跃状态(onInActive) LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。
您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 Activity 和 Fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 Activity 和 Fragment 的生命周期被销毁时,系统会立即退订它们)。
LiveData的优势
及时更新界面数据
不会发生内存泄漏,当其关联的生命周期被摧毁,则回收自己
不会因为Activity停止而崩溃,准确判断生命周期,决定是否通知
不需要自己手动处理生命周期
在再次活跃时会接收到最新的数据,保持数据最新状态
如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
共享资源。 您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。
LiveData源码分析 建立号viewModel后,我们在Activity中这样使用:
1 2 3 processViewModel.isBigScreen.observe(appCompatActivity, it -> { ... });
进入observe方法进行查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @MainThread public void observe (@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe" ); if (owner.getLifecycle().getCurrentState() == DESTROYED) { return ; } LifecycleBoundObserver wrapper = new LifecycleBoundObserver (owner, observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing != null && !existing.isAttachedTo(owner)) { throw new IllegalArgumentException ("Cannot add the same observer" + " with different lifecycles" ); } if (existing != null ) { return ; } owner.getLifecycle().addObserver(wrapper); }
通常我们使用setValue和postValue的方法进行数据更新 进入setValue下查看:
1 2 3 4 5 6 7 @MainThread protected void setValue (T value) { assertMainThread("setValue" ); mVersion++; mData = value; dispatchingValue(null ); }
进入dispatchingValue()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void dispatchingValue (@Nullable ObserverWrapper initiator) { if (mDispatchingValue) { mDispatchInvalidated = true ; return ; } mDispatchingValue = true ; do { mDispatchInvalidated = false ; if (initiator != null ) { considerNotify(initiator); initiator = null ; } else { for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break ; } } } } while (mDispatchInvalidated); mDispatchingValue = false ; }
便利订阅者集合,进行分发:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private void considerNotify (ObserverWrapper observer) { if (!observer.mActive) { return ; } if (!observer.shouldBeActive()) { observer.activeStateChanged(false ); return ; } if (observer.mLastVersion >= mVersion) { return ; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); }
在active的生命周期下,如果是onResume状态且是最新数据,则进行数据分发,否则,进入activeStateChanged方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void activeStateChanged (boolean newActive) { if (newActive == mActive) { return ; } mActive = newActive; boolean wasInactive = LiveData.this .mActiveCount == 0 ; LiveData.this .mActiveCount += mActive ? 1 : -1 ; if (wasInactive && mActive) { onActive(); } if (LiveData.this .mActiveCount == 0 && !mActive) { onInactive(); } if (mActive) { dispatchingValue(this ); } }
当不是active状态下,则不会进行分发处理,当页面从后台回到前台时,也会触发该方法,那么会取最新的mData并分发给该页面。
如果是post请求,会通过handler传递到主线程,调用setvalue方法,所有的回掉,observer方法都是在主线程中的