【问题标题】:How to handle many Api requests using Paging 3如何使用 Paging 3 处理许多 Api 请求
【发布时间】:2020-11-13 08:35:28
【问题描述】:

this codelab 之后,我使用RemoteMediator 实现了分页和缓存(我正在调用一个返回新闻列表的简单API)。我将这个RemoteMediator 注入到具有返回Flow<PagingData<News>> 的方法getResultStream() 的存储库中。在 ViewModel 中是函数 getNews() : Flow<PagingData<News>>,在 Fragment 中我正在调用此函数并将列表提交给 RecyclerAdapter。

现在我想添加一个返回新闻但带有搜索关键字的新 API 调用。正确的方法是什么?我是否必须重新编写所有这些代码并创建一个新的RemoteMediator?逻辑将是相同的,但现在我必须将字符串参数传递给 Retrofit get 函数。此调用的结果将替换 RecyclerView 中的项目,因此我将有两个数据源但一个 Recycler,我是否还必须创建一个 MediatorLiveData(我没有添加任何代码,但如果有帮助我可以做到)


有人问我到底是怎么做到的(问题已作为答案发布,因此现在已将其删除,但将来可能会对某人有所帮助)。所以,在 ViewModel 我有这个:

// this flow keeps query. If it is null it means that I want to get all News from API. If it is not null it means that I want to make another API request which takes a parameter query
private val _queryFlow: MutableStateFlow<String?> = MutableStateFlow(null)
val queryFlow: StateFlow<String?>
    get() = _queryFlow

// this function set and validate query
fun submitQuery(query: String?)
{
    Timber.d("Submit new search $query")
    _queryFlow.value = when
    {
        query.isNullOrEmpty() -> null
        query.trim()
            .isNotBlank() -> query.trim()
        else -> null
    }
}

// flow of paging data that I am using in RecyclerView
@ExperimentalCoroutinesApi
val homeNewsData = _queryFlow.flatMapLatest {
    searchNews(it)
}


private fun searchNews(
    query: String?
): Flow<PagingData<NewsRecyclerModel>>
{
    return newsRepository.getSearchResultStream(
        query
    )
        // mapping, filtering, separators etc.
        .cachedIn(viewModelScope)
}

NewsRepository 在VM中有这个功能:

fun getSearchResultStream(searchKey: String?): Flow<PagingData<News>>
{
    val pagingSourceFactory = { database.cacheNewsDao.getNews() }
    return Pager(
        config = PagingConfig(
            pageSize = NETWORK_PAGE_SIZE,
            enablePlaceholders = false,
            initialLoadSize = INITIAL_LOAD_SIZE
        ),
        remoteMediator = newsRemoteMediator.apply { this.searchKey = searchKey },
        pagingSourceFactory = pagingSourceFactory
    ).flow
}

NewsRemoteMedietor:

// it keeps submitted query. based on this I can letter define which API request I want to do
var searchKey: String? = null

override suspend fun load(loadType: LoadType, state: PagingState<Int, News>): MediatorResult
{
    \\ all logic the same like in codelabs

    try
    {
        val apiResponse =
            if (searchKey.isNullOrEmpty()) // query is null/empty get Trending news
                newsRetrofit.getTrending(
                    state.config.pageSize,
                    page * state.config.pageSize
                )
            else // query is not blank, make API request with search keyword
                newsRetrofit.getSearched(
                    state.config.pageSize,
                    page * state.config.pageSize,
                    searchKey!!
                )
        \\ again the same logic like in codelabs
    }
}
我不知道这是否是最好的方法(可能不是),但就我而言,它正在工作

【问题讨论】:

    标签: android kotlin android-paging


    【解决方案1】:

    假设你还有一个 recyclerview,你可以这样做:

    val queryFlow = MutableStateFlow(startingQuery)
    queryFlow.flatMapLatest { query ->
        Pager(..., MyRemoteMediator(query)) {
            MyPagingSource(...)
        }.flow
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      • 2019-03-30
      • 1970-01-01
      • 2016-08-01
      • 1970-01-01
      • 2020-11-27
      相关资源
      最近更新 更多