如何用Retrofit+RxJava解析REST API返回的Cosmetic JSON数组?
解决Retrofit+RxJava解析JSON数组(0/1/多个对象)的问题
问题根源
- 你的API返回的是顶级JSON数组(
[{},{}]),而非嵌套在cosmetic字段中的对象,所以自定义的ArrayOfCosmetics类格式不匹配,导致解析失败。 - 直接使用
ArrayList<Cosmetic>时,大概率是Retrofit Service接口的返回类型定义错误,或者泛型书写失误。 - 你用
while循环阻塞线程等待异步结果的做法严重错误,会导致Android应用ANR(应用无响应),必须移除。
正确解决方案
1. 修正Retrofit Service接口定义
将接口方法的返回类型从Single<Cosmetic>改为Single<List<Cosmetic>>(推荐用List而非ArrayList,Gson会自动适配为ArrayList实例):
public interface CosmeticsService { @GET("/prod/beauty/{field}") Single<List<Cosmetic>> getCosmeticsByName(@Path("field") String query); }
2. 调整RxJava订阅代码
订阅时使用SingleObserver<List<Cosmetic>>,直接处理返回的列表(自动兼容0、1或多个对象):
CompositeDisposable compositeDisposable = new CompositeDisposable(); Single<List<Cosmetic>> callSync = service.getCosmeticsByName(query); callSync.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .onErrorReturn(throwable -> Collections.emptyList()) // 错误时返回空列表,统一处理逻辑 .subscribe(new SingleObserver<List<Cosmetic>>() { @Override public void onSubscribe(Disposable d) { compositeDisposable.add(d); } @Override public void onSuccess(List<Cosmetic> cosmetics) { System.out.println("API 返回 " + cosmetics.size() + " 条结果"); // 处理不同数量的结果 if (cosmetics.isEmpty()) { // 无结果的业务逻辑 } else if (cosmetics.size() == 1) { // 单个对象的业务逻辑 Cosmetic singleCosmetic = cosmetics.get(0); System.out.println("单个商品编码:" + singleCosmetic.getCode()); } else { // 多个对象的业务逻辑 for (Cosmetic cosmetic : cosmetics) { System.out.println("商品编码:" + cosmetic.getCode()); } } } @Override public void onError(Throwable e) { e.printStackTrace(); } });
3. 移除错误的阻塞逻辑
彻底删除while(result[0]==""){}这行代码,RxJava是异步框架,阻塞线程会引发ANR。如果需要将结果传递到上层组件(如ViewModel、Activity),可以采用以下方式:
- 定义回调接口
- 使用LiveData或StateFlow
- 利用RxJava的
flatMap/map操作符链式传递结果
示例回调接口实现:
// 定义回调接口 public interface CosmeticsLoadCallback { void onLoadSuccess(List<Cosmetic> cosmetics); void onLoadFailed(Throwable error); } // 在Repository中使用 public void loadCosmetics(String query, CosmeticsLoadCallback callback) { CompositeDisposable compositeDisposable = new CompositeDisposable(); service.getCosmeticsByName(query) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new SingleObserver<List<Cosmetic>>() { @Override public void onSuccess(List<Cosmetic> cosmetics) { callback.onLoadSuccess(cosmetics); compositeDisposable.dispose(); } @Override public void onError(Throwable e) { callback.onLoadFailed(e); compositeDisposable.dispose(); } @Override public void onSubscribe(Disposable d) { compositeDisposable.add(d); } }); } // 在Activity/ViewModel中调用 loadCosmetics("your_query", new CosmeticsLoadCallback() { @Override public void onLoadSuccess(List<Cosmetic> cosmetics) { // 更新UI或处理数据 } @Override public void onLoadFailed(Throwable error) { // 显示错误提示 } });
为什么之前的尝试失败?
ArrayOfCosmetics类:你的API返回的是[{},{}],但这个类期望的是{"cosmetic": [{},{}]}格式,结构不匹配,Gson无法解析。- 直接用
ArrayList<Cosmetic>报错:大概率是Service接口仍返回Single<Cosmetic>,或者订阅时泛型写错(比如你代码中的SingleObserver<ArrayOfObjects>是明显的类型错误)。
内容的提问来源于stack exchange,提问作者sempre_em_pe
相关产品推荐
相关产品推荐

