[英]Jetpack Compose + Paging3 RemoteMediator propagate errors
I'm trying Jetpack Compose and I've created a simple app to consume the Star Wars API with Ktor, Room, Hilt, Paging3 and Material3.我正在尝试 Jetpack Compose,我创建了一个简单的应用程序来使用带有 Ktor、Room、Hilt、Paging3 和 Material3 的星球大战 API 。
I can't understand how to propagate any eventual error caught during the data fetch.我无法理解如何传播在数据获取期间捕获的任何最终错误。
AppDatabase.kt
@Database(
entities = [
SWCharacter::class
], version = 2, exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun people(): PeopleDao
}
PeopleService.kt
class PeopleService(private val httpClient: HttpClient) {
suspend fun getPeople(page: Int?): SwapiResult<SWCharacter> {
return httpClient.get(path = "api/people") {
parameter("page", page)
}
}
}
RemoteMediator.kt
@ExperimentalPagingApi
class PeopleRemoteMediator @Inject constructor(private val database: AppDatabase, private val service: PeopleService) : RemoteMediator<Int, SWCharacter>() {
private val dao: PeopleDao = database.people()
override suspend fun initialize(): InitializeAction {
return if (database.people().getCount() > 0) {
InitializeAction.SKIP_INITIAL_REFRESH
} else {
InitializeAction.LAUNCH_INITIAL_REFRESH
}
}
override suspend fun load(loadType: LoadType, state: PagingState<Int, SWCharacter>): MediatorResult {
return try {
val loadPage = when (loadType) {
LoadType.REFRESH -> 1
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
2
}
}
val response = service.getPeople(page = loadPage)
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dao.clearAll()
}
dao.insertAll(response.results)
}
MediatorResult.Success(endOfPaginationReached = response.next == null)
} catch (e: IOException) {
MediatorResult.Error(e)
} catch (e: ResponseException) {
MediatorResult.Error(e)
}
}
}
and PeopleRepository.kt和 PeopleRepository.kt
class PeopleRepository @Inject constructor(private val database: AppDatabase, private val service: PeopleService) {
@ExperimentalPagingApi
fun fetchPeople(): Flow<PagingData<SWCharacter>> {
return Pager(
PagingConfig(pageSize = 10, enablePlaceholders = false, prefetchDistance = 3),
remoteMediator = PeopleRemoteMediator(database, service),
pagingSourceFactory = { database.people().pagingSource() }
).flow
}
}
I consume all the above code inside a ViewModel
我在
ViewModel
中使用了上述所有代码
@ExperimentalPagingApi
@HiltViewModel
class PeopleViewModel @Inject constructor(private val repo: PeopleRepository) : ViewModel() {
private val _uiState = mutableStateOf<UIState>(UIState.Loading)
val uiState: State<UIState>
get() = _uiState
init {
viewModelScope.launch {
try {
val people = repo.fetchPeople()
_uiState.value = UIState.Success(data = people)
} catch (e: Exception) {
_uiState.value = UIState.Error(message = e.message ?: "Error")
}
}
}
}
sealed class UIState {
object Loading : UIState()
data class Success<T>(val data: T) : UIState()
data class Error(val message: String) : UIState()
}
To simulate an error, I'll change the endpoint address to ie:为了模拟错误,我将端点地址更改为 ie:
return httpClient.get(path = "api/peoplethatnotexists")
The error is caught correctly in the RemoteMediator
, but I don't know how to catch it in the view model.在
RemoteMediator
中正确捕获了该错误,但我不知道如何在视图 model 中捕获它。
In order to listen to RemoteMediator errors, you can add a LoadStateListener to your RecyclerView adapter as follows:为了侦听 RemoteMediator 错误,您可以将 LoadStateListener 添加到您的 RecyclerView 适配器,如下所示:
mAdapter = MyAdapter(...).apply {
addLoadStateListener { loadState ->
val mediatorLoadState: LoadState? = loadState.mediator?.refresh
if (mediatorLoadState is LoadState.Error) {
// Herein you can implement your fallback
// as per mediatorLoadState.error
}
}
}
Likewise, you can change loadState.refresh by the RemoteMediator's state you want to listen to.同样,您可以通过要收听的 RemoteMediator 的 state 更改 loadState.refresh。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.