如何处理 Kotlin Jetpack Paging 3 异常?

问题描述 投票:0回答:3

我是 kotlin 和 jetpack 的新手,我被要求处理来自 PagingData 的错误(异常),我不被允许使用 Flow,我只被允许使用 LiveData。

这是存储库:

class GitRepoRepository(private val service: GitRepoApi) {

    fun getListData(): LiveData<PagingData<GitRepo>> {
        return Pager(
            // Configuring how data is loaded by adding additional properties to PagingConfig
            config = PagingConfig(
                pageSize = 20,
                enablePlaceholders = false
            ),
            pagingSourceFactory = {
                // Here we are calling the load function of the paging source which is returning a LoadResult
                GitRepoPagingSource(service)
            }
        ).liveData
    }
}

这是视图模型:

class GitRepoViewModel(private val repository: GitRepoRepository) : ViewModel() {

    private val _gitReposList = MutableLiveData<PagingData<GitRepo>>()

    suspend fun getAllGitRepos(): LiveData<PagingData<GitRepo>> {
        val response = repository.getListData().cachedIn(viewModelScope)
        _gitReposList.value = response.value
        return response
    }

}

在我正在做的活动中:

  lifecycleScope.launch {
            gitRepoViewModel.getAllGitRepos().observe(this@PagingActivity, {
                recyclerViewAdapter.submitData(lifecycle, it)
            })
        }

这是我创建的用于处理异常的资源类(如果有,请为我提供一个更好的)

data class Resource<out T>(val status: Status, val data: T?, val message: String?) {

    companion object {
        fun <T> success(data: T?): Resource<T> {
            return Resource(Status.SUCCESS, data, null)
        }

        fun <T> error(msg: String, data: T?): Resource<T> {
            return Resource(Status.ERROR, data, msg)
        }

        fun <T> loading(data: T?): Resource<T> {
            return Resource(Status.LOADING, data, null)
        }
    }
}

如您所见,我正在使用协程和 LiveData。我希望能够在发生异常时从存储库或 ViewModel 返回到 Activity,以便在 TextView 中显示异常或基于异常的消息。

kotlin kotlin-coroutines android-livedata android-jetpack android-paging-3
3个回答
11
投票

您的

GitRepoPagingSource
应该捕获可重试的错误并将其作为
LoadResult.Error(exception)
转发到 Paging。

class GitRepoPagingSource(..): PagingSource<..>() {
    ...
    override suspend fun load(..): ... {
        try {
            ... // Logic to load data
        } catch (retryableError: IOException) {
            return LoadResult.Error(retryableError)
        }
    }
}

这会以

LoadState
的形式暴露给寻呼的演示者端,可以通过
LoadStateAdapter
.addLoadStateListener
等以及
.retry
做出反应。 Paging 中的所有 Presenter API 都公开了这些方法,例如
PagingDataAdapter
https://developer.android.com/reference/kotlin/androidx/paging/PagingDataAdapter


2
投票

您必须将错误处理程序传递给

PagingSource

class MyPagingSource(
    private val api: MyApi,
    private val onError: (Throwable) -> Unit,
): PagingSource<Int, MyModel>() {

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, YourModel> {
        try {
            ...
        } catch(e: Exception) {
            onError(e) // <-- pass your error listener here
        }
    }
}

0
投票

添加到 @dlam 答案中,您可以监视将 loadState 附加到 pagingAdapter 时出现的各个错误阶段。 例如,您的第一个呼叫通过互联网进行,但第二个寻呼呼叫由于没有互联网连接而失败。

gitRepoAdapter.addLoadStateListener { loadState ->
    
            binding.apply {
                when (loadState.refresh) {
                    is LoadState.Error -> {
                        showError(loadState.source.refresh as? LoadState.Error)
                    }
                    else -> { // Do nothing}
                    }
                }

                /** If second API fails, means an append operation was tried 
                    so you get the error here in this wrapper. */

                when(loadState.append) {

                    is LoadState.Error -> {
                        showError(loadState.source.append as? LoadState.Error ?: loadState.append as? LoadState.Error)
                    }
                    else -> {
                     // Do nothing
                    }
                }

                when(loadState.prepend) {
                    is LoadState.Error -> {
                        showError(loadState.source.prepend as? LoadState.Error ?: loadState.prepend as? LoadState.Error)
                    }
                    else -> {
                       // Do nothing
                    }
                }
            }
        }

  private fun showError(errorState: LoadState.Error?) {
        errorState?.let {
            Toast.makeText(context, "${it.error.message}", Toast.LENGTH_SHORT)
                .show()
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.