将 NetworkBoundRepository 与协程一起使用时,将远程数据单独保存在相关表中 (android)

Save remote data separately related tables when using NetworkBoundRepository with coroutines (android)

我想在我的申请中使用单一事实来源原则。使用 NetworkBoundRepository 时如何添加多个 table。

MainApi.kt

interface MainApi {
    @GET("main")
    suspend fun getMain(): Response<MainResponse>
}

MainResponse.kt

@JsonClass(generateAdapter = true)
data class MainResponse(
        @Json(name = "categories") val categoryList: List<Category>,
        @Json(name = "locations") val locationList: List<Location>,
        @Json(name = "tags") val tagList: List<Tag>
) 

NetworkBoundRepository.kt

@ExperimentalCoroutinesApi
abstract class NetworkBoundRepository<RESULT, REQUEST> {

    fun asFlow() = flow<Resource<RESULT>> {
        emit(Resource.Success(fetchFromLocal().first()))
        val apiResponse = fetchFromRemote()
        val remoteCategories = apiResponse.body()

        if (apiResponse.isSuccessful && remoteCategories != null) {
            saveRemoteData(remoteCategories)
        } else {
            emit(Resource.Failed(apiResponse.message()))
        }

        emitAll(
            fetchFromLocal().map {
                Resource.Success<RESULT>(it)
            }
        )
    }.catch { e ->
        emit(Resource.Failed("Network error! Can't get latest categories."))
    }

    @WorkerThread
    protected abstract suspend fun saveRemoteData(response: REQUEST)

    @MainThread
    protected abstract fun fetchFromLocal(): Flow<RESULT>

    @MainThread
    protected abstract suspend fun fetchFromRemote(): Response<REQUEST>
}

MainRepository.kt

@ExperimentalCoroutinesApi
class MainRepository @Inject constructor(
    private val mainApi: MainApi,
    private val categoryDao: CategoryDao,
    private val locationDao: LocationDao,
    private val tagDao: TagDao
) {
        suspend fun getMain(): Flow<Resource<List<Category>>> {
        return object : NetworkBoundRepository<List<Category>, List<Category>>() {
            override suspend fun saveRemoteData(response: List<Category>) = categoryDao.insertList(response)
            override fun fetchFromLocal(): Flow<List<Category>> = categoryDao.getList()
            override suspend fun fetchFromRemote(): Response<List<Category>> = mainApi.getMain()
        }.asFlow()
    }
}

目前 NetworkBoundRepository 和 MainRepository 仅适用于类别。我想从互联网上获取一些数据并将每个数据保存到数据库中的相关 tables。应用程序必须先离线。 如何将 locationDao、tagDao 添加到 MainRepository?

我不太明白你的问题。您正在将 locationDao 和 tagDao 添加到 MainRepository 已经在这里:

class MainRepository @Inject constructor(
    ...
    private val locationDao: LocationDao,
    private val tagDao: TagDao
)

如果您询问如何提供它们以便通过 Dagger2 注入它们,您必须将 dao 构造函数定义为 @Inject 或添加 @Provides@Binds 将具有相关 return 类型的注释方法添加到所需的 @Module,并将它们纠缠在同一个 @Scope - 更多 here

如果您询问如何在您的函数中使用这些存储库,也很简单:

object : NetworkBoundRepository<List<Category>, MainResponse>() {
            override suspend fun saveRemoteData(response: MainResponse) = response?.run{
                categoryDao.insertList(categoryList)
                locationDao.insertList(locationList)
                tagDao.insertList(tagList)
            }
            override fun fetchCategoriesFromLocal(): Flow<List<Category>> = categoryDao.getList()
            override fun fetchLocationsFromLocal(): Flow<List<Location>> = locationDao.getList()
            override fun fetchTagsFromLocal(): Flow<List<Tag>> = tagDao.getList()
            override suspend fun fetchFromRemote(): Response<MainResponse> = mainApi.getMain()

//This function is not tested and written more like a pseudocode
            override suspend fun mapFromLocalToResponse(): Flow<MainResponse> = fetchCategoriesFromLocal().combine(fetchLocationsFromLocal(), fetchTagsFromLocal()){categories, locations, tags ->
                MainResponse(categories,locations,tags)
            }
        }

也许还需要进行一些调整。但是你的代码的主要问题是你试图将所有不同的实体组合到一个回购中,这不是很好(并且请求 returns 一个响应下的所有东西也不好) -我建议以某种方式将其拆分而不是全部混合。