【问题标题】:Retrofit + Observable - Expected BEGIN_ARRAY but was BEGIN_OBJECTRetrofit + Observable - 预期为 BEGIN_ARRAY 但为 BEGIN_OBJECT
【发布时间】:2018-06-19 10:39:34
【问题描述】:

我正在尝试将 New York Times API 与使用 Observable 的 Retrofit 结合使用。但是我在尝试使用数据时遇到了这个错误。

谁能帮我看看我哪里错了?

这是我的 ApiServices 接口:

@GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<TopStoryResult> getTopStories();

@GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<List<NewsItem>> getResults();


Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.nytimes.com/")
        .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()))
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build();

这是我的 ApiStreams 类

public static Observable<TopStoryResult> streamFetchTopStories(){
    ApiServices mApiServices = ApiServices.retrofit.create(ApiServices.class);
    return mApiServices.getTopStories()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .timeout(10, TimeUnit.SECONDS);
}

public static Observable<List<NewsItem>> streamFetchNews(){
    ApiServices mApiServices = ApiServices.retrofit.create(ApiServices.class);
    return mApiServices.getResults()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .timeout(10, TimeUnit.SECONDS);
}

这就是我在 MainActivity 中尝试做的事情。现在我只想在 TextView 中显示每个标题的列表...

//------------------------
// Update UI
//------------------------
private void updateUIWhenStartingHttpRequest() {
    this.textView.setText("Downloading...");
}


private void updateUIWhenStopingHttpRequest(String response) {
    this.textView.setText(response);
}



//------------------------
// Rx Java
//------------------------
private void executeRequestWithRetrofit(){
    this.updateUIWhenStartingHttpRequest();

    this.disposable = ApiStreams.streamFetchNews()
            .subscribeWith(new DisposableObserver<List<NewsItem>>(){

                @Override
                public void onNext(List<NewsItem> topStories) {
                    Log.e("TAG", "On Next");
                    updateUIWithResult(topStories);
                }

                @Override
                public void onError(Throwable e) {
                    Log.e("ERROR", Log.getStackTraceString(e));
                }

                @Override
                public void onComplete() {
                    Log.e("TAG", "On Complete !");
                }
            });
}



private void updateUIWithResult(List<NewsItem> newsItemList){
    StringBuilder mStringBuilder = new StringBuilder();
    for (NewsItem news : newsItemList){
        Log.e("TAG", "UPDATE UI" + news.getTitle());
        mStringBuilder.append("- " + news.getTitle() + "\n");
    }
    updateUIWhenStopingHttpRequest(mStringBuilder.toString());
}

[编辑] TopStories 和 NewsItem 有我的两个模型

热门故事:

private String status;
private String copyright;
private String section;
private String lastUpdated;
private Integer numResults;
private List<NewsItem> results = null;

public String getStatus() {return status;
}

public void setStatus(String status) {
    this.status = status;
}

public String getCopyright() {
    return copyright;
}

public void setCopyright(String copyright) {
    this.copyright = copyright;
}

public String getSection() {
    return section;
}

public void setSection(String section) {
    this.section = section;
}

public String getLastUpdated() {
    return lastUpdated;
}

public void setLastUpdated(String lastUpdated) {
    this.lastUpdated = lastUpdated;
}

public Integer getNumResults() {
    return numResults;
}

public void setNumResults(Integer numResults) {
    this.numResults = numResults;
}

public List<NewsItem> getResults() {
    return results;
}

public void setResults(List<NewsItem> results) {
    this.results = results;
}

新闻项目:

 private String section;
private String subsection;
private String title;
private String url;
private String byline;
private String updated_date;
private String created_date;
private String published_date;
private String material_type_facet;
private String kicker;


@SerializedName("abstract")
private String abstract_string;

private List<Multimedia> multimedia;


private transient String des_facet;
private transient String org_facet;
private transient String per_facet;
private transient String geo_facet;

public NewsItem() {
}

public NewsItem(String url) {
    this.url = url;
}

public NewsItem(String section, String subsection, String title, String url, String byline, String updated_date, String created_date, String published_date, String material_type_facet, String kicker) {
    this.section = section;
    this.subsection = subsection;
    this.title = title;
    this.url = url;
    this.byline = byline;
    this.updated_date = updated_date;
    this.created_date = created_date;
    this.published_date = published_date;
    this.material_type_facet = material_type_facet;
    this.kicker = kicker;
}

public String getSection() {
    return section;
}

public void setSection(String section) {
    this.section = section;
}

public String getSubsection() {
    return subsection;
}

public void setSubsection(String subsection) {
    this.subsection = subsection;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public String getUrl() {
    return url;
}

public void setUrl(String url) {
    this.url = url;
}

public String getByline() {
    return byline;
}

public void setByline(String byline) {
    this.byline = byline;
}

public String getUpdated_date() {
    return updated_date;
}

public void setUpdated_date(String updated_date) {
    this.updated_date = updated_date;
}

public String getCreated_date() {
    return created_date;
}

public void setCreated_date(String created_date) {
    this.created_date = created_date;
}

public String getPublished_date() {
    return published_date;
}

public void setPublished_date(String published_date) {
    this.published_date = published_date;
}

public String getMaterial_type_facet() {
    return material_type_facet;
}

public void setMaterial_type_facet(String material_type_facet) {
    this.material_type_facet = material_type_facet;
}

public String getKicker() {
    return kicker;
}

public void setKicker(String kicker) {
    this.kicker = kicker;
}


public String getAbstract() {
    return abstract_string;
}

public void setAbstract(String abstract_string) {
    this.abstract_string = abstract_string;
}

public List<Multimedia> getMultimedia() {
    return multimedia;
}

public void setMultimedia(List<Multimedia> multimedia) {
    this.multimedia = multimedia;
}

public String getDes_facet() {
    return des_facet;
}

public void setDes_facet(String des_facet) {
    this.des_facet = des_facet;
}

public String getOrg_facet() {
    return org_facet;
}

public void setOrg_facet(String org_facet) {
    this.org_facet = org_facet;
}

public String getPer_facet() {
    return per_facet;
}

public void setPer_facet(String per_facet) {
    this.per_facet = per_facet;
}

public String getGeo_facet() {
    return geo_facet;
}

public void setGeo_facet(String geo_facet) {
    this.geo_facet = geo_facet;
}

这是 JSON 的样子:

JSON

首先,当我使用 Github 用户 API 尝试这个时,它运行良好。但是我不知道我错在哪里......

有人可以帮帮我吗?

非常感谢!

【问题讨论】:

  • 你也可以分享你的模型吗?因为我怀疑问题在于将您的模型解析为 json。
  • 您的 json 返回 Jsonobject,您正尝试使用 List 作为返回类型来捕获 Json 数组
  • @LesterL。刚刚用我的两个模型编辑了我的问题

标签: java android retrofit observable


【解决方案1】:

应为 BEGIN_ARRAY,但为 BEGIN_OBJECT 这意味着您正在尝试将 JSON 数组作为 JAVA 中的列表获取,但 api 向您发送了 JSON OBJECT。所以我无法收集到足够的信息,但如果我不得不猜测你应该改变这个

@GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<List<NewsItem>> getResults();

@GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
Observable<NewsItemObject> getResults();

NewsItemObject 是包装 NewsItem 的类

【讨论】:

    【解决方案2】:

    在您的 ApiServices 界面中,您希望 getResults() 返回 Observable&lt;List&lt;NewsItem&gt;&gt;。基于 JSON,您将无法返回,因为您的根 JSON 元素是 Object,而不是 Array

    您必须创建新的包装类 (ResultsWrapper),“结果”字段类型为 List&lt;NewsItem&gt;。您在 ApiServices 接口中的方法将是:

    @GET("svc/topstories/v2/home.json?api-key=HiddenApiKeyJustForThisMessage")
    Observable<ResultsWrapper> getResults();
    

    这就是“预期为 BEGIN_ARRAY,但为 BEGIN_OBJECT”的意思。

    【讨论】:

    • 我在链接我的 NewsItem 模型时犯了一个错误,现在它是好的。它不是在做包装工作吗?
    • @SebShad GsonConverter 您在 Retrofit 实例中用作转换器的是将 Java 列表映射到 JSON 数组,反之亦然。例如提到的其他对象 ResultsWrapper 或您的 TopStoryResult 被映射到 JSON 对象。因为您的根 JSON 元素是 Object -> 以“{”开头,所以您的 Observable> getResults();无法工作,因为 GSON 正在尝试将 LIST 映射到 JSON 数组,但找到了 JSON 对象。现在可以理解了吗?
    猜你喜欢
    • 2019-06-14
    • 2016-09-26
    • 1970-01-01
    • 2017-02-14
    • 2019-05-10
    • 1970-01-01
    • 2014-08-01
    • 2015-11-26
    • 2018-03-27
    相关资源
    最近更新 更多