Coroutine 学习(二)ViewModelScope LifeCycleScope Dispatcher
问题:
koin如何创建ViewModel?
ViewModelScope和LifeCycleScope的最佳使用方式是什么?
ViewModel和Repository使用方式是什么 各自的职责是什么?
Room和ViewModel应该如何配合使用
单独使用supsend函数,suspend函数表示的协程和它所在的CoroutineScope的生命周期相同吗?
我们所使用的Dispatchers.Main IO 是一个【单例】吗?

Koin
首先需要明确module, Service, scope这些概念和我们之前所了解的都不同,在谈及Koin的上下文时,这些都是Koin定义的概念
Koin使用步骤
Koin是一种实现依赖注入的方式,使用的时候需要遵循的步骤
定义KoinModule
2. 在application中注册:
Service的创建:
factory single viewModel都可以创建Service到Module中

生命周期
Service的创建方式还指定了Service的生命周期。可以自定义Scope的生命周期
依赖注入方式:
1. get
定义在module中的类需要参数,可以通过get声明参数。Koin会在module中寻找是否存在对应的Service
在其他地方也可以通过get方法获取实例:
2. 懒加载inject

在Android中使用协程的最佳做法:
https://developer.android.google.cn/kotlin/coroutines/coroutines-best-practices?hl=zh-cn

在Android ViewModel中使用协程的最佳方式
在ViewModel中使用协程的一个方式是使用viewModelScope,因为遵循了结构化并发思想。
结构化并发:
内容:使得每一个协程都运行在指定的CoroutineScope中
为什么要这么做:
是我们的每一个suspend、协程都不会产生lost or leak
保证所有的异常都能够正确的处理
对于lost和leak的理解:
因为所有的协程的生命都在一个上下文中,所以只要管理好上文的Scope,内部的协程也可以被管理,当关闭父协程(外面的scope)时,内部的子协程也会被关闭。
ViewModel的生命周期

ViewModel的生命周期和创建它时传入的LifeCycle组件的生命周期有关。使用viewScope我们能在viewScope中开启协程也不用担心内存泄漏:
viewModelScope = SupervisorJob + Dispatchers.Main.immediate
当ViewModel生命周期走到尽头时,会调用clear方法其中又会调用closeWithRuntimeException。因为viewModelScope又是一个CloseCoroutineScope,所以可以使用closeWithRuntimeException方法关闭。Dispatchers.Main.immediate判断如果当前在主线程,立马执行协程,不会通过Dispatcher再分发。

对于ViewModel职责的理解
ViewModel应该是连接View和Model的桥梁。所以viewModelscope是在Main调度器上运行。
如果在ViewModelScope中出现了异常,应该选择就地捕获异常
src:https://developer.android.google.cn/kotlin/coroutines/coroutines-best-practices?hl=zh-cn

在协程中使用viewModelScope的方式
https://medium.com/androiddevelopers/easy-coroutines-in-android-viewmodelscope-25bffb605471

Dipatcher:
协程中的Dispatchers.main Dispatchers.IO Dispatchers.default 这些会创建单例,还是每次调用都创建不同的实例?
Dispatchers.Main:

以上是Dispacthers.Main的构建过程。Dispatcher.Main在文档中的描述的特点是:该协程调度器被限定在了主线程中,可以和UI对象进行交互。
MainDispatcherLoader
MainDispatcherLoader类是一个object,也就是说这个类是一个天生的单例。MainDispatcherLoader通过loadMainDispatcher创建了dispatcher。
接下来调用了MainDispatcherFactory的方法创建Dispacther
。MainDispatcherFactory的实现类只有AndroidDispatcherFactory一个。在AndroidDispatcherFatctory的重写方法中,我们发现真正的返回对象是HandlerContext:

HandlerContext其中一个参数就是通过主线程的Looper构建的Handler实例。所以其实现在已经可以得出结论,每次调用Dispatchers.Main都会创建一个新的HandlerContext对象。我们通过这个Handler对象和主线程进行交互。特别是可以看看这里的dispatch方法:
其他的Dispatcher也是类似的,所以我们可以在Koin Module中使用factory模块生成Dispatcher的Service。
总结:
理解协程首先需要理解什么叫做结构性并发。结构性并发保证了所有的协程、挂起函数都能被CoroutineScope管理生命周期。
创建一个协程会继承CoroutineScope中的内容,但是如果指定了Dispatchers.Main或者其他的Dispatchers.IO 这里不存在【单例】或者是【复用】机制,会重新创建一个Dispacthers的实例。