用Retrofit + Rx链接API请求



我正在尝试使用这个API为Hacker News开发一个客户端,只是为了学习Android是如何工作的,作为一个个人项目。我试着遵循一些教程,但我在某一点上卡住了。

我想检索前N个故事的标题、赞等。这可以通过以下api实现:

  1. 向api请求检索top post的ID(确切地说是500个)
  2. 对于每个ID,向api的posts端点请求获取详细信息。

似乎我卡住了如何为我想要的帖子创建N个不同的网络请求,检索它们并将它们放在列表上,然后在我的片段上显示它们。我正试图遵循MVVM模式,与存储库。相关文件在这里:

NewsApi.kt:

interface NewsApi {
@GET("topstories.json")
fun getTopStories() : Single<List<Int>>
@GET("item/{id}")
fun getItem(@Path("id") id: String): Single<News>
}

MainRepository。kt(我):

interface MainRepository {
fun getTopStoryIDs(): Single<List<Int>>
fun getStory(storyId: Int): Single<News>
fun getTop20Stories(): Single<List<News>>
}

News对象是一个简单的数据类,具有从item/{id}返回的所有JSON字段,因此我省略了它。

这是我的仓库,实现:

class DefaultMainRepository @Inject constructor(
private val api: NewsApi
) : MainRepository {
override fun getTopStoryIDs(): Single<List<Int>> {
return api.getTopStories()
}
override fun getStory(storyId: Int): Single<News> {
return api.getItem(storyId.toString())
}
override fun getTop20Stories(): Single<List<News>> {
TODO("HOW?")
}
}

我最想问的问题是:

  1. 如何使用Retrofit/RxJava以这种方式进行链接API调用?我已经使用flatMap回顾了以前的答案,但在我的情况下,使用Int的列表,我实际上不知道如何正确地做到这一点。
  2. 这是正确的方法吗?我是否应该抛弃我所做的架构选择,并尝试以一种全新的方式思考?
  3. 假设我可以完成getTop20Stories(它,顾名思义,应该检索20个新闻,使用getTopStoryIDs的结果,前20个元素的时间应该做到这一点),我将如何能够从中检索数据?谁应该负责检索响应?虚拟机?片段?

提前感谢。

在这种情况下,作为返回类型并不是最好的选择,因为它被设计为只维护单个流。concatMapflatMapon Single也不会,因为它会尝试将一个项目列表映射到另一个项目列表,而事实并非如此这里。

你可以使用Observable或者使用toObservable()将你的Single映射到Observable与concatMapIterable将单个项目映射到项目序列的操作符。

我使用concatMap操作符代替flatMap因为它保持列表项的顺序,所以你的数据不会混淆。

getTopStoryIDs()
.map { it.take(20) }
.toObservable()
.concatMapIterable { it }
.concatMapSingle { singleId ->
api.getItem(singleId)
}
.toList()
.subscribe { items ->
//do something with your items
}

这段代码可以工作,但它不是最好的解决方案,因为你将进行20次或更多的api调用,这会损害你的网络数据和设备电池,所以如果不是完全必要的话,我不会使用它。

如果您有任何问题,请随时提问:)

你使用FlatMap的方法是正确的。

像这样的代码应该可以达到这个效果:

getTopStoryIDs().flatMap { storyId -> getStory(storyId) }

最新更新