基本使用
-
这里借用官方的改造Java
Executors线程池的工程例程进行梳理,所以这里也印证了Kotlin协程(一)——之语言特性中所说的,协程本质还是线程框架 -
通过
viewModelScope.launch切换作用域,增加延时函数
fun updateTaps() { viewModelScope.launch { _tapCount++ delay(1_000) _taps.postValue("$_tapCount taps") } }
模拟网络请求
- kotlin 协程和
Retroft的结合使用将在下一篇文章演示,这里参照例子模拟本地请求
private fun refreshTitle() { viewModelScope.launch { try { _spinner.value = true repository.refreshTitle() } catch (error: TitleRefreshError) { _snackBar.value = error.message } finally { _spinner.value = false } } }
suspend fun refreshTitle() { withContext(Dispatchers.IO) { val result = try { network.fetchNextTitle().execute() } catch (cause: Throwable) { throw TitleRefreshError("Unable to refresh title", cause) }
if (result.isSuccessful) { wordDao.insert(Word(result.body()!!)) } else { throw TitleRefreshError("Unable to refresh title", null) } } }
// 这里通过拦截器用本地数据模拟网络请求 interface MainService {
@GET("next_title.json") fun fetchNextTitle(): Call
companion object { private const val BASE_URL = "http://localhost/"
fun create(): MainService { val logger = HttpLoggingInterceptor() logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder() .addInterceptor(logger) .addInterceptor(SkipNetworkInterceptor()) .build() return Retrofit.Builder() .baseUrl(BASE_URL) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() .create(MainService::class.java) } } }
@InstallIn(SingletonComponent::class) @Module object NetworkModule { ... @Provides @Singleton fun provideMainService(): MainService { return MainService.create() } }
优化网络请求
@GET("next_title.json") suspend fun fetchNextTitle(): String
suspend fun refreshTitle() { try { val result = network.fetchNextTitle() wordDao.insert(Word(result)) } catch (cause: Throwable) { throw TitleRefreshError("Unable to refresh title", null) } }
private fun refreshTitle() { launchDataLoad { repository.refreshTitle() } }
private fun launchDataLoad(block: suspend () -> Unit): Job = viewModelScope.launch { try { _spinner.value = true block() } catch (error: TitleRefreshError) { _snackBar.value = error.message } finally { _spinner.value = false } }
协程测试
// coroutineRule 是 TestWatcher的实现类,指定协程作用域 @Test fun testDefaultValues() = coroutineRule.runBlockingTest { viewModel.updateTaps() Truth.assertThat(viewModel.taps.getOrAwaitValue()).isEqualTo("0 taps") coroutineRule.testDispatcher.advanceTimeBy(1_000) Truth.assertThat(viewModel.taps.getOrAwaitValue()).isEqualTo("1 taps") viewModel.updateTaps() coroutineRule.testDispatcher.advanceTimeBy(1_000) Truth.assertThat(viewModel.taps.getOrAwaitValue()).isEqualTo("2 taps") }
- 网络测试
- 和
Retroft一起梳理
相关知识点
知识点一: Kotlin协程使用调度器确定线程 ,调用
withContext()来创建一个在指定线程中运行的代码块
- Dispatchers.Main - 使用此调度器可在 Android 主线程上运行协程。
- Dispatchers.IO - 此调度器经过了专门优化,适合在主线程之外执行磁盘或网络 I/O
- Dispatchers.Default - 此调度器经过了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作,默认调度器