【问题标题】:Custom TypeAdapter for Retrofit 2.0Retrofit 2.0 的自定义 TypeAdapter
【发布时间】:2017-07-07 12:38:10
【问题描述】:

我正在使用一个 API,它提供了我需要的更多信息。 我使用 Retrofit 和 GSON 来获取数据并创建一个包含所需值的 POJO 列表。 我制作了一个自定义的 TypeAdapter,在其中,我得到了响应并返回了一个对象列表。使用本地 JSON 对象时,它可以与自定义 TypeAdapter 一起正常工作,但使用 Retrofit 我会出错。

Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

任何想法为什么会这样?我做错了什么?

编辑:

我更改了 GsonBuilder,将正确的类型传递给 Retrofit Builder,如下所示:

Type collectionType = new TypeToken<List<Article>>(){}.getType();
    gsonBuilder.registerTypeAdapter(collectionType,new ArticleTypeAdapter());

JSON

{
"status": "OK",
"copyright": "Copyright (c) 2017 The New York Times Company.  All Rights Reserved.",
"num_results": 5,
"results": [
    {
        "url": "https://www.nytimes.com/2017/06/29/automobiles/autoreviews/video-review-a-family-friendly-ferrari-for-the-family-of-means.html",
        "adx_keywords": "Ferrari SpA;Ferrari GTC4Lusso;Automobiles",
        "column": "Driven",
        "section": "Automobiles",
        "byline": "By TOM VOELK",
        "type": "Article",
        "title": "Video Review: A Family-Friendly Ferrari, for the Family of Means",
        "abstract": "The all-wheel-drive V12 GTC4Lusso seats four comfortably. With its svelte silhouette, it may look like a station wagon. It is anything but.",
        "published_date": "2017-06-29",
        "source": "The New York Times",
        "id": 100000005178442,
        "asset_id": 100000005178442,
        "views": 1,
        "des_facet": [
            "AUTOMOBILES"
        ],
        "org_facet": [
            "FERRARI SPA"
        ],
        "per_facet": "",
        "geo_facet": "",
        "media": [
            {
                "type": "image",
                "subtype": "photo",
                "caption": "Ferrari GTC4Lusso",
                "copyright": "Martin Campbell",
                "approved_for_syndication": 1,
                "media-metadata": [
                    {
                        "url": "https://static01.nyt.com/images/2017/06/26/automobiles/autoreviews/27driven1/27driven1-thumbStandard.jpg",
                        "format": "Standard Thumbnail",
                        "height": 75,
                        "width": 75
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/06/26/automobiles/autoreviews/27driven1/27driven1-mediumThreeByTwo210.jpg",
                        "format": "mediumThreeByTwo210",
                        "height": 140,
                        "width": 210
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/06/26/automobiles/autoreviews/27driven1/27driven1-mediumThreeByTwo440.jpg",
                        "format": "mediumThreeByTwo440",
                        "height": 293,
                        "width": 440
                    }
                ]
            }
        ]
    },
    {
        "url": "https://www.nytimes.com/2017/07/06/automobiles/wheels/luxury-cars-dealers-sales.html",
        "adx_keywords": "Automobiles;Luxury Goods and Services;Customer Relations;United States;Lexus Division of Toyota Motor Corp;Cadillac Division of General Motors Corp;Alfa Romeo Automobiles;Lincoln Motor Co",
        "column": "Wheels",
        "section": "Automobiles",
        "byline": "By ERIC A. TAUB",
        "type": "Article",
        "title": "How to Soothe Luxury-Car Buyers: Add Perks and Subtract Haggling",
        "abstract": "Several automakers aim to change the shopping experience with fixed prices, after-sale care and even ways to avoid the dealership altogether.",
        "published_date": "2017-07-06",
        "source": "The New York Times",
        "id": 100000005135624,
        "asset_id": 100000005135624,
        "views": 2,
        "des_facet": [
            "AUTOMOBILES",
            "LUXURY GOODS AND SERVICES",
            "CUSTOMER RELATIONS"
        ],
        "org_facet": [
            "LEXUS DIVISION OF TOYOTA MOTOR CORP",
            "CADILLAC DIVISION OF GENERAL MOTORS CORP",
            "ALFA ROMEO AUTOMOBILES",
            "LINCOLN MOTOR CO"
        ],
        "per_facet": "",
        "geo_facet": [
            "UNITED STATES"
        ],
        "media": [
            {
                "type": "image",
                "subtype": "photo",
                "caption": "Lexus has introduced a fixed-price program, called Lexus Plus, in which the buyer deals with only one person from beginning to end.",
                "copyright": "Alex Wroblewski for The New York Times",
                "approved_for_syndication": 1,
                "media-metadata": [
                    {
                        "url": "https://static01.nyt.com/images/2017/07/06/business/07WHEELS1/07WHEELS1-thumbStandard.jpg",
                        "format": "Standard Thumbnail",
                        "height": 75,
                        "width": 75
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/07/06/business/07WHEELS1/07WHEELS1-mediumThreeByTwo210.jpg",
                        "format": "mediumThreeByTwo210",
                        "height": 140,
                        "width": 210
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/07/06/business/07WHEELS1/07WHEELS1-mediumThreeByTwo440.jpg",
                        "format": "mediumThreeByTwo440",
                        "height": 293,
                        "width": 440
                    }
                ]
            }
        ]
    },
    {
        "url": "https://www.nytimes.com/2017/06/29/automobiles/wheels/why-fog-lamps-are-starting-to-disappear.html",
        "adx_keywords": "Automobile Safety Features and Defects;AAA Foundation for Traffic Safety;Mercedes-Benz;Consumer Reports;Insurance Institute for Highway Safety",
        "column": "Wheels",
        "section": "Automobiles",
        "byline": "By JAMES G. COBB",
        "type": "Article",
        "title": "Why Fog Lamps Are Starting to Disappear",
        "abstract": "Several luxury automakers have moved away from fog lights, saying that new high-tech headlights render them obsolete.",
        "published_date": "2017-06-29",
        "source": "The New York Times",
        "id": 100000005172500,
        "asset_id": 100000005172500,
        "views": 3,
        "des_facet": [
            "AUTOMOBILE SAFETY FEATURES AND DEFECTS"
        ],
        "org_facet": [
            "AAA FOUNDATION FOR TRAFFIC SAFETY",
            "MERCEDES-BENZ",
            "CONSUMER REPORTS",
            "INSURANCE INSTITUTE FOR HIGHWAY SAFETY"
        ],
        "per_facet": "",
        "geo_facet": "",
        "media": [
            {
                "type": "image",
                "subtype": "photo",
                "caption": "General Motors’ headquarters and other buildings in the Detroit skyline, obscured by early morning fog. Some automakers have quietly omitted front fog lights from many new models, saying that high-tech headlights make them unnecessary.",
                "copyright": "Kevin Miyazaki for The New York Times",
                "approved_for_syndication": 1,
                "media-metadata": [
                    {
                        "url": "https://static01.nyt.com/images/2017/06/29/business/30WHEELS1/30WHEELS1-thumbStandard.jpg",
                        "format": "Standard Thumbnail",
                        "height": 75,
                        "width": 75
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/06/29/business/30WHEELS1/30WHEELS1-mediumThreeByTwo210.jpg",
                        "format": "mediumThreeByTwo210",
                        "height": 140,
                        "width": 210
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/06/29/business/30WHEELS1/30WHEELS1-mediumThreeByTwo440.jpg",
                        "format": "mediumThreeByTwo440",
                        "height": 293,
                        "width": 440
                    }
                ]
            }
        ]
    },
    {
        "url": "https://www.nytimes.com/2017/07/06/automobiles/autoreviews/video-review-volvo-v90-cross-country-rolls-into-suv-territory.html",
        "adx_keywords": "Automobiles;Volvo Car Corp;2017 Volvo V90 Cross Country",
        "column": "Driven",
        "section": "Automobiles",
        "byline": "By TOM VOELK",
        "type": "Article",
        "title": "Video Review: Volvo V90 Cross Country Rolls Into S.U.V. Territory",
        "abstract": "Americans are buying S.U.V.s and crossovers in record numbers, but it’s worth keeping an open mind about Volvo’s station wagon.",
        "published_date": "2017-07-06",
        "source": "The New York Times",
        "id": 100000005194798,
        "asset_id": 100000005194798,
        "views": 4,
        "des_facet": [
            "AUTOMOBILES"
        ],
        "org_facet": [
            "VOLVO CAR CORP"
        ],
        "per_facet": "",
        "geo_facet": "",
        "media": ""
    },
    {
        "url": "https://www.nytimes.com/2017/06/08/automobiles/saab-autos-cars.html",
        "adx_keywords": "Automobiles;Saab Automobile AB;Bankruptcies;Portland (Ore)",
        "column": "Wheels",
        "section": "Automobiles",
        "byline": "By NICK KURCZEWSKI",
        "type": "Article",
        "title": "In Portland, a Rare Outpost for Die-Hard Saab Fans",
        "abstract": "The Swedish automaker filed for bankruptcy in 2011, leaving a vanishingly small number of dealerships for fans of the company.",
        "published_date": "2017-06-08",
        "source": "The New York Times",
        "id": 100000005095241,
        "asset_id": 100000005095241,
        "views": 5,
        "des_facet": [
            "AUTOMOBILES",
            "BANKRUPTCIES"
        ],
        "org_facet": [
            "SAAB AUTOMOBILE AB"
        ],
        "per_facet": "",
        "geo_facet": [
            "PORTLAND (ORE)"
        ],
        "media": [
            {
                "type": "image",
                "subtype": "photo",
                "caption": "Saab filed for bankruptcy in 2011, but Garry Small Saab in Portland, Ore., has continued to service and sell the brand’s cars.",
                "copyright": "Amanda Lucier for The New York Times",
                "approved_for_syndication": 1,
                "media-metadata": [
                    {
                        "url": "https://static01.nyt.com/images/2017/06/08/business/09WHEELS1/09WHEELS1-thumbStandard.jpg",
                        "format": "Standard Thumbnail",
                        "height": 75,
                        "width": 75
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/06/08/business/09WHEELS1/09WHEELS1-mediumThreeByTwo210.jpg",
                        "format": "mediumThreeByTwo210",
                        "height": 140,
                        "width": 210
                    },
                    {
                        "url": "https://static01.nyt.com/images/2017/06/08/business/09WHEELS1/09WHEELS1-mediumThreeByTwo440.jpg",
                        "format": "mediumThreeByTwo440",
                        "height": 293,
                        "width": 440
                    }
                ]
            }
        ]
    }
]

}

Type Adapter 的读取方法

public List<Article> read(JsonReader in) throws IOException {

    final List<Article> article_list = new ArrayList<>();
    in.beginObject();
    while(in.hasNext()){
        switch (in.nextName()){
            case "results":
                in.beginArray();
                while(in.hasNext()){
                    final Article article = new Article();
                    in.beginObject();
                    while (in.hasNext()){
                        switch (in.nextName()){

                            case "id":
                                article.setId(Long.valueOf(in.nextString()));
                                break;
                            case "title":
                                article.setTitle(in.nextString());
                                break;
                            case "url":
                                article.setUrl(in.nextString());
                                break;
                            case "adx_keywords":
                                article.setAdxKeywords(in.nextString());
                                break;
                            case "section":
                                article.setSection(in.nextString());
                                break;
                            case "byline":
                                article.setByline(in.nextString());
                                break;
                            case "abstract":
                                article.set_abstract(in.nextString());
                                break;
                            case "published_date":
                                article.setPublishedDate(in.nextString());
                                break;
                            case "media":
                                if(!in.peek().equals(JsonToken.BEGIN_ARRAY)){
                                    in.skipValue();
                                    break;
                                }
                                in.beginArray();
                                final ArrayList<Media> media_list = new ArrayList<>();
                                while(in.hasNext()){
                                    in.beginObject();
                                    while(in.hasNext()){
                                        switch (in.nextName()){
                                            case "media-metadata":
                                                in.beginArray();
                                                while(in.hasNext()){
                                                    in.beginObject();
                                                    final Media media = new Media();
                                                    while(in.hasNext()){
                                                        switch (in.nextName()){
                                                            case "url":
                                                                media.setUrl(in.nextString());
                                                                break;
                                                            case "format":
                                                                media.setFormat(in.nextString());
                                                                break;
                                                            default:
                                                                in.skipValue();
                                                                break;
                                                        }
                                                    }
                                                    in.endObject();
                                                    media_list.add(media);
                                                }
                                                in.endArray();
                                                break;
                                            default:
                                                in.skipValue();
                                                break;
                                        }
                                    }
                                    in.endObject();
                                }
                                in.endArray();
                                for(Media m : media_list){
                                    if(m.getFormat().equals("mediumThreeByTwo440")){
                                        article.setMedia(m);
                                        break;
                                    }
                                }
                                break;

                            default:
                                in.skipValue();
                                break;
                        }/**/
                    }
                    in.endObject();
                    article_list.add(article);
                }
                in.endArray();
                break;
            default:
                in.skipValue();
                break;

        }

    }
    in.endObject();

    Timber.d(article_list.toString());
    return article_list;
}

文章和媒体类(无方法)

public class Article {
private Long id;
private String url;
private String adxKeywords;
private String section;
private String byline;
private String title;
private String _abstract;
private String publishedDate;
private Media media;
}

public class Media {
private String url;
private String format;
}

改造生成器

final GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Article.class,new ArticleTypeAdapter());
    final Gson gson = gsonBuilder.create();
    retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

【问题讨论】:

标签: android retrofit2


【解决方案1】:

你需要做这样的事情:-

public class Response{
    public String status;
    public String copyright;
    public int num_results;
    public Article[] results;
}

您必须传递一个与您从服务器接收到的响应结构相同的响应类。 请按照以下步骤操作:-

您不需要为每个请求使用不同类型的适配器,您可以简单地使用默认 Gson 转换器工厂创建改造,如下所示:-

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .build();

现在您需要为 API 请求定义一个服务,如下所示:-

public class ArticleService{
   @GET("endpoint")//What ever is your request type
   Call<Response> getArticals(/** body query param or other required data**// )
}

之后,您请求创建将是这样的:-

ArticleService service = retrofit.create(ArticleService.class);

【讨论】:

  • 这可行,是的。但我会觉得有一个有很多属性未使用的类会很丑。我解决了这个问题,并编辑了帖子。谢谢
  • 如果您的 API 正在发送一些属性,那么它们不应该是丑陋的,如果您觉得丑陋,那么是时候更改 API 的结构了,但您认为与其创建多个 GSON 适配器不如有一个可以使用默认适配器的类。
  • 我在这个项目中使用 NewYorkTimesAPI。但我不会使用所有属性。而且我只使用这个 GSON 适配器来获取新闻。对我来说,没有它附带的所有数据,代码看起来更干净。
  • 我投了反对票,因为我没有回答这个问题,而是重新发布了改造文档。 OP 已经意识到这种可能性,这就是为什么他要求以另一种方式来做这件事(这肯定更干净,而且您通常无法更改公共 API)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-25
  • 2016-05-31
  • 1970-01-01
  • 2019-12-28
相关资源
最近更新 更多