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

问题描述

我想在我的应用程序中使用单一事实来源原则。使用 NetworkBoundRepository 时如何添加多个表。

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 仅适用于类别。我想从互联网上获取一些数据并将每个数据保存到数据库中的相关表中。应用程序必须先离线。 如何将 locationDao、tagDao 添加到 MainRepository?

解决方法

我不太明白你的问题。您已在此处向 MainRepository 添加 locationDao 和 tagDao:

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

如果您询问如何提供它们以便通过 Dagger2 注入它们,您必须将 dao 构造函数定义为 @Inject 或添加 @Provides@Binds 注释具有相关返回类型的方法到所需的 @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,tags)
            }
        }

也许需要更多的调整。但是你的代码的主要问题是你试图将所有不同的实体组合成一个 repo 并且它不是很好(并且在一个响应下返回所有东西的请求也不好) - 我建议拆分以某种方式不要将其全部混合。