首页 > 解决方案 > 如何在 Kotlin 中使用 Fuel 和协程?

问题描述

我想获取 API 请求并将请求的数据保存到数据库。还想返回数据(即写入 DB)。我知道,这在 RxJava 中是可能的,但现在我用 Kotlin 协程编写,目前使用 Fuel 而不是 Retrofit(但差异不是很大)。我读了 How to use Fuel with a Kotlin coroutine,但不明白。

如何编写协程和方法?

更新

比如说,我们有一个 Java 和 Retrofit,RxJava。然后我们可以写一段代码。

区域响应:

@AutoValue
public abstract class RegionResponse {
    @SerializedName("id")
    public abstract Integer id;
    @SerializedName("name")
    public abstract String name;
    @SerializedName("countryId")
    public abstract Integer countryId();

    public static RegionResponse create(int id, String name, int countryId) {
        ....
    }
    ...
}

地区:

data class Region(
    val id: Int,
    val name: String,
    val countryId: Int)

网络:

public Single<List<RegionResponse>> getRegions() {
    return api.getRegions();
    // @GET("/regions")
    // Single<List<RegionResponse>> getRegions();
}

区域存储库:

fun getRegion(countryId: Int): Single<Region> {
    val dbSource = db.getRegion(countryId)
    val lazyApiSource = Single.defer { api.regions }
            .flattenAsFlowable { it }
            .map { apiMapper.map(it) }
            .toList()
            .doOnSuccess { db.updateRegions(it) }
            .flattenAsFlowable { it }
            .filter({ it.countryId == countryId })
            .singleOrError()
    return dbSource
            .map { dbMapper.map(it) }
            .switchIfEmpty(lazyApiSource)
}

区域交互器:

class RegionInteractor(
    private val repo: RegionRepository,
    private val prefsRepository: PrefsRepository) {

    fun getRegion(): Single<Region> {
        return Single.fromCallable { prefsRepository.countryId }
                .flatMap { repo.getRegion(it) }
                .subscribeOn(Schedulers.io())
    }
}

标签: androidkotlinkotlin-coroutines

解决方案


让我们一层一层的看。

首先,据我所知,您的RegionResponseRegion完全适合这个用例,所以我们根本不会碰它们。

您的网络层是用 Java 编写的,因此我们假设它总是期望同步行为,并且也不会触及它。

所以,我们从 repo 开始:

fun getRegion(countryId: Int) = async {
    val regionFromDb = db.getRegion(countryId)

    if (regionFromDb == null) {
        return apiMapper.map(api.regions).
                  filter({ it.countryId == countryId }).
                  first().
           also {
           db.updateRegions(it)
        }
    }

    return dbMapper.map(regionFromDb)
}

请记住,我没有您的代码,所以细节可能会有所不同。但是协程的总体思路是,async()在它们需要返回结果的情况下启动它们,然后编写代码,就好像你在一个不需要关心并发的完美世界中一样。

现在到交互器:

class RegionInteractor(
    private val repo: RegionRepository,
    private val prefsRepository: PrefsRepository) {

    fun getRegion() = withContext(Schedulers.io().asCoroutineDispatcher()) {
        val countryId = prefsRepository.countryId
        return repo.getRegion(countryId).await()
    }
}

您需要一些东西来从异步代码转换回同步代码。为此,您需要某种线程池来执行。这里我们使用来自 Rx 的线程池,但是如果你想使用其他池,那么就这样做。


推荐阅读