android - Retrofit 2.0 的自定义类型适配器

标签 android retrofit2

我使用的 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();

最佳答案

你需要做这样的事情:-

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);

关于android - Retrofit 2.0 的自定义类型适配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44962386/

相关文章:

android - 在 Android 中分享图库中的图片

android - Android Record Audio没有SDCARD

android - 每次滚动时 RecyclerAdapter 都会重新加载项目 - Android Studio

java - Retrofit @Header 中的属性必须是常量

android - Retrofit.Builder() 中的 JacksonConverterFactory

android - 如何升级安装在.gradle文件夹中的appengine-java-sdk

java - com.google.firebase.database.DatabaseException : Can't convert object of type java. lang.String 输入 com.example.myapplication.Orders

php - 使用Retrofit、PHP、JSON和WAMP从Android应用程序获取Mysql数据库的信息

android - HTTPS 不适用于 OkHttp3 和 Retrofit2

在 Java 中改造 protobuf-lite 转换器