我该如何在Retrofit库中使用Gson?

7

我在安卓应用中使用了Retrofit发送请求和接收响应,但是当我想要转换从服务器返回的响应时,总是出现异常问题:

retrofit.RetrofitError: com.google.gson.JsonSyntaxException: 
               java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING

当服务器返回电影列表时,我需要将所有这些电影放入列表中。

电影(模型类):

public class Movie {
    public Movie() {}
    @SerializedName("original_title")
    private String movieTitle;
    @SerializedName("vote_average")
    private String movieVoteAverage;
    @SerializedName("overview")
    private String movieOverview;
    ............  
}

GitMovieApi 类:

public interface GitMovieApi {
    @GET("/3/movie/{movie}")  
    public void getMovie(@Path("movie") String typeMovie,@Query("api_key") String  keyApi, Callback<Movie> response);    
}

RestAdapter 配置:

RestAdapter restAdapter = new RestAdapter.Builder()
                    .setLogLevel(RestAdapter.LogLevel.FULL)
                    .setConverter(new GsonConverter(new GsonBuilder().registerTypeAdapter(Movie.class, new UserDeserializer()).create()))
                    .setEndpoint("http://api.themoviedb.org")
                    .build(); 
                     GitMovieApi git = restAdapter.create(GitMovieApi.class);  
                git.getMovie("popular", "Keyapi", new Callback<Movie>() {
                @Override
                public void success(Movie movie, Response response) {
                    Toast.makeText(getActivity(), "s", Toast.LENGTH_LONG).show();
                }
                @Override
                public void failure(RetrofitError error) {
                    Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_LONG).show();
                }
            });

UserDeserializer:

public class UserDeserializer implements JsonDeserializer<Movie> {
        @Override
        public Movie deserialize(JsonElement jsonElement, Type typeOF,
                                 JsonDeserializationContext context)
                throws JsonParseException {
            JsonElement userJson = new JsonParser().parse("results");
            return new Gson().fromJson(userJson, Movie.class);
        }
    }    

JSON(响应):

{
  "page": 1,
  "results": [
    {
      "adult": false,
      "backdrop_path": "/tbhdm8UJAb4ViCTsulYFL3lxMCd.jpg",
      "genre_ids": [
        53,
        28,
        12
      ],
      "id": 76341,
      "original_language": "en",
      "original_title": "Mad Max: Fury Road",
      "overview": "An apocalyptic story set in the furthest.",
      "release_date": "2015-05-15",
      "poster_path": "/kqjL17yufvn9OVLyXYpvtyrFfak.jpg",
      "popularity": 48.399601,
      "title": "Mad Max: Fury Road",
      "video": false,
      "vote_average": 7.6,
      "vote_count": 2114
    },
    {
      "adult": false,
      "backdrop_path": "/sLbXneTErDvS3HIjqRWQJPiZ4Ci.jpg",
      "genre_ids": [
        10751,
        16,
        12,
        35
      ],
      "id": 211672,
      "original_language": "en",
      "original_title": "Minions",
      "overview": "Minions Stuart.",
      "release_date": "2015-06-25",
      "poster_path": "/s5uMY8ooGRZOL0oe4sIvnlTsYQO.jpg",
      "popularity": 31.272707,
      "title": "Minions",
      "video": false,
      "vote_average": 6.8,
      "vote_count": 1206
    },     
],
  "total_pages": 11871,
  "total_results": 237415
}  

results 的内容不是电影。它是电影列表。 - njzk2
new JsonParser().parse("results") 这不是正确的用法。这会尝试解析一个字符串 "results"。你需要使用给定的 JsonElement。 - njzk2
我知道结果是电影列表,但当你看到Gson时,你会发现它是一个对象,我试图获取那个对象{...},然后访问电影列表。 - mohammad tofi
2个回答

5

您甚至不需要在此处创建自定义反序列化程序。

完全摆脱 UserDeserializer,它是不必要的。您的查询返回一个电影列表,因此将回调函数更改为实际读取电影列表的对象:

public class MovieList {
    @SerializedName("results")
    List<Movie> movieList;
    // you can also add page, total_pages, and total_results here if you want
}

然后你的GitMovieApi类将会是这样的:
public interface GitMovieApi {
    @GET("/3/movie/{movie}")  
    public void getMovie(@Path("movie") String typeMovie,
                @Query("api_key") String keyApi,
                Callback<MovieList> response);    
}

您的 RestAdapter
RestAdapter restAdapter = new RestAdapter.Builder()
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setConverter(new GsonConverter(new GsonBuilder()).create()))
                .setEndpoint("http://api.themoviedb.org")
                .build(); 
                 GitMovieApi git = restAdapter.create(GitMovieApi.class); 

问题不在于您编写了错误的Deserializer(尽管您确实有错误,但没关系,因为您不需要它,JsonParser并不是您所需要的方式),而是默认的反序列化行为应该可以正常工作。使用上面的代码就可以正常工作。

2
在Retrofit 2中,这变得更加简单。您的GitMovieApi类:
interface MoviesApi {
    @GET("/3/movie/{movie}")
    Call<MovieList> getMovies(@Path("movie") String typeMovie,
                              @Query("api_key") String keyApi);
}

然后你只需要创建一个Retrofit对象,然后进行回调:

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(MOVIES_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
service = retrofit.create(MoviesApi.class);

Call<MovieList> mlc = service.getMovies(getArguments().getString(ARG_MOVIE_TYPE), getString(R.string.THE_MOVIE_DB_API_TOKEN));
mlc.enqueue(new Callback<MovieList>() {
        @Override
        public void onResponse(Call<MovieList> call, Response<MovieList> response) {
            movies = response.body().movieList;
        }

        @Override
        public void onFailure(Call<MovieList> call, Throwable t) {}
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接