美文网首页
在 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