改造 2:如何处理动态响应

Retrofit 2: How to handle dynamic response

我正在尝试从此 api 获取数据:http://www.omdbapi.com/ 我正在使用 Retrofit 2 并为第一个 json 创建了一个 pojo。我很好奇的是当数据不可用时如何将我的 pojo 转换为第二个。

当有可用数据时,它 returns 这个 json:

http://www.omdbapi.com/?t=Suits

{
Title: "Suits",
Year: "2011–",
Rated: "TV-14",
Released: "23 Jun 2011",
Runtime: "44 min",
Genre: "Comedy, Drama",
Director: "N/A",
Writer: "Aaron Korsh",
Actors: "Gabriel Macht, Patrick J. Adams, Rick Hoffman, Meghan Markle",
Plot: "On the run from a drug deal gone bad, Mike Ross, a brilliant college-dropout, finds himself a job working with Harvey Specter, one of New York City's best lawyers.",
Language: "English",
Country: "USA",
Awards: "7 nominations.",
Poster: "http://ia.media-imdb.com/images/M/MV5BMTk1MjYzOTU2Nl5BMl5BanBnXkFtZTgwMzAxMTg5MTE@._V1_SX300.jpg",
Metascore: "N/A",
imdbRating: "8.7",
imdbVotes: "244,979",
imdbID: "tt1632701",
Type: "series",
totalSeasons: "6",
Response: "True"
}

当没有可用数据时,它returns这个json:

http://www.omdbapi.com/?t=asdasdas

{
Response: "False",
Error: "Movie not found!"
}

你有几个选择。在我看来,最简单的方法是在原始 pojo 中包含 Error 字段并始终检查字段 Response。当这是 "True" 时,所有其他字段都会出现。当 "False" 时,只有 Error 字段会在那里。

另一种可能最不灵活和难以理解的选择是拥有一个可以继承的 pojo Error。您仍然需要检查 Response 的值以检查是否有错误。我个人会在这里避免使用此选项,但我认为很高兴知道您仍然可以这样做。像这样:

class Error {
  @SerializedName("Error")
  @Expose
  private String error;
  // ...
}

class Movie extends Error {
  // other fields here
}

如您所见,这非常丑陋,但有效...

您可以尝试的第三个选项是检查 Http 状态代码。这取决于API。如果即使出现错误 api returns Http 代码 200,那么这就不是那么简单了。然而,它是我的最爱,因为在我看来它提供了更多的正确性。

在没有数据时说 api return Http 404。然后您可以检查此状态并使用不同的 pojo 反序列化错误主体(pojo 可能只是错误消息)。如果您使用内置 Callbacks 的改造,则必须在 onResponse 上执行此操作。如果您使用 RxJava,那么这会更直接,因为您可以在 onError 方法中轻松完成(所有非 2XX http 响应都在 onError 方法中)。

您可以使用 errorBody 访问改造响应的错误主体。您可以使用 Gson 或仅使用此代码段将其转换为 pojo:

Converter<ResponseBody, MyError> converter = new GsonConverterFactory()
   .responseBodyConverter(MyError.class, Annotation[0]);
MyError error = converter.convert(response.errorBody());

(此处 MyError 将是包含错误字段的 pojo 的名称)。

您可能只想创建转换器工厂一次。很可能应该是您在创建 Retrofit 实例时使用的那个。

如果你真的在使用 RxJava 你可以查看我的回答 关于如何访问 Rx 响应中的错误主体