如何在存储库类中使用改造、流程、NetworkBoundResource 在 Android 中链接 API 以从服务器检索所有页面?

如何解决如何在存储库类中使用改造、流程、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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?