最近Kotlin的使用越来越普及,尤其是kotlin携程的使用,更是极大地简化了异步操作,尤其是网络请求,再也不怕线程切换了,从此告别接口回调,和RxJava,对是的,你没听错,暂时告别RxJava,只能说RxJava这把杀牛刀,被我们拿来杀鸡,确实有点大材小用。扯远了,下面开始进入正题,来看看Android的ViewModel的扩展变量,ViewModel.viewModelScope到底是如何在页面关闭的时候,自动关闭携程的(也就是我们的网络请求)。
我们在执行网络请求之前,一般都要先初始化ViewModel,代码如下
mViewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(tClass) as VM
lifecycle.addObserver(mViewModel)
注意了,看似不起眼的2行代码,可是后面完成自动取消的关键,我们一句一句来分析,先看第一句
mViewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(tClass) as VM
这里调用了ViewModelProvider的构造函数,我们点进去看看,这里也很重要
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
注意一点,此处调用了下面这行代码
owner.getViewModelStore()
owner即当前的Activity,的getViewModelStore方法,此处也很关键,我们点进去看一下,是ViewModelStoreOwner 接口
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
看一下,我们的BaseActivity的继承关系
BaseActivity > AppCompatActivity > FragmentActivity > ComponentActivity > ViewModelStoreOwner
我们点进去看一下就会发现,最终实现 getViewModelStore() 方法的是 ComponentActivity,如下
@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;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
这里主要的作用是初始化了 ViewModelStore ,传递给ViewModelProvider ,这个也很重要,后面会用到。好的,现在我们回到刚才的 mViewModel初始化的地方,就是刚才的第一句代码,还没说完,我们接着看。
mViewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(tClass) as VM
现在我们来看看,这个get方法
ViewModelProvider(x,x).get(tClass)
点进去以后
@NonNull
@MainThread
public T get(@NonNull Class 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 get(@NonNull String key, @NonNull Class 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 {
//因为我们使用的是默认的Factory,所以这里就不看了,以后如果需要自定义Factory的时候,这里就是我们自定义的Factory的方法
viewModel = (mFactory).create(modelClass);
}
//主要是这里,把viewModel存储在mViewModelStore里
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
上面的代码,主要干了一件事,就是实例化viewModel,并把viewModel存储在mViewModelStore里,这里我们顺便看一下ViewModelStore,这个类代码不多,也是后面自动解绑的关键
public class ViewModelStore {
当前页面的所有ViewModel都存储在这个map里,可能一般只有一个ViewModel
private final HashMap 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 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();
}
}
好的,至此我们的第一行初始化代码就讲完了,其实最主要的一件事情就是,把实例化的ViewMode放在了ViewModelStore的map里
下面我们开始分析第二句代码
lifecycle.addObserver(mViewModel)
这里的lifecycle实际上是调用的 FragmentActivity 的 getLifecycle() 方法
@NonNull
@Override
public Lifecycle getLifecycle() {
return mFragmentLifecycleRegistry;
}
mFragmentLifecycleRegistry在一开始就初始化了
final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);
传的 this 即 继承了 LifecycleOwner 的 FragmentActivity ,我们再看,第二句代码的后面一句 addObserve()方法
lifecycle.addObserver(mViewModel)
点进去看看
@MainThread
public abstract void addObserver(@NonNull LifecycleObserver observer);
是一个抽象方法,他的实现类是刚才我们才见过的 LifecycleRegistry,
我们进去看看
@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--;
}
其实这么多代码,只有一个地方,我们需要知道即可,就是把我们传进来的 observer 也就是ViewModel,放在了 mObserverMap 里面,这里后面马上也会说到。
至此,第二句代码也分析完了,主要是把ViewModel即观察者放在了mObserverMap里
一般我们的网络请求是在 ViewModel 里的,代码如下
block()即为我们的网络请求方法
viewModelScope.launch { block() }
viewModelScope 是 ViewModel 的扩展属性,这个是Google官方提供的,用它就对了,我们看一下这个扩展属性,看看它到底厉害在哪里
val ViewModel.viewModelScope: CoroutineScope
get() {
val scope: CoroutineScope? = this.getTag(JOB_KEY)
if (scope != null) {
return scope
}
return setTagIfAbsent(JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
}
internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
上述代码可以知道,在开启携程的时候,先创建了一个自定义的携程作用域 CloseableCoroutineScope 用于之后的取消携程,存储在ViewModel的 mBagOfTags里,记住这个 mBagOfTags,后面取消携程时,也是它。
internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
注意上面这个自定义的 CloseableCoroutineScope,它实现了Closeable接口,这里也很关键,并在 close() 方法里关闭了携程。
至此,启动携程的代码我们就讲完了,其实启动携程很简单,是不是感觉还没准备好就结束了,好吧,让我们直接开始高潮部分,到底viewModelScope是如何在页面关闭的时候,自动取消携程的
开始之前我们还是再看一眼Activity的继承关系,加深点印象
BaseActivity > AppCompatActivity > FragmentActivity > ComponentActivity > ViewModelStoreOwner
我们直接进到 FragmentActivity 的 onDestroy 方法里看一下页面关闭的时候做了什么
@Override
protected void onDestroy() {
super.onDestroy();
mFragments.dispatchDestroy();
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
我们看到,最后一行代码 ,mFragmentLifecycleRegistry 还记得吧,之前初始化的时候可是提到过的,在 getLifecycle() 方法里返回的就是它,在一开始就初始化了的。
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
这里就开始了,我们接着点进去看一下 handleLifecycleEvent 方法
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
State next = getStateAfter(event);
moveToState(next);
}
调用了 getStateAfter 返回了一个 State = DESTROYED,主要是调用了 moveToState,我们点进去看看
private void moveToState(State next) {
if (mState == next) {
return;
}
mState = next;
if (mHandlingEvent || mAddingObserverCounter != 0) {
mNewEventOccurred = true;
// we will figure out what to do on upper level.
return;
}
mHandlingEvent = true;
sync();
mHandlingEvent = false;
}
没什么好看的,继续往下看看 sync() 方法
private void sync() {
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
+ "garbage collected. It is too late to change lifecycle state.");
}
while (!isSynced()) {
mNewEventOccurred = false;
// no need to check eldest for nullability, because isSynced does it for us.
if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
backwardPass(lifecycleOwner);
}
Entry newest = mObserverMap.newest();
if (!mNewEventOccurred && newest != null
&& mState.compareTo(newest.getValue().mState) > 0) {
forwardPass(lifecycleOwner);
}
}
mNewEventOccurred = false;
}
这里会调用2个方法 backwardPass() 和 forwardPass() 其实这两个方法里面代码几乎一样,一个是从前往后找,一个是从后往前找,找什么,当然是找观察者了,LifecycleEventObserver,都存储在 mObserverMap 里,我们就看一个backwardPass() 方法
private void backwardPass(LifecycleOwner lifecycleOwner) {
Iterator> descendingIterator =
mObserverMap.descendingIterator();
while (descendingIterator.hasNext() && !mNewEventOccurred) {
Entry entry = descendingIterator.next();
ObserverWithState observer = entry.getValue();
while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
&& mObserverMap.contains(entry.getKey()))) {
Event event = downEvent(observer.mState);
pushParentState(getStateAfter(event));
observer.dispatchEvent(lifecycleOwner, event);
popParentState();
}
}
}
我们看到这行代码,在找到对应的观察者以后,开始回调了,event 是 DESTROYED
observer.dispatchEvent(lifecycleOwner, event);
那么,这个观察者 LifecycleEventObserver 到底在哪里注册的呢,之前初始化的时候,我们没说,因为这个不是我们初始化的,是系统代码初始化的,在 ComponentActivity 的构造函数里,有这么一段代码
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();
}
}
}
});
在onDestroy的时候会回调到这里,最主要的是调用了下面这句
getViewModelStore().clear();
还记得 getViewModelStore() 方法吗,刚才我们在初始化的时候可是见过啊,不记得的往上翻一下就看见了,所以这个时候 mViewModelStore 早已初始化过了,直接返回 mViewModelStore ,主要我们看一下 clear() 方法
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
是不是很熟悉,刚才初始化的时候,我们已经把ViewModel放在了,这个ViewModelStore 的 mMap里面,这个时候,在遍历ViewModel,并且调用其 vm.clear() 方法,我们进去看一下
@MainThread
final void clear() {
mCleared = true;
// Since clear() is final, this method is still called on mock objects
// and in those cases, mBagOfTags is null. It'll always be empty though
// because setTagIfAbsent and getTag are not final so we can skip
// clearing it
if (mBagOfTags != null) {
synchronized (mBagOfTags) {
for (Object value : mBagOfTags.values()) {
// see comment for the similar call in setTagIfAbsent
closeWithRuntimeException(value);
}
}
}
onCleared();
}
这里在遍历 mBagOfTags ,还记得刚开启携程的时候,在 viewModelScope 的扩展属性里,调用了 setTagIfAbsent 把当前的 CloseableCoroutineScope 传进来,存储在 mBagOfTags里吗,我们继续点进去看看 closeWithRuntimeException()方法
private static void closeWithRuntimeException(Object obj) {
if (obj instanceof Closeable) {
try {
((Closeable) obj).close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
最后调用的是 ((Closeable) obj).close(),还记得刚才我们开启携程的时候,说的吗 CloseableCoroutineScope 实现了 Closeable 接口,所以这里的 close() 方法最终会走到 CloseableCoroutineScope 的 close() 方法里
internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
最终在这里,关闭了携程 coroutineContext.cancel()。
至此,viewModelScope是如何做到自动解绑网络请求的,就分析完了,如有错误还请指正。
下面附上我自己画的时序图,没有用PowerDesign画的不是很好。