You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 03:45:36