简体   繁体   English

Jetpack Compose + Paging3 RemoteMediator 传播错误

[英]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.

相关问题 Jetpack Compose 中带有 Paging3 的水平寻呼机 - Horizontal Pager with Paging3 in Jetpack Compose 在 Jetpack Compose 中,如何专门处理 paging3 中的错误并在 ui 上显示? - In Jetpack Compose, how do I specifically handle errors in paging3 and display them on ui? Jetpack Compose Paging3 调用 append 加载下一页 - Jetpack Compose Paging3 invoke append to load next page 使用 Jetpack Compose Paging3,在 Launch Effect 块中的分页项目上调用 refresh() 不会更新 UI - With Jetpack Compose Paging3, calling refresh() on paging items in Launch Effect block doesn't update the UI Paging3中如何使用自定义的PagingSource和RemoteMediator加载数据? - How to load data using custom PagingSourceand RemoteMediator in Paging3? Android:Paging3 使用 cloud-firestore 创建远程中介 - Android: Paging3 create remotemediator with cloud-firestore Android jetpack paging3 更新项目 - Android jetpack paging3 update item Android Paging3 - 使用 Compose 从 ViewModel 刷新 - Android Paging3 - refresh from a ViewModel with Compose Paging3 : Recycler View 闪烁,一些项目在从 RemoteMediator 获取数据后移动到位 - Paging3 : Recycler View blinking and some items move in position after getting data from RemoteMediator Jetpack Paging3 库对同一页面进行多次调用 - Jetpack Paging3 library makes several calls to the same page
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM