使用Flow进行多个翻新呼叫

问题描述

我制作了一个应用,用户可以在其中添加服务器(回收行)。它仅保存IP和端口。然后,当用户打开FavoriteFragment改造时,每个服务器都会进行呼叫

 @GET("v0/server/{ip}/{port}")
    suspend fun getServer(
        @Path("ip") ip: String,@Path("port") port: Int
    ): Server

因此,在repository中,我混合了源并进行了多次呼叫:

suspend fun getFavoriteServersToRecyclerView(): Flow<DataState<List<Server>>> = flow {
        emit(DataState.Loading)
        try {
            val getFavoritesServersNotLiveData = favoritesDao.getFavoritesServersNotLiveData()
            val list: MutableList<Server> = mutablelistof()
            getFavoritesServersNotLiveData.forEach { fav ->
                val server = soldatApiService.getServer(fav.ip,fav.port)
                list.add(server)
            }
            emit(DataState.Success(list))
        } catch (e: Exception) {
            emit(DataState.Error(e))
        }
    }

然后在viewmodel中创建LiveData对象

fun getFavoriteServers() {
        viewmodelScope.launch {
            repository.getFavoriteServersToRecyclerView()
                .onEach { dataState ->
                    _favoriteServers.value = dataState
                }.launchIn(viewmodelScope)
        }
    }

一切正常,直到“大厅”和Retrofit呼叫失败中“收藏夹”服务器不再可用为止。 我的问题是:如何在循环中跳过失败的调用而不崩溃整个函数

解决方法

如果希望继续使用RxJava进行onResumeNext之类的流程,请使用emitAll发出另一个捕获流。

   catch { cause ->
      emitAll(flow { emit(DataState.Errorcause)})
   }
,

好,我找到了解决方法:

 suspend fun getFavoriteServersToRecyclerView(): Flow<DataState<List<Server>>> = flow {
        emit(DataState.Loading)

        val list: MutableList<Server> = mutableListOf()

        try {
            val getFavoritesServersNotLiveData = favoritesDao.getFavoritesServersNotLiveData()

            val job = CoroutineScope(coroutineContext).launch {
                getFavoritesServersNotLiveData.forEach { fav ->
                    val server = getServer(fav.ip,fav.port)

                    server.collect { dataState ->
                        when (dataState) {
                            is DataState.Loading -> Log.d(TAG,"loading")
                            is DataState.Error -> Log.d(TAG,dataState.exception.message!!)
                            is DataState.Success -> {
                                list.add(dataState.data)
                                Log.d(TAG,dataState.data.toString())
                            }
                        }
                    }
                }
            }
            job.join()
            emit(DataState.Success(list))
        } catch (e: Exception) {
            emit(DataState.Error(e))
        }
    }
,

当使用改造时,您可以使用 Response<T> (从改造导入响应) 包装响应对象,以便

@GET("v0/server/{ip}/{port}")
    suspend fun getServer(
        @Path("ip") ip: String,@Path("port") port: Int
    ): Response<Server>

然后在存储库中,您可以在不使用 try-catch

的情况下检查网络是否失败
suspend fun getFavoriteServersToRecyclerView(): Flow<DataState<List<Server>>> = flow {
        emit(DataState.Loading)
        val getFavoritesServersNotLiveData = favoritesDao.getFavoritesServersNotLiveData()
        if(getFavoritesServersNotLiveData.isSuccessful) {
            
            val list: MutableList<Server> = mutableListOf()
            getFavoritesServersNotLiveData.body().forEach { fav ->
                val server = soldatApiService.getServer(fav.ip,fav.port)
                // if the above request fails it wont go to the else block
                list.add(server)
            }
            emit(DataState.Success(list))
        } else {
            val error = getFavoritesServersNotLiveData.errorBody()!!
            //do something with error
        }
    }