建议大家可以对着文章末尾的时序图(画的不咋的)一起看会比较好理解,下面开始吧
最近Kotlin的使用越来越普及,尤其是kotlin协程的使用,更是极大地简化了异步操作,尤其是网络请求,再也不怕线程切换了,从此告别接口回调,和RxJava,对是的,你没听错,暂时告别RxJava,只能说RxJava这把杀牛刀,被我们拿来杀鸡,确实有点大材小用。扯远了,下面开始进入正题,来看看Android的ViewModel的扩展变量,ViewModel.viewModelScope到底是如何在页面关闭的时候,自动关闭协程的(也就是我们的网络请求)。
一、初始化
我们在执行网络请求之前,一般都要先初始化ViewModel,代码如下
mViewModel = ViewModelProvider(this,ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(tClass) as VM
注意了,看似不起眼的1行代码,可是后面完成自动取消的关键,我们慢慢来分析
这里调用了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 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 {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
//因为我们使用的是默认的Factory,所以这里就不看了,以后如果需要自定义Factory的时候,这里就是我们自定义的Factory的方法
viewMode