简体   繁体   English

在 Jetpack Compose 中,如何专门处理 paging3 中的错误并在 ui 上显示?

[英]In Jetpack Compose, how do I specifically handle errors in paging3 and display them on ui?

In my case, I'm requesting a GitHub API, if I request a lot of data, I might get a 403 error, while if I run out of requested data, GitHub will return me a 422 Unprocessable Entity.就我而言,我正在请求 GitHub API,如果我请求大量数据,我可能会收到 403 错误,而如果我用完请求的数据,GitHub 会返回一个 422 Unprocessable Entity。 So I want to prompt the user on the UI based on this whether it is rate limited by the API or there is no new data.所以我想根据这个在UI上提示用户是受API速率限制还是没有新数据。

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, EventWithRepoInfo> {
        val position = params.key ?: GITHUB_STARTING_PAGE_INDEX
        return try {
            val receivedEvents = network.receivedEvents(token, network.getUserInfo(token).login, position, params.loadSize)
            val eventWithRepoInfo: MutableList<EventWithRepoInfo> = mutableListOf()
            val nextKey = if (receivedEvents.isEmpty()) {
                null
            } else {
                position + (params.loadSize / NETWORK_PAGE_SIZE)
            }
            nextKey?.let {
                receivedEvents.forEach {
                    eventWithRepoInfo.add(EventWithRepoInfo(it, ktorClient.getRepoInfo(token, it.repo.url)))
                }
            }
            LoadResult.Page(
                data = eventWithRepoInfo,
                prevKey = if (position == GITHUB_STARTING_PAGE_INDEX) null else position - 1,
                nextKey = nextKey
            )
        } catch (exception: IOException) {
            exception.printStackTrace()
            return LoadResult.Error(exception)
        } catch (exception: HttpException) {
            exception.printStackTrace()
            return LoadResult.Error(exception)
        }
    }

So I want to judge whether it is 403 or 422 in this place.所以想判断这个地方是403还是422。 If it is 422, it will show that there is no more data, and 403 will prompt the user that the api is rate-limited.如果是422就说明没有数据了,403会提示用户api是限速的。

    LazyColumn {
        events.apply {
            when {
                loadState.append is LoadState.Loading -> {
                    item {
                            Text("loading")
                        }
                    }
                }
                // I want to show different things here depending on different error codes
                loadState.append is LoadState.Error -> {
                    item {
                        LargeButton(onClick = { events.retry() }) {
                            Text("loading error, retry.")
                        }
                    }
                }
            }
        }
    }

so multiple things here, if you really want to use the power of paging (and so, load item only when the user scroll), you need to use the items method provided by the LazyColumn, that take in argument a LazyPagingItems<T>这里有很多东西,如果你真的想使用分页的力量(所以,只有在用户滚动时才加载项目),你需要使用 LazyColumn 提供的items方法,它接受参数LazyPagingItems<T>

Firstly, you should retrieve the PagingData flow from the Pager.首先,您应该从寻呼机中检索 PagingData 流。

val githubPager = Pager(...)
val pagingItems : Flow<PagingData<MyCustomDto>> = githubPager.flow

Once you get the flow of paging data, ideally you should cache it inside you're view model scope, and then expose it to you're view一旦获得分页数据流,理想情况下,您应该将其缓存在您的视图模型范围内,然后将其公开给您的视图

val cachedPagingItems = pagingItems.cachedIn(viewModelScope)

Inside you're composable, you can now then collect the pagingItems, transmit the error to you're view model, and show the paging data inside you're LazyColumn在您是可组合的内部,您现在可以收集 pagingItems,将错误传输到您的视图模型,并在您的 LazyColumn 中显示分页数据

I've made a small extension function to perform the remember operation, and expose a retry block directly :我做了一个小的扩展函数来执行记忆操作,并直接暴露一个重试块:

@Composable
fun <T : Any> Flow<PagingData<T>>.collectAndHandleState(
    handleLoadStates: (LoadStates, () -> Unit) -> Job
): LazyPagingItems<T> {
    val lazyPagingItem = collectAsLazyPagingItems()

    // Handle the different load state event
    val pagingLoadStates = lazyPagingItem.loadState.mediator ?: lazyPagingItem.loadState.source
    LaunchedEffect(pagingLoadStates) {
        handleLoadStates(pagingLoadStates)
    }

    return lazyPagingItem
}

To use this extension function, do inside you're composable :要使用此扩展功能,请在 you're composable 内部执行:

// Get our paging items
val pagingItems = viewModel.cachedPagingItems.collectAndHandleState(viewModel::handleLoadState)
LazyColumn {
    item {
        // Display an error if any, or any informative message here, coming from an UiState exposed by you're view model
    } 

    // Display the items
    items(pagingItems) { pagedItem ->
        // The composable you want to display
    }


}

And inside you're view model, a simple function :在你的视图模型里面,一个简单的函数:

fun handleLoadState(loadStates: LoadStates, retry: () -> Unit): Job {
    // Handle the different load state, find the error or loading ones and update you're ui state
    // To rapidly find an error you can do : 
    val errorLoadState = arrayOf(
        loadStates.append,
        loadStates.prepend,
        loadStates.refresh
    ).filterIsInstance(LoadState.Error::class.java).firstOrNull()
    // And then check the error by getting the associated throwable
    val throwable = errorLoadState?.error

}

There's a simple way to find out what kind of error has occurred, hope following code is helpful.有一种简单的方法可以找出发生了什么样的错误,希望以下代码对您有所帮助。

   events.apply {
                when {
                    /** Showing error state */
                    loadState.refresh is LoadState.Error -> {
                        val e = loadState.refresh as LoadState.Error
                        val message = ""
                        if (e.error is UnknownHostException) {
                            message = // Your message
                        } else if (e.error is /*Exception*/){
                            message = // Your message
                        }
                        item {
                            ErrorView(message)
                        }
                    }

                    /** Showing error state */
                    loadState.append is LoadState.Error -> {
                        val e = loadState.refresh as LoadState.Error
                        val message = ""
                        if (e.error is UnknownHostException) {
                            message = // Your message
                        } else if (e.error is /*Exception*/){
                            message = // Your message
                        }
                        item {
                            ErrorView(message)
                        }
                    }
                }
            }

我在这里处理了惰性行中的服务器错误,第 206 行Github

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM