【问题标题】:IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY while using Retrofit 2IllegalStateException:应为 BEGIN_OBJECT,但在使用 Retrofit 2 时为 BEGIN_ARRAY
【发布时间】:2021-01-04 23:42:45
【问题描述】:

我正在尝试使用 Retrofit 对一些已解析的 JSON 执行一些代码,但我遇到了非法状态异常。这是我的改造实例:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.pro.coinbase.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        CoinbaseProAPI coinbaseProAPI = retrofit.create(CoinbaseProAPI.class);

Coinbase Pro API 接口:

@GET("products/{productId}/candles")
    Call<ArrayList<HistoricRates>> getHistoricRates(@Header("CB-ACCESS-SIGN") String signature,
        @Header("CB-ACCESS-TIMESTAMP") String timeStamp,
        @Path("productId") String productId,
        @Query("start") String intervalStart,
        @Query("end") String intervalEnd,
        @Query("granularity") int granularity
    );

对服务器的调用请求(这是导致错误的原因):

Call<ArrayList<HistoricRates>> call = coinbaseProAPI.getHistoricRates(signature, timeStamp, productId, intervalStart, intervalEnd, granularity);
            try {
                //this is being executed inside a for loop; requests are rate limited so consecutive 
                //iterations must wait
                if (i > 0) {
                    call.wait(1010);
                }
                //this is the line the debugger doesn't like:
                Response<ArrayList<HistoricRates>> response = call.execute();
                if (!response.isSuccessful()) {
                    Message eMsg = errorHandler.obtainMessage();
                    String e = R.string.error_header + response.toString();
                    eMsg.what = 2;
                    eMsg.obj = e;
                    errorHandler.sendMessage(eMsg);
                } else {
                    ArrayList<HistoricRates> candles = response.body();
                    int n = 0;
                    double[][] aCandles = new double[3][3];
                    for (HistoricRates historicRates : candles) {
                        aCandles[n][0] = historicRates.getOpen();
                        aCandles[n][1] = historicRates.getClose();
                        aCandles[n][2] = historicRates.getVolume();
                        n++;
                    }
                    selectedAsset.setCandles(aCandles);
                }
            } catch (Exception e) {
                Message eMsg = errorHandler.obtainMessage();
                eMsg.what = 2;
                eMsg.obj = e.getMessage();
                errorHandler.sendMessage(eMsg);
                e.printStackTrace();
            }

最后是 JSON 被解析成的类对象:

public class HistoricRates {
    private int time;
    private double low;
    private double high;
    private double open;
    private double close;
    private double volume;

    public double getOpen() {
        return open;
    }

    public double getClose() {
        return close;
    }

    public double getVolume() {
        return volume;
    }
}

因此,根据我从类似帖子中收集到的信息,发生非法状态异常是因为我试图传递给 Gson 的对象类型不正确。但我不明白这是怎么回事,因为我正在使用 Retrofit; GsonConverterFactory 不应该为我处理这个吗?此外,即使我将此代码包含在 try/catch 块中,它实际上并没有引发异常;它只是默默地失败了。我什至知道非法状态异常的唯一原因是调试控制台。我该如何改进我的错误报告或者还有什么我不理解的地方?

编辑添加: 尝试了 Capps99 的解决方案(在 HistoricRatesList 中添加了访问器方法,因此我可以获得一个迭代器来循环遍历这些值)如下所示:

HistoricRatesList candles = response.body();
                    Iterator candleIterator = candles.getList().iterator();
                    int n = 0;
                    double[][] aCandles = new double[3][3];
                    while (candleIterator.hasNext()) {
                        HistoricRates historicRates = (HistoricRates) candleIterator.next();
                        aCandles[n][0] = historicRates.getOpen();
                        aCandles[n][1] = historicRates.getClose();
                        aCandles[n][2] = historicRates.getVolume();
                        n++;
                    }

很遗憾,我仍然遇到非法状态例外。应另一位评论者的要求,这是来自服务器的预期 JSON 响应(抱歉,我应该一开始就包括这个):

[
     //these are all decimal values except for time; which is an integer value 
     //representing the UNIX epoch time
     [time, low, high, open, close, volume],
     [time, low, high, open, close, volume],
     ...
]

也许问题在于服务器似乎以二维数组的形式返回数据,我没有经验知道如何正确解析。

【问题讨论】:

  • 确切的错误信息是什么?
  • 你能添加一个你的api返回json数据的例子吗?
  • 您使用的 API 是否正确? /candles 的响应是嵌套的 JSONArray。如果您看到 coinbase 文档,您的预期响应与“products/{productId}/stats”匹配
  • retrofit 告诉您响应是 Array,这是正确的。但是,声明的 HistoricRates 的类型是一个对象

标签: java android retrofit2


【解决方案1】:

试试这个。

创建以下类来解析列表。

public class HistoricRatesList {
 List<HistoricRates> historicRates;
}

然后像这样使用。

@GET("products/{productId}/candles")
    Call<HistoricRatesList> getHistoricRates(@Header("CB-ACCESS-SIGN") String signature,
        @Header("CB-ACCESS-TIMESTAMP") String timeStamp,
        @Path("productId") String productId,
        @Query("start") String intervalStart,
        @Query("end") String intervalEnd,
        @Query("granularity") int granularity
    );

【讨论】:

    猜你喜欢
    • 2017-08-04
    • 1970-01-01
    • 2018-01-12
    • 2019-06-14
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 2016-12-27
    • 2013-08-10
    相关资源
    最近更新 更多