如何解决如何在存储库类中使用改造、流程、NetworkBoundResource 在 Android 中链接 API 以从服务器检索所有页面?
我正在开发一个 Android 应用程序,它需要从网络中检索所有页面以在屏幕上显示详细信息。这是 Youtube API https://developers.google.com/youtube/v3/docs/playlistItems/list
每个响应都有nextPagetoken,需要用于下一页api。应用程序未显示列表,因此不需要分页。我正在使用改造+流+NetworkBoundResource+mvvm+kotlin。 如何使用存储库中的任何转换方法 FlatMapMerge/FlatMapConcat/FlatMapLatest 将所有响应放在一起然后发出。
restApiService
@GET(Contracts.PLAYLIST_ITEM_ENDPOINT)
fun getAllPlayListItemsForPlayListId(
@Query("part") part: String = "snippet,status",@Query("playlistId") playlistId: String,@Query("pagetoken") pagetoken: String = "",@Query("maxResults") maxResults: Int? = 50
): Flow<ApiResponse<PlaylistItemsResponse>>
网络绑定资源
suspend fun asFlow(): Flow<Resource<ResultType>> {
return loadFromDb().transformlatest { dbValue ->
if (shouldFetch(dbValue)) {
emit(Resource.loading(dbValue))
createCall().collect { apiResponse ->
when (apiResponse) {
is ApiSuccessResponse -> {
withContext(dispatchers.IO) {
saveCallResult(processResponse(apiResponse))
}
}
is ApiEmptyResponse -> {
emit(Resource.success(dbValue))
}
is ApiErrorResponse -> {
onFetchFailed()
emit(Resource.error(apiResponse.errorMessage,dbValue))
}
}
}
} else {
emit(Resource.success(dbValue))
}
}
}
存储库
override suspend fun createCall() =
apiService.getAllPlayListItemsForPlayListId(playlistId = playlistId,pagetoken = nextPagetoken)
如何递归调用相同的api直到nextPagenToken为空,像这样,在Go中实现,参考Youtube API指南。 https://developers.google.com/youtube/v3/docs/playlistItems/list
package main
import (
"fmt"
"log"
"google.golang.org/api/youtube/v3"
)
// Retrieve playlistItems in the specified playlist
func playlistItemsList(service *youtube.Service,part string,playlistId string,pagetoken
string) *youtube.PlaylistItemListResponse {
call := service.PlaylistItems.List(part)
call = call.PlaylistId(playlistId)
if pagetoken != "" {
call = call.Pagetoken(pagetoken)
}
response,err := call.Do()
handleError(err,"")
return response
}
// Retrieve resource for the authenticated user's channel
func channelsListmine(service *youtube.Service,part string) *youtube.ChannelListResponse {
call := service.Channels.List(part)
call = call.mine(true)
response,"")
return response
}
func main() {
client := getClient(youtube.YoutubeReadonlyScope)
service,err := youtube.New(client)
if err != nil {
log.Fatalf("Error creating YouTube client: %v",err)
}
response := channelsListmine(service,"contentDetails")
for _,channel := range response.Items {
playlistId := channel.ContentDetails.Relatedplaylists.Uploads
// Print the playlist ID for the list of uploaded videos.
fmt.Printf("Videos in list %s\r\n",playlistId)
nextPagetoken := ""
for {
// Retrieve next set of items in the playlist.
playlistResponse := playlistItemsList(service,"snippet",playlistId,nextPagetoken)
for _,playlistItem := range playlistResponse.Items {
title := playlistItem.Snippet.Title
videoId := playlistItem.Snippet.ResourceId.VideoId
fmt.Printf("%v,(%v)\r\n",title,videoId)
}
// Set the token to retrieve the next page of results
// or exit the loop if all results have been retrieved.
nextPagetoken = playlistResponse.NextPagetoken
if nextPagetoken == "" {
break
}
fmt.Println()
}
}
}
解决方法
我通过 flatMapLatest 得到了它。
fun getPageAndNext(playlistId: String,nextPageToken: String): Flow<ApiResponse<PlaylistItemsResponse>> {
return apiService.getAllPlayListItemsForPlayListId(playlistId = playlistId,pageToken = nextPageToken)
.flatMapLatest { apiResponse ->
var nextPage: String? = null
if (apiResponse is ApiSuccessResponse) {
nextPage = apiResponse.body.nextPageToken
}
if (nextPage == null) {
flowOf(apiResponse)
} else {
getPageAndNext(playlistId,nextPage)
}
}
}
override suspend fun createCall() = getPageAndNext(playlistId = playlistId,nextPageToken = nextPageToken)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。