相关博客参考
Lifecycle源码解析:https://juejin.im/post/6847902220755992589#heading-13
LiveData源码解析:https://juejin.im/post/6844903796657782791
ViewModel源码解析:https://juejin.im/post/6844904169401221134
一 简介
Lifecycle 是 Jetpack 整个家族体系内最为基础的内容之一,为上层的LiveData、ViewModel等等更上层的组件提供监听 Activity、Fragment、Service、甚至 Process 的生命周期变化的统一方式。
LiveData 是 Jetpack 家族的一种响应式开发框架,类似框架有还RxJava等。以数据驱动的方式更新UI,并且由于其基于Livecycle,能够感知组件生命周期变化,只会更新活跃的组件的状态,并在组件销毁时能自动解除对该组件的监听。
ViewModel: Activity或Fragment支持以数据以ViewModel的形式存储在内部,于是ViewModel常常作为组件相关的多个LiveData的存储载体。ViewModel 里面的数据不会因为屏幕的旋转或者其他配置(比如切换到多窗口模式)而丢失。
LiveData
一、LiveData简介
LiveData是google官方架构JetPack系列的一个响应式开发框架,LiveData是一个可以被观察的数据持有者类。说到响应式开发或者说观察者就不免想到RxJava,RxJava将观察者模式运用的炉火纯青。但LiveData和RxJava的定位是不一样的,LiveData主要用于搭建MVVM架构,并在其中作为数据持有者,LiveData能监听组件的生命周期变化,这样一来只会更新处于活跃状态的组件。
LiveData的特点:
1)采用观察者模式自动提示UI更新。
2)不需要手动处理生命周期,不会因为Activity的销毁重建而丢失数据。
3)不会出现内存泄漏。
4)不需要手动取消订阅,Activity在非活跃状态下(销毁、finish之后)不会收到数据更新信息。
二、LiveData用法
1)LiveData往往结合于ViewModel使用,对于ViewModel的分析之前已经进行分析了,这里不再过多描述。首先在ViewModel中创建LiveData,代码如下:
class MainViewModel : ViewModel() {
private val repertory: MainRepository by lazy {
MainRepository()
}
var data: MutableLiveData = MutableLiveData()
fun getDataFromServer() {
repertory.getDataFromServer(data)
}
}
这里采用的是MutableLiveData,它是LiveData的实现类,LiveData是一个抽象类。
2)在Activity中观察LiveData的数据变化。代码如下:
class MainActivity : AppCompatActivity() {
private lateinit var mModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initData()
}
private fun initData() {
mModel = ViewModelProviders.of(this)[MainViewModel::class.java]
mModel.data?.observe(this, Observer {
val mainAdapter = MainAdapter(this, it)
val linearLayoutManager = LinearLayoutManager(this)
rv.layoutManager = linearLayoutManager
rv.adapter = mainAdapter
})
mModel.getDataFromServer()
}
}
3)对LiveData进行赋值,代码如下:
fun postData() {
mModel.data.postValue(JsonBean(ArrayList(), 0, ""))
}
三、源码分析
1)首先先从实例化MutableLiveData入手,MutableLiveData是LiveData的实现类,源码如下:
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
从代码中可以看到,LiveData是一个泛型类,泛型参数就是存储数据的实际类型,同时MutableLiveData提供两个赋值方法:postValue和setValue,而这两个方法直接调用父类中的方法。所以看一下父类中这两个方法的具体实现
setValue方法必须在主线程调用,调用只有LiveData就持有新的数据了。
postValue方法同样是更新LiveData持有的数据,但区别在于postValue方法是单独采用Runnable通过主线程handler发送给主线程更新数据,这样一来postValue就可以在异线程更新数据了。其实postValue最终更新数据还是走的setValue方法。
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
2)分析在Activity中订阅LiveData的方法observe,此方法接收两个参数,一个LifecycleOwner和Observer,代码如下:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
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);
}
从中我们可以发现方法首先会判断当前视图状态是否已经是”DESTROYED“状态,在分析订阅方法之前先分析一下LifecycleOwner这个接口。
public interface LifecycleOwner {
/**
* Returns the Lifecycle of the provider.
*
* @return The lifecycle of the provider.
*/
@NonNull
Lifecycle getLifecycle();
}
在这个接口中只有一个方法用于返回Lifecycle。查看一下接口的实现类可以发现v4和v7包下的Acvitity和Fragment都实现了这个接口。接下来看一下Lifecycle这个抽象类。
public abstract class Lifecycle {
@MainThread
public abstract void addObserver(@NonNull LifecycleObserver observer);
@MainThread
public abstract void removeObserver(@NonNull LifecycleObserver observer);
@MainThread
@NonNull
public abstract State getCurrentState();
.....省略部分代码
}
类中定义了添加和移除订阅者的方法,同时还包括订阅者的生命周期状态信息。而Lifecycle的唯一实现类是LifecycleRegistry,代码如下。
public class LifecycleRegistry extends Lifecycle {
private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap = new FastSafeIterableMap<>();
private final WeakReference<LifecycleOwner> mLifecycleOwner;
private int mAddingObserverCounter = 0;
private boolean mHandlingEvent = false;
private boolean mNewEventOccurred = false;
private ArrayList<State> mParentStates = new ArrayList<>();
public LifecycleRegistry(@NonNull LifecycleOwner provider) {
mLifecycleOwner = new WeakReference<>(provider);
mState = INITIALIZED;
}
......省略部分代码
private boolean isSynced() {
if (mObserverMap.size() == 0) {
return true;
}
State eldestObserverState = mObserverMap.eldest().getValue().mState;
State newestObserverState = mObserverMap.newest().getValue().mState;
return eldestObserverState == newestObserverState && mState == newestObserverState;
}
private State calculateTargetState(LifecycleObserver observer) {
Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
State siblingState = previous != null ? previous.getValue().mState : null;
State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
: null;
return min(min(mState, siblingState), parentState);
}
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
if (previous != null) {
return;
}
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
// it is null we should be destroyed. Fallback quickly
return;
}
boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
popParentState();
// mState / subling may have been changed recalculate
targetState = calculateTargetState(observer);
}
if (!isReentrance) {
// we do sync only on the top level.
sync();
}
mAddingObserverCounter--;
}
private void popParentState() {
mParentStates.remove(mParentStates.size() - 1);
}
private void pushParentState(State state) {
mParentStates.add(state);
}
@Override
public void removeObserver(@NonNull LifecycleObserver observer) {
mObserverMap.remove(observer);
}
@NonNull
@Override
public State getCurrentState() {
return mState;
}
static State getStateAfter(Event event) {
switch (event) {
case ON_CREATE:
case ON_STOP:
return CREATED;
case ON_START:
case ON_PAUSE:
return STARTED;
case ON_RESUME:
return RESUMED;
case ON_DESTROY:
return DESTROYED;
case ON_ANY:
break;
}
throw new IllegalArgumentException("Unexpected event value " + event);
}
private static Event downEvent(State state) {
switch (state) {
case INITIALIZED:
throw new IllegalArgumentException();
case CREATED:
return ON_DESTROY;
case STARTED:
return ON_STOP;
case RESUMED:
return ON_PAUSE;
case DESTROYED:
throw new IllegalArgumentException();
}
throw new IllegalArgumentException("Unexpected state value " + state);
}
private static Event upEvent(State state) {
switch (state) {
case INITIALIZED:
case DESTROYED:
return ON_CREATE;
case CREATED:
return ON_START;
case STARTED:
return ON_RESUME;
case RESUMED:
throw new IllegalArgumentException();
}
throw new IllegalArgumentException("Unexpected state value " + state);
}
.....省略部分代码
}
先来看一下主要的成员变量mObserverMap和mLifecycleOwner,mObserverMap是一个Map结构,以观察者为key存储观察者状态。mLifecycleOwner是一个弱引用,持有LifecycleOwner,其实LifecyleOwner就是Activity或者Fragment。前面说到过Activity中会实现LifecycleOwner接口,其实追踪到源码发现SupportActivity实现了LifecycleOwner接口,同时声明变量LifecycleRegistry,代码如下:
private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
由此一来LifecycleRegistry就持有Activity的弱引用了,这样一来既能监听Activity的生命周期同时也不会造成内存泄漏。接下来看关键的订阅和取消订阅方法,取消订阅很简单就是将观察者移除Map集合,订阅方法会先校验观察者的生命周期状态,同时从软引用中获取LifecycleOwner,如果为空的话则说明界面已经被销毁了,则不需要进行订阅了。否则进行订阅操作。 现在回到前面继续分析LiveData的订阅操作,订阅操作会将owner和observer统一包装成LifecycleBoundObserver,这是Lifecycle真正的订阅者。
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
类中封装了对于Lifecycle的状态赋值操作和状态改变对观察者进行取消订阅操作。最后将LifecycleBoundObserver传入LifecycleRegistry完成订阅。整体的订阅流程就分析完了。
3)Observer响应获取数据变化流程分析。 分析完订阅流程接下来分析LiveData如何响应数据变化通知给订阅者,这里需要从setValue方法入手。
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
private 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<T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
调用setValue方法后会调用dispatchingValue方法循环通知订阅者响应数据变化。
三、LiveData特点原理总结
1)采用观察者模式自动提示UI更新: 由于采用订阅方式获取数据变化所以自动获取数据更新。
2)不需要手动处理生命周期,不会因为Activity的销毁重建而丢失数据: 会自动重新订阅。
3)不会出现内存泄漏: Lifecycle持有的是Activity(Fragment)的弱引用。
4)不需要手动取消订阅,Activity在非活跃状态下(销毁、finish之后)不会收到数据更新信息: LifecycleRegistry会回调Activity的状态,在onDestory之后LiveData自动取消订阅。
四、核心原理
1)observe做为入口,使用LifecycleBoundObserver把观察者和被观察者包装在一起绑定wrapper作为观察者
2)绑定完成后,使用setValue与postValue通知观察者
3)setValue中
dispatchingValue(null)
if (initiator != null)
参数传null和不传null的区别就是如果传null将会通知所有的观察者,反之仅仅通知传入的观察者。
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
通知所有的观察者通过遍历 mObservers ,将所有的 ObserverWrapper 拿到,实际上就是我们上面提到的 LifecycleBoundObserver,通知观察者调用considerNotify()方法,这个方法就是通知的具体实现了。
considerNotify()
先用2个if判断出被观察者对应的activity状态是否为显示
发送通知 onChanged()被调用
4) postValue中 切换线程到主线程中去执行setValue
ViewModel
一 概述
ViewModel 在Activity或者Fragment生命周期内只有一个的存储数据。ViewModel 里面的数据不会因为屏幕的旋转或者其他配置(比如切换到多窗口模式)而丢失。但是在正常的finish()或者按返回键的时候,在Activity或者Fragment走到onDestroy的时候回清除ViewModel里面的数据,避免内存泄漏。虽然屏幕旋转Activity也会走onDestroy,但是会判断是否是因为屏幕旋转而导致的。所以ViewModel是一个很合格的存储数据的类
二 ViewModel生命周期
ViewModel 对象存在的时间比Activity的生命周期要长,禁止在ViewModel的持有Activity、Fragment、View等对象,这样会引起内存泄漏。如果需要在ViewModel中引用Context的话,google为我们提供了AndroidViewModel 类来供我们使用。
三 ViewModel的好处
- 不会因为屏幕旋转或者其他配置改变(比如切换到多窗口模式)而销毁,避免数据重新创建,比如网络数据重新加载的情况
- 当Activity或者Fragment的正常销毁的时候,自动清除数据,也就是绑定了Activity或者Fragment的生命周期,避免了内存泄漏,
- 多个Fragment之间或者Activity和Fragment之间更好地传递数据,进行交互
- 减少Activityu或者Fragment的压力,Activityu或者Fragment的只是显示数据的界面,帮助Activity和Fragment处理一些数据逻辑
- 也可以new ViewModle的,new出来的 基本上就没有ViewModle的特性了。相当于一个成员属性了
Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的情况。Activity和Fragment的之间互相调用,下面是一个Activity和两个Fragment之间的互相调用
3.1.1 构建一个Avtivity
class ViewModelDemoActivity : AppCompatActivity() {
// 创建以Activity为维度的ViewModel
private val viewModel: DemoViewModel by lazy { ViewModelProvider(this).get(DemoViewModel::class.java) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var binding = DataBindingUtil.setContentView<ActivityViewmodelDemoBinding>(
this,
R.layout.activity_viewmodel_demo
)
viewModel.dataLive.observe(this, object : Observer<String> {
override fun onChanged(s: String?) {
// 当横竖屏变换时,会重新走这里,毕竟是View也都重新绘制了,只不过user里面立马有值
tv_name.text = s
}
})
tv_name.setOnClickListener {
// activity 里面的点击去改变值
viewModel.dataLive.value = "Activity触发的改变"
}
viewModel.getName()
}
companion object {
fun startMe(activity: Activity) {
activity.startActivity(Intent(activity, ViewModelDemoActivity::class.java))
}
}
}
3.1.2 ViewModel的代码
class DemoViewModel : ViewModel() {
val dataLive: MutableLiveData<String> =
MutableLiveData<String>()
fun getName(){
viewModelScope.launch {
delay(1000)
dataLive.value = "王者荣耀"
}
}
}
3.1.3 布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ED6E6E"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<fragment
android:id="@+id/one"
android:name="com.nzy.mvvmsimple.viewmodel.ShareOneFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="@+id/guidline"
app:layout_constraintTop_toBottomOf="@+id/tv_name" />
<fragment
android:id="@+id/two"
app:layout_constraintTop_toBottomOf="@+id/tv_name"
android:name="com.nzy.mvvmsimple.viewmodel.ShareTwoFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="@+id/guidline"
app:layout_constraintRight_toRightOf="parent"
/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
意: 两个Fragment获取ViewModel的维度,要以Activity为维度
class ShareOneFragment : Fragment() {
// 创建以Activity为维度的ViewModel,注意 这里是 requireActivity() 不是 getActivity(),requireActivity()不可能为空,getActivity()有可能为空
private val viewModel: DemoViewModel
by lazy { ViewModelProvider(requireActivity()).get(DemoViewModel::class.java) }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_share_one, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// 这里传入是 viewLifecycleOwner(getViewLifecycleOwner()),而不会Fragment本身
viewModel.dataLive.observe(viewLifecycleOwner, Observer {
tv_name_one.text = it
})
// 在 FragmentOne 中去改变值
tv_one.setOnClickListener {
viewModel.dataLive.value = "Fragment-One,改变的值"
}
}
companion object {
@JvmStatic
fun newInstance() =
ShareOneFragment()
}
}
可以发现很轻松的通过这个来实现数据的共享更改,再利用databinding实现ui的更新
四 ViewModel 和 onSaveInstanceState 区别
4.1 ViewModel
-
缓存在内存中的,相当于本地缓存和网络缓存读写比较快
-
可以存较大的值,比如bitmap、大对象等等
-
数据绑定了Activity或者Fragment的生命周期,当Activity正常关闭的时候,都会清除ViewModel中的数据.比如
-
调用finish()
-
按返回键退出,
-
用户直接杀进程或者是放后台内存不足,被回收了
-
-
在Activity旋转或者其他配置改变的时候,ViewModel里面是还有值得,不会销毁,
-
ViewModel也可以使用本地存储,通过SavedStateHandle实现的,使用SavedStateViewModelFactory这个工厂,这里就不多介绍了,已经是正式版本了,引用是
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0
4.2 onSaveInstanceState
- 仅适合可以序列化再反序列化的少量数据
- 不适合数量可能较大的数据,如用数组或Bitmap。可以存一些简单的基本类型和简单的小对象、例如字符串,和一些id
- 会把数据存储到磁盘上
注意 对于复杂的大型数据,请使用 数据库 或者 SharedPreferences
五 ViewModel源码解析
5.1 源码
ViewModel的源码很少,基本上就是一个map 里面用来存储关于协程和SavedStateHandleController,onCleared() 方法是供我们自己调用,就是当Activity或者Fragmengt的关闭的时候,需要清理一些资源,比如Rxjava的流
//来存储 一些东西,当Activity 关闭的时候 会清除这里的数据
private final Map<String, Object> mBagOfTags = new HashMap<>();
private volatile boolean mCleared = false;
//来存储 一些东西,当Activity 关闭的时候 自己实现去清楚一些数据,比如Rxjava中的流
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
5.1.1 获得ViewModelProvider
private val viewModel: DemoViewModel by lazy { ViewModelProvider(this).get(DemoViewModel::class.java) }
看ViewModelProvicder的构造方法
//创建一个ViewModelProvider , 用来创建ViewModels的,并将其保留在给定ViewModelStoreOwner的存储区中,如果owner是 HasDefaultViewModelProviderFactory 的子类,就用HasDefaultViewModelProviderFactory的工厂,像Fragment 和 ComponentActivity 都是实现了HasDefaultViewModelProviderFactory的接口
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;
}
上面默认的方法是; 用来创建ViewModels的,并将其保留在给定ViewModelStoreOwner的存储区中,如果owner是 HasDefaultViewModelProviderFactory 的子类,就用HasDefaultViewModelProviderFactory的工厂,像Fragment 和 ComponentActivity(是FragmentActivity的爹,AppCompatActivity的爷爷) 都是实现了HasDefaultViewModelProviderFactory的接口,获取到的Frctory是 SavedStateViewModelFactory。 否则就用NewInstanceFactory去创建ViewModel,比如需要我们在ViewModel中传递参数的时候,我们可以写自己的Factory继承NewInstanceFactory,走我们自己方法Create()
5.1.1.1 ComponentActivity中获取Factory的方法
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
// 看这个activity是否已经attache到application
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 (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
5.1.1.2 Fragment中获取Factory的方法
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
requireActivity().getApplication(),
this,
getArguments());
}
return mDefaultFactory;
}
5.1.2 自己定义的Factory
private val viewModel:UserViewModel by lazy { ViewModelProvider(this,UserViewModelFactory(repository)).get(UserViewModel::class.java) }
class UserViewModelFactory(
private val repository: UserRepository
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
// 传入一个 Repository 参数
return UserViewModel(repository) as T
}
}
5.1.3 ViewModelStoreOwner: 存储ViewModel的拥有者
Fragment 和 ComponentActivity(是FragmentActivity的爹,AppCompatActivity的爷爷)都实现了 ViewModelStoreOwner 这个接口,
public interface ViewModelStoreOwner {
// ViewModelStore 是用来存储 ViewModel的实例的
@NonNull
ViewModelStore getViewModelStore();
}
5.1.3.1 ComponentActivity中的获得 ViewModelStroe 的方法
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实例,NonConfigurationInstances整个activity都装在里面了,NonConfigurationInstances是跟配置改变没有关系的一个实例。
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
//从NonConfigurationInstances 恢复 ViewModelStore
mViewModelStore = nc.viewModelStore;
}
// 如果为null,证明从来没有创建过,重新new 出来
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
5.1.3.2 在看一下ComponentActivity:: onRetainNonConfigurationInstance
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// 如果是null,说明以前没有调用过 getViewModelStore()方法,也就是没有调用过ViewModelProvider(requireActivity()).get(DemoViewModel::class.java)的方法来获取 ViewModel。所以我们看一下最后一个的NonConfigurationInstance里面是否存在viewModelStore
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// 若果nc 不等于null,就证明以前存储过,所以从这里取出来
viewModelStore = nc.viewModelStore;
}
}
// custom这个返回null,子类也没重写他的方法,所以是必须是null
if (viewModelStore == null && custom == null) {
return null;
}
// 如果viewModelStore不是null,也就是说最后一个NonConfigurationInstance里面有值,直接new出来NonConfigurationInstances并赋值,返回出去
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
然后看看 NonConfigurationInstances类,是ComponentActivity的一个静态内部类,用来存储viewModelStore的,无论配置是否改变,这个类的实例不会改,里面的ViewModelStore不会消失
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
5.1.3.3 retainNonConfigurationInstances 方法执行来存贮NonConfigurationInstances,返回结果就是NonConfigurationInstances,同时把NonConfigurationInstances存储到ActivityClientRecord中去,ActivityClientRecord是一个Activity的记录本。之后在Activity的Attach的时候,会把NonConfigurationInstances赋值给成员变量
在Activity调用onDestroy的之前会调用activity的retainNonConfigurationInstances
NonConfigurationInstances retainNonConfigurationInstances() {
....
}
总结一下:
- 先通过NonConfigurationInstances来拿ViewModelStore,NonConfigurationInstances是一个静态内部类,不会因为配置改变(比如屏幕旋转),而重新创建
- 如果NonConfigurationInstances没有拿到,证明这就是个新的ViewModelStore,所以直接走创建ViewModelStore流程
5.1.4 ViewModelStore 用来存储ViewModel的容器,,里面有个HashMap,用来存储ViewModel的,存储的key下面会讲到
public class ViewModelStore {
// 这个就是存储ViewModel的Hashmap
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());
}
// 清除viewmodel的里面的东西
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
5.1.5 获得ViewModel
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
// 获得 viewmodel这个类的全限定名
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
// 用一个DEFAULT_KEY常量 + 一个这个类的全限定名当做key
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
继续看get(String,Class) 方法
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
// 你可以认为mViewModelStore就是个map,上面也讲了,其实它里面就是一个map来存储ViewModel的
// 从map里面拿到 拿到这个 ViewModel
ViewModel viewModel = mViewModelStore.get(key);
// viewModel 这个对象是否可以转化成这个类,如果 viewModel 是null的话,这里也返回false
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.
}
}
// mFactory 如果不是自己实现的话,那就是SavedStateViewModelFactory 实现于 KeyedFactory,所以第一次拿的时候 ,走到这里
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
// 把获取到的ViewModel缓存到HashMap中
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
5.1.6 在什么时候清除ViewModel
当 ComponentActivity 的构造方法中有以下代码,当Activity走到destroy的时候清楚ViewModel,里面有个isChangingConfigurations方法,表示 是否是配置改变引起的(比如 Activity屏幕旋转),如果是就不清除。
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
总结:
数据恢复原理
1、ComponentActivity
onRetainNonConfigurationInstance()保存状态 转屏时自动调用
getLastNonConfigurationInstance()恢复状态
2、获取viewModel
model = ViewModelProviders.of(getActivity()).get(NameViewModel.class);
3、ViewModelProviders.of()
保存了ViewModelStore和Factory并返回ViewModelProvider
参数1:getViewModelStore()方法中
从Activity的NonConfigurationInstances中取ViewModelStore,取不到就new一个
参数2:Factory中反射生成ViewModel实例
4、Activity在横竖屏切换时悄悄保存了viewModelStore,放到了NonConfigurationInstances实例里面,横竖屏切换时保存了又恢复了回来,相当于ViewModel实例就一直在,也就避免了横竖屏切换时的数据丢失.
5、public ComponentActivity() 构造方法中clear()