Kotlin协程(二)之——在Android当中应用

53 阅读1分钟

基本使用

  1. 这里借用官方的改造Java Executors线程池的工程例程进行梳理,所以这里也印证了Kotlin协程(一)——之语言特性中所说的,协程本质还是线程框架

  2. 通过viewModelScope.launch 切换作用域,增加延时函数

fun updateTaps() { viewModelScope.launch { _tapCount++ delay(1_000) _taps.postValue("$_tapCount taps") } }

模拟网络请求

  1. 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") }

  1. 网络测试
  • Retroft一起梳理

相关知识点

知识点一: Kotlin协程使用调度器确定线程 ,调用 withContext() 来创建一个在指定线程中运行的代码块

  • Dispatchers.Main - 使用此调度器可在 Android 主线程上运行协程。
  • Dispatchers.IO - 此调度器经过了专门优化,适合在主线程之外执行磁盘或网络 I/O
  • Dispatchers.Default - 此调度器经过了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作,默认调度器