美文网首页
在 Android 应用中使用 Kotlin 协程 - 官方示例

在 Android 应用中使用 Kotlin 协程 - 官方示例

作者: 行走中的3卡 | 来源:发表于2022-10-26 10:01 被阅读0次

前文参考:
在 Android 应用中使用 Kotlin 协程 - 官方示例详解
在 Android 应用中使用 Kotlin 协程 - 官方示例详解(2)

1. Room 中的协程

MainDatabase.kt 中将 insertTitle 设置为挂起函数

// add the suspend modifier to the existing insertTitle

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTitle(title: Title)

分析:
执行此操作后,Room 会让查询具有主线程安全性,并自动在后台线程上执行此查询。
不过,这也意味着您只能从协程内调用此查询。

2. Retrofit 中的协程

MainNetwork.kt 将 fetchNextTitle 设置为 挂起函数.
将返回值类型从 Call<String> 更改为 String。

挂起函数支持需要 Retrofit 2.6.0 或更高版本。

// add suspend modifier to the existing fetchNextTitle
// change return type from Call<String> to String

interface MainNetwork {
   @GET("next_title.json")
   suspend fun fetchNextTitle(): String
}

分析:
(1) 为函数添加挂起修饰符
(2) 返回值类型中移除 Call 封装容器

Retrofit 将 自动使挂起函数具有 主线程安全性
以便直接从 Dispatchers.Main 调用它们

Room 和 Retrofit 均会让挂起函数具有主线程安全性。
尽管这些挂起函数从网络中提取数据并将数据写入数据库,
您可以安全地从 Dispatchers.Main 调用这些函数。

Room 和 Retrofit 都使用自定义调度程序,而不使用 Dispatchers.IO。
Room 会使用已配置的默认查询和事务 Executor 运行协程。
Retrofit 将在后台创建新的 Call 对象,并对其调用队列以异步发送请求。

3. 使用 Room 和 Retrofit

TitleRepository.kt
原始:

// interact with *blocking* network and IO calls from a coroutine
withContext(Dispatchers.IO) {
    val result = try {
        // Make network request using a blocking call
       network.fetchNextTitle().execute()
    } catch (cause: Throwable) {
        // If the network throws an exception, inform the caller
        throw TitleRefreshError("unable to refresh title", cause)
    }

    if (result.isSuccessful) {
        // Save it to database
        titleDao.insertTitle(Title(result.body()!!))
    } else {
        // If it's not successful, inform the callback of the error
        throw TitleRefreshError("unable to insert title", null)
    }
}

修改后:

suspend fun refreshTitle() {
   try {
       // Make network request using a blocking call
       val result = network.fetchNextTitle()
       titleDao.insertTitle(Title(result))
   } catch (cause: Throwable) {
       // If anything throws an exception, inform the caller
       throw TitleRefreshError("Unable to refresh title", cause)
   }
}

分析:
(1) 依赖挂起和恢复操作会使代码大幅缩短

network.fetchNextTitle().execute() --> network.fetchNextTitle()
titleDao.insertTitle(Title(result.body()!!)) -> titleDao.insertTitle(Title(result))
且删除了 result 是否为空、是否成功的判断
(2) 去掉了 withContext
由于 Room 和 Retrofit 都提供主线程安全挂起函数,
因此可以安全地通过 Dispatchers.Main 安排此异步工作

4. 修正编译器错误

转用协程确实涉及更改函数的签名,因为无法通过常规函数调用挂起函数。

4.1 TestingFakes.kt

(1) TitleDaoFake 添加 suspend 到 fun insertTitle()
(2) MainNetworkFake
原始:

 override suspend fun fetchNextTitle() = MakeCompilerHappyForStarterCode() // TODO: replace with `result`

修改后

override suspend fun fetchNextTitle() = result // TODO: replace with `result`

修改 MainNetworkCompletableFake
原始:

override suspend fun fetchNextTitle() = MakeCompilerHappyForStarterCode() // TODO: replace with `completable.await()`

修改后

    override suspend fun fetchNextTitle() = completable.await() // TODO: replace with `completable.await()`

--End--

相关文章

网友评论

      本文标题:在 Android 应用中使用 Kotlin 协程 - 官方示例

      本文链接:https://www.haomeiwen.com/subject/jyrgzrtx.html