在Retrofit中使用RxJava的startWith方法传递状态遇语法错误求助
解决Retrofit+RxJava中用startWith传递加载状态的语法错误问题
我明白你遇到的问题了——直接给Retrofit返回的Flowable<Response<ResponseMobileGetAccess>>加startWith(Resource.Loading)会报类型不匹配的语法错误,这是因为**startWith要求发射的事件类型必须和原流的类型完全一致**,而你原流的类型是Retrofit的Response,但你想发送的是自定义的Resource状态类,两者类型不兼容。
下面是完整的解决方案,分步骤说明:
1. 先定义统一的状态封装类Resource
首先需要一个密封类(Kotlin)或抽象类(Java)来封装加载、成功、错误三种状态,确保整个流的事件类型统一:
Kotlin版本
sealed class Resource<out T> { // 加载状态,不需要携带数据 object Loading : Resource<Nothing>() // 成功状态,携带返回数据 data class Success<out T>(val data: T) : Resource<T>() // 错误状态,携带错误信息和异常对象 data class Error(val message: String?, val throwable: Throwable?) : Resource<Nothing>() }
Java版本
public abstract class Resource<T> { private Resource() {} public static class Loading<T> extends Resource<T> {} public static class Success<T> extends Resource<T> { public final T data; public Success(T data) { this.data = data; } } public static class Error<T> extends Resource<T> { public final String message; public final Throwable throwable; public Error(String message, Throwable throwable) { this.message = message; this.throwable = throwable; } } }
2. 转换Retrofit流的类型并添加加载状态
现在需要把Retrofit返回的Response类型转换成Resource类型,再用startWith发送加载状态,这样类型就完全匹配了:
Kotlin调用示例
apiService.getAccess(url, requestModel) // 第一步:把Retrofit的Response转换成Resource状态 .map { response -> if (response.isSuccessful) { // 成功且有返回体时,封装成Success状态 response.body()?.let { Resource.Success(it) } ?: Resource.Error("接口返回空数据", null) } else { // 接口返回错误码时,封装成Error状态 Resource.Error("请求失败,错误码:${response.code()}", null) } } // 捕获网络请求中的异常,转换成Error状态(避免流终止) .onErrorReturn { throwable -> Resource.Error("网络异常:${throwable.message}", throwable) } // 现在可以安全添加加载状态了,因为流的类型已经是Resource<ResponseMobileGetAccess> .startWith(Resource.Loading) // 线程切换 .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { resource -> when (resource) { is Resource.Loading -> { // 处理加载状态:显示loading弹窗、禁用按钮等 } is Resource.Success -> { // 处理成功数据:resource.data就是ResponseMobileGetAccess对象 } is Resource.Error -> { // 处理错误状态:显示错误提示、隐藏loading等 } } }, { // 这里理论上不会走到(因为onErrorReturn已经捕获了异常),可以留作兜底处理 } )
Java调用示例
apiService.getAccess(url, requestModel) .map(response -> { if (response.isSuccessful()) { ResponseMobileGetAccess body = response.body(); if (body != null) { return new Resource.Success<>(body); } else { return new Resource.Error<>("接口返回空数据", null); } } else { return new Resource.Error<>("请求失败,错误码:" + response.code(), null); } }) .onErrorReturn(throwable -> new Resource.Error<>("网络异常:" + throwable.getMessage(), throwable)) .startWith(new Resource.Loading<>()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(resource -> { if (resource instanceof Resource.Loading) { // 处理加载状态 } else if (resource instanceof Resource.Success) { ResponseMobileGetAccess data = ((Resource.Success<ResponseMobileGetAccess>) resource).data; // 处理成功数据 } else if (resource instanceof Resource.Error) { Resource.Error error = (Resource.Error) resource; // 处理错误状态 } }, throwable -> { // 兜底错误处理 });
关键注意点
- 类型统一是核心:必须先把Retrofit的
Response流转换成Resource类型,再调用startWith,否则会因为类型不匹配报错。 - 异常处理:用
onErrorReturn捕获网络异常并转换成Error状态,这样整个流不会因为异常中断,能完整传递错误状态到订阅端。 - Loading状态的泛型适配:Kotlin中用
Nothing作为Loading的泛型,Java中用通配符适配,确保它能和Success/Error的泛型兼容。
内容的提问来源于stack exchange,提问作者Mehdi Jahed Manesh
相关产品推荐
相关产品推荐

