如何从分页源或远程调解器 Kotlin 调用不同的 api 资源
Posted
技术标签:
【中文标题】如何从分页源或远程调解器 Kotlin 调用不同的 api 资源【英文标题】:How to call different api resource from paging source or remote mediator Kotlin 【发布时间】:2021-12-13 04:11:52 【问题描述】:嘿,我想为我的 Paging Library 3 调用两个不同的 api。我想问什么最适合我使用 Paging Source 或 Remote Mediator?。两者的用例是什么?谁能给我解释一下。
第一次 api 调用仅限单次
@GET("/movie?min=20")
上面的 api 调用返回这个响应
data class movie(
var id: Int?,
var name: String?,
var items : List<Genre>?
现在第二个 api 调用它的循环来一次又一次地调用
@GET("/movie?count=20&&before=time")
上面的api调用rerun this
data class movie(
var items : List<Genre>?
类型
data class Genre(
var type: String?,
var date: String?,
var cast: String?
流派在两个 api 调用中都有数据。我试图用谷歌搜索并找到这个Example。但是在这两个api中都返回相同的数据。但在我的情况下,两者的回报都有点不同。 id, name 仅在 UI 组件中使用,否则列表将转到 adapter。但我不明白如何做到这一点。我是Flow的新手,太难理解了,说实话我正在努力学习CodeLab。第一次 api 调用时的另一件重要事情,其中最后一项包含日期将发送到 time 参数中的第二次 api 调用,然后第二次 api 最后项日期再次调用第二次 api,这将进入循环。那么如何在循环条件下再次跟踪它。 第三我想更新列表顶部的数据,我们可以将数据存储在内存中而不是更新该列表上的值吗?感谢提前。对不起我的英语错误。
更新
在@dlam 建议后,我尝试练习一些代码
MainActivity
class MainActivity : AppCompatActivity()
private lateinit var binding: ActivityMainBinding
private val viewModel by viewModels<ActivityViewModel>()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
lifecycleScope.launchWhenCreated
viewModel.getMovie().collectLatest
// setupAdapter()
ActivityViewModel
class ActivityViewModel(app: Application) : androidViewModel(app)
fun getMovie(): Flow<PagingData<Genre>>
return Pager(
config = PagingConfig(
pageSize = 20
),
pagingSourceFactory =
MultiRequestPagingSource(DataSource())
).flow
MultiRequestPagingSource
class MultiRequestPagingSource(private val dataSource: DataSource) : PagingSource<String, Genre>()
override fun getRefreshKey(state: PagingState<String, Genre>): String?
return state.anchorPosition?.let anchorPosition ->
state.closestPageToPosition(anchorPosition)?.nextKey
override suspend fun load(params: LoadParams<String>): LoadResult<String, Genre>
val key = params.key ?: ""
return try
val data = when (params)
is LoadParams.Refresh ->
dataSource.fetchInitialMovie()
is LoadParams.Append ->
dataSource.fetchMovieBefore(key)
is LoadParams.Prepend -> null
LoadResult.Page(
data = data.result,
prevKey = null,
nextKey = data?.nextKey,
)
catch (exception: IOException)
LoadResult.Error(exception)
data = data.result
出现错误
Type mismatch.
Required:
List<TypeVariable(Value)>
Found:
ArrayDeque<Genre>?
数据源
package com.example.multirequestpaging
class DataSource
data class MovieResult(
val result: ArrayDeque<Genre>?,
val nextKey: String?
)
fun fetchInitialMovie(): MovieResult
val response = ApiInterface.create().getMovieResponse(20)
return MovieResult(
addInArrayDeque(response),
response.items?.last()?.date
)
fun fetchMovieBefore(key: String): MovieResult
val response = ApiInterface.create().getMovieResponseBefore(20, key)
return MovieResult(
addInArrayDeque(response),
response.items?.last()?.date
)
private fun addInArrayDeque(response: MovieResponse): ArrayDeque<Genre>
val result: ArrayDeque<Genre> = ArrayDeque()
response.items?.forEach
result.add(it)
return result
完整代码Project Link
1.我想在列表顶部添加一个项目。如何使用 invalidate 功能?抱歉,我不明白我可以在哪里使用。
2.我想在其他地方使用 id,name 那么如何在我的活动类中获取这些变量值。
3.我的代码结构好不好?我需要改进吗,请举个例子。它还可以帮助正在学习分页库的初学者。
谢谢
【问题讨论】:
【参考方案1】:PagingSource
是 Paging 的主要驱动程序,它负责加载显示的项目并代表数据的单一真实来源。
RemoteMediator
用于分层源,它本质上是一个回调,当PagingSource
用完数据时触发,因此您可以从辅助源获取。这主要适用于从 DB + Network 获取数据的情况,您希望本地缓存数据为 Paging 提供支持,然后使用 RemoteMediator
作为回调从网络获取更多项目到缓存中。
在这种情况下,您有两个 API,但它们都从同一个网络源获取,因此您只需要 PagingSource
。如果我理解正确,您本质上是想在初始加载时调用第一个 API,在随后的前置/附加页面加载时调用第二个 API,您可以通过您获得的 LoadParams 类型检查/打开它。在此处查看子类型:https://developer.android.com/reference/kotlin/androidx/paging/PagingSource.LoadParams
【讨论】:
是的,试图从网站中学习。你能给我一些例子吗? 还有如何更新来自第一个 api 调用的 0 索引中的数据。我的意思是在 Flow 中 您的意思是您已经加载了第一页,然后想要更改索引 0 处的项目?分页通过失效+重新加载来处理这个问题。以这种方式进行更新并保持单一的事实来源非常重要,这样配置更改之类的事情也会得到处理。 是的,我想这样做。你能给我举个例子吗?我想学习这个神奇的图书馆。但我找不到合适的方法。谢谢 我们怎样才能在内存中实现存储列表。我不想存储在房间或任何数据库中。以上是关于如何从分页源或远程调解器 Kotlin 调用不同的 api 资源的主要内容,如果未能解决你的问题,请参考以下文章