一、引言
在现代的 Android 和 Java 开发中,网络请求是必不可少的一部分。Retrofit 作为一个强大的网络请求框架,以其简洁的 API 和高度的可定制性受到了广泛的欢迎。数据转换模块是 Retrofit 框架中至关重要的一部分,它负责将请求参数序列化为 HTTP 请求体,以及将 HTTP 响应体反序列化为 Java 对象。通过对 Retrofit 数据转换模块的源码分析,我们可以深入了解其工作原理,从而更好地使用和扩展这个框架。
二、数据转换模块的核心概念
2.1 Converter
接口
Converter
接口是数据转换模块的核心接口,它定义了数据转换的基本方法。以下是 Converter
接口的源码:
java
// Converter 接口定义了数据转换的基本方法
public interface Converter<F, T> {// 将输入类型 F 转换为输出类型 TT convert(F value) throws IOException;
}
这个接口非常简单,只定义了一个 convert
方法,用于将输入类型 F
转换为输出类型 T
。在实际应用中,F
通常是 ResponseBody
(用于响应体转换)或请求参数类型(用于请求体转换),T
则是 Java 对象类型。
2.2 Converter.Factory
抽象类
Converter.Factory
抽象类是用于创建 Converter
对象的工厂类。以下是其源码:
java
// 工厂类,用于创建 Converter 对象
public abstract static class Factory {// 创建请求体转换器,用于将请求参数转换为 RequestBodypublic @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return null;}// 创建响应体转换器,用于将 ResponseBody 转换为 Java 对象public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,Annotation[] annotations, Retrofit retrofit) {return null;}// 创建字符串转换器,用于将对象转换为字符串public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;}
}
Converter.Factory
抽象类提供了三个方法,分别用于创建请求体转换器、响应体转换器和字符串转换器。这些方法的默认实现返回 null
,具体的实现由子类完成。
2.3 Retrofit
类中的相关方法
Retrofit
类是 Retrofit 框架的核心类,它包含了与数据转换模块相关的方法。以下是部分相关源码:
java
public final class Retrofit {// 转换器工厂列表private final List<Converter.Factory> converterFactories;Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,Executor callbackExecutor, boolean validateEagerly) {this.callFactory = callFactory;this.baseUrl = baseUrl;// 保存转换器工厂列表this.converterFactories = unmodifiableList(converterFactories);this.callAdapterFactories = unmodifiableList(callAdapterFactories);this.callbackExecutor = callbackExecutor;this.validateEagerly = validateEagerly;}// 创建响应转换器private static <T> Converter<ResponseBody, T> createResponseConverter(Retrofit retrofit, Method method, Type responseType) {Annotation[] annotations = method.getAnnotations();try {// 遍历转换器工厂列表,查找合适的转换器工厂for (Converter.Factory factory : retrofit.converterFactories()) {// 调用工厂的 responseBodyConverter 方法创建响应体转换器Converter<ResponseBody, ?> converter = factory.responseBodyConverter(responseType, annotations, retrofit);if (converter != null) {// 找到合适的转换器,返回return (Converter<ResponseBody, T>) converter;}}} catch (RuntimeException e) {throw methodError(method, e, "Unable to create converter for %s", responseType);}throw methodError(method, "Could not locate response converter for %s.", responseType);}// 创建请求体转换器private static <T> Converter<T, RequestBody> createRequestBodyConverter(Retrofit retrofit, Method method, Type requestType, Annotation[] parameterAnnotations) {Annotation[] methodAnnotations = method.getAnnotations();try {// 遍历转换器工厂列表,查找合适的转换器工厂for (Converter.Factory factory : retrofit.converterFactories()) {// 调用工厂的 requestBodyConverter 方法创建请求体转换器Converter<?, RequestBody> converter = factory.requestBodyConverter(requestType, parameterAnnotations, methodAnnotations, retrofit);if (converter != null) {// 找到合适的转换器,返回return (Converter<T, RequestBody>) converter;}}} catch (RuntimeException e) {throw methodError(method, e, "Unable to create converter for %s", requestType);}throw methodError(method, "Could not locate request body converter for %s.", requestType);}
}
Retrofit
类中保存了一个 converterFactories
列表,用于存储所有的转换器工厂。createResponseConverter
方法和 createRequestBodyConverter
方法分别用于创建响应体转换器和请求体转换器,它们会遍历 converterFactories
列表,调用每个工厂的相应方法,直到找到合适的转换器为止。
三、常见的转换器工厂实现
3.1 GsonConverterFactory
GsonConverterFactory
是 Retrofit 中常用的转换器工厂,它使用 Gson 库来进行 JSON 数据的序列化和反序列化。以下是其源码分析:
java
// Gson 转换器工厂类
public final class GsonConverterFactory extends Converter.Factory {private final Gson gson;private GsonConverterFactory(Gson gson) {this.gson = gson;}// 创建 GsonConverterFactory 实例public static GsonConverterFactory create() {return create(new Gson());}// 创建 GsonConverterFactory 实例,传入自定义的 Gson 实例public static GsonConverterFactory create(Gson gson) {return new GsonConverterFactory(gson);}// 创建响应体转换器@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {return new GsonResponseBodyConverter<>(gson, type);}// 创建请求体转换器@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return new GsonRequestBodyConverter<>(gson, type);}
}// Gson 响应体转换器
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {private final Gson gson;private final TypeAdapter<T> adapter;GsonResponseBodyConverter(Gson gson, Type type) {this.gson = gson;// 通过 Gson 获取指定类型的 TypeAdapter,用于解析 JSON 数据this.adapter = gson.getAdapter(TypeToken.get(type));}@Overridepublic T convert(ResponseBody value) throws IOException {// 创建 JsonReader 对象,用于读取响应体的字符流JsonReader jsonReader = gson.newJsonReader(value.charStream());try {// 使用 TypeAdapter 从 JsonReader 中读取数据并转换为指定类型return adapter.read(jsonReader);} finally {// 关闭响应体value.close();}}
}// Gson 请求体转换器
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");private static final Charset UTF_8 = Charset.forName("UTF-8");private final Gson gson;private final TypeAdapter<T> adapter;GsonRequestBodyConverter(Gson gson, Type type) {this.gson = gson;// 通过 Gson 获取指定类型的 TypeAdapter,用于将对象转换为 JSON 数据this.adapter = gson.getAdapter(TypeToken.get(type));}@Overridepublic RequestBody convert(T value) throws IOException {// 创建 ByteArrayOutputStream 用于存储序列化后的 JSON 数据ByteArrayOutputStream out = new ByteArrayOutputStream();// 创建 JsonWriter 对象,用于将对象以 JSON 格式写入输出流JsonWriter jsonWriter = gson.newJsonWriter(new OutputStreamWriter(out, UTF_8));try {// 使用 TypeAdapter 将对象写入 JsonWriteradapter.write(jsonWriter, value);// 刷新 JsonWriter 以确保所有数据都被写入输出流jsonWriter.close();} catch (IOException e) {// 捕获可能的 I/O 异常并重新抛出throw new AssertionError(e); // Writing to a buffer can't throw an IOException.}// 创建 OkHttp 的 RequestBody 对象,指定媒体类型和字节数组return RequestBody.create(MEDIA_TYPE, out.toByteArray());}
}
3.1.1 GsonConverterFactory
类
GsonConverterFactory
类实现了 Converter.Factory
抽象类,提供了 create
方法用于创建实例。responseBodyConverter
方法返回 GsonResponseBodyConverter
实例,用于将响应体转换为 Java 对象;requestBodyConverter
方法返回 GsonRequestBodyConverter
实例,用于将 Java 对象转换为请求体。
3.1.2 GsonResponseBodyConverter
类
GsonResponseBodyConverter
类实现了 Converter<ResponseBody, T>
接口,其 convert
方法使用 Gson 的 TypeAdapter
从 ResponseBody
中读取 JSON 数据并转换为指定类型的 Java 对象。
3.1.3 GsonRequestBodyConverter
类
GsonRequestBodyConverter
类实现了 Converter<T, RequestBody>
接口,其 convert
方法使用 Gson 的 TypeAdapter
将 Java 对象转换为 JSON 数据,并创建 RequestBody
对象。
3.2 ScalarsConverterFactory
ScalarsConverterFactory
用于处理基本数据类型(如 String
、ByteString
、byte[]
)的转换。以下是其源码分析:
java
// 标量转换器工厂类
public final class ScalarsConverterFactory extends Converter.Factory {private static final MediaType MEDIA_TYPE = MediaType.get("text/plain; charset=UTF-8");// 创建响应体转换器@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {if (type == String.class) {return new StringResponseBodyConverter();}if (type == ByteString.class) {return new ByteStringResponseBodyConverter();}if (type == byte[].class) {return new ByteArrayResponseBodyConverter();}return null;}// 创建请求体转换器@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {if (type == String.class) {return new StringRequestBodyConverter();}if (type == ByteString.class) {return new ByteStringRequestBodyConverter();}if (type == byte[].class) {return new ByteArrayRequestBodyConverter();}return null;}// 字符串响应体转换器static final class StringResponseBodyConverter implements Converter<ResponseBody, String> {@Overridepublic String convert(ResponseBody value) throws IOException {try {return value.string();} finally {value.close();}}}// ByteString 响应体转换器static final class ByteStringResponseBodyConverter implements Converter<ResponseBody, ByteString> {@Overridepublic ByteString convert(ResponseBody value) throws IOException {try {return value.source().readByteString();} finally {value.close();}}}// 字节数组响应体转换器static final class ByteArrayResponseBodyConverter implements Converter<ResponseBody, byte[]> {@Overridepublic byte[] convert(ResponseBody value) throws IOException {try {return value.bytes();} finally {value.close();}}}// 字符串请求体转换器static final class StringRequestBodyConverter implements Converter<String, RequestBody> {@Overridepublic RequestBody convert(String value) throws IOException {return RequestBody.create(MEDIA_TYPE, value);}}// ByteString 请求体转换器static final class ByteStringRequestBodyConverter implements Converter<ByteString, RequestBody> {@Overridepublic RequestBody convert(ByteString value) throws IOException {return RequestBody.create(MEDIA_TYPE, value);}}// 字节数组请求体转换器static final class ByteArrayRequestBodyConverter implements Converter<byte[], RequestBody> {@Overridepublic RequestBody convert(byte[] value) throws IOException {return RequestBody.create(MEDIA_TYPE, value);}}
}
3.2.1 ScalarsConverterFactory
类
ScalarsConverterFactory
类实现了 Converter.Factory
抽象类,responseBodyConverter
方法根据目标类型返回不同的响应体转换器,requestBodyConverter
方法根据源类型返回不同的请求体转换器。
3.2.2 具体的转换器类
StringResponseBodyConverter
、ByteStringResponseBodyConverter
和 ByteArrayResponseBodyConverter
分别用于将响应体转换为 String
、ByteString
和 byte[]
类型;StringRequestBodyConverter
、ByteStringRequestBodyConverter
和 ByteArrayRequestBodyConverter
分别用于将 String
、ByteString
和 byte[]
类型转换为请求体。
3.3 MoshiConverterFactory
MoshiConverterFactory
是基于 Moshi 库的转换器工厂,用于处理 JSON 数据的序列化和反序列化。以下是其源码分析:
java
// Moshi 转换器工厂类
public final class MoshiConverterFactory extends Converter.Factory {private final Moshi moshi;private final boolean lenient;private final boolean failOnUnknown;private final boolean serializeNulls;// 创建 MoshiConverterFactory 实例public static MoshiConverterFactory create() {return create(new Moshi.Builder().build());}// 创建 MoshiConverterFactory 实例,传入自定义的 Moshi 实例public static MoshiConverterFactory create(Moshi moshi) {return new MoshiConverterFactory(moshi, false, false, false);}private MoshiConverterFactory(Moshi moshi, boolean lenient, boolean failOnUnknown, boolean serializeNulls) {this.moshi = moshi;this.lenient = lenient;this.failOnUnknown = failOnUnknown;this.serializeNulls = serializeNulls;}// 创建响应体转换器@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {JsonAdapter<?> adapter = moshi.adapter(type);if (lenient) {adapter = adapter.lenient();}if (failOnUnknown) {adapter = adapter.failOnUnknown();}if (serializeNulls) {adapter = adapter.serializeNulls();}return new MoshiResponseBodyConverter<>(adapter);}// 创建请求体转换器@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {JsonAdapter<?> adapter = moshi.adapter(type);if (lenient) {adapter = adapter.lenient();}if (failOnUnknown) {adapter = adapter.failOnUnknown();}if (serializeNulls) {adapter = adapter.serializeNulls();}return new MoshiRequestBodyConverter<>(adapter);}
}// Moshi 响应体转换器
final class MoshiResponseBodyConverter<T> implements Converter<ResponseBody, T> {private final JsonAdapter<T> adapter;MoshiResponseBodyConverter(JsonAdapter<T> adapter) {this.adapter = adapter;}@Overridepublic T convert(ResponseBody value) throws IOException {try {return adapter.fromJson(value.source());} finally {value.close();}}
}// Moshi 请求体转换器
final class MoshiRequestBodyConverter<T> implements Converter<T, RequestBody> {private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");private final JsonAdapter<T> adapter;MoshiRequestBodyConverter(JsonAdapter<T> adapter) {this.adapter = adapter;}@Overridepublic RequestBody convert(T value) throws IOException {Buffer buffer = new Buffer();adapter.toJson(buffer, value);return RequestBody.create(MEDIA_TYPE, buffer.readByteString());}
}
3.3.1 MoshiConverterFactory
类
MoshiConverterFactory
类实现了 Converter.Factory
抽象类,提供了 create
方法用于创建实例。responseBodyConverter
方法返回 MoshiResponseBodyConverter
实例,用于将响应体转换为 Java 对象;requestBodyConverter
方法返回 MoshiRequestBodyConverter
实例,用于将 Java 对象转换为请求体。
3.3.2 MoshiResponseBodyConverter
类
MoshiResponseBodyConverter
类实现了 Converter<ResponseBody, T>
接口,其 convert
方法使用 Moshi 的 JsonAdapter
从 ResponseBody
中读取 JSON 数据并转换为指定类型的 Java 对象。
3.3.3 MoshiRequestBodyConverter
类
MoshiRequestBodyConverter
类实现了 Converter<T, RequestBody>
接口,其 convert
方法使用 Moshi 的 JsonAdapter
将 Java 对象转换为 JSON 数据,并创建 RequestBody
对象。
四、数据转换模块的工作流程
4.1 创建 Retrofit 实例时添加转换器工厂
java
// 创建 Retrofit 实例时添加 GsonConverterFactory
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).build();
在创建 Retrofit
实例时,通过 addConverterFactory
方法添加转换器工厂,这些工厂会被添加到 Retrofit
类的 converterFactories
列表中。
4.2 接口方法调用时创建转换器
java
// 定义 API 接口
public interface ApiService {@GET("users/{id}")Call<User> getUser(@Path("id") int id);
}// 创建 API 服务实例
ApiService apiService = retrofit.create(ApiService.class);
Call<User> call = apiService.getUser(1);
当调用 API 接口方法时,Retrofit
会根据方法的返回类型和参数类型,调用 createResponseConverter
和 createRequestBodyConverter
方法,遍历 converterFactories
列表,查找合适的转换器工厂并创建转换器。
4.3 请求体转换
java
// 在 OkHttpCall 类中进行请求体转换
final class OkHttpCall<T> implements Call<T> {private final ServiceMethod<T, ?> serviceMethod;private final Object[] args;OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {this.serviceMethod = serviceMethod;this.args = args;}@Overridepublic Request request() {// 创建请求体RequestBody body = serviceMethod.toRequestBody(args);// 创建 OkHttp 的 Request 对象return new Request.Builder().url(serviceMethod.requestFactory.url(args)).headers(serviceMethod.requestFactory.headers(args)).method(serviceMethod.httpMethod, body).build();}
}// 在 ServiceMethod 类中调用请求体转换器
abstract class ServiceMethod<T, R> {final RequestFactory requestFactory;final Converter<?, RequestBody> requestBodyConverter;ServiceMethod(Builder<T, R> builder) {this.requestFactory = builder.requestFactory;this.requestBodyConverter = builder.requestBodyConverter;}RequestBody toRequestBody(Object[] args) {Object value = args[requestFactory.parameterHandlers.length - 1];try {// 调用请求体转换器进行转换return requestBodyConverter.convert(value);} catch (IOException e) {throw new RuntimeException("Unable to convert request body", e);}}
}
在 OkHttpCall
类的 request
方法中,调用 ServiceMethod
的 toRequestBody
方法,该方法会调用请求体转换器的 convert
方法,将请求参数转换为 RequestBody
对象。
4.4 响应体转换
java
// 在 OkHttpCall 类中进行响应体转换
final class OkHttpCall<T> implements Call<T> {@Overridepublic Response<T> execute() throws IOException {okhttp3.Call call = rawCall();okhttp3.Response rawResponse = call.execute();try {// 解析响应体return parseResponse(rawResponse);} catch (Throwable t) {try {rawResponse.body().close();} catch (IOException ignored) {}throw t;}}private Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();rawResponse = rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();int code = rawResponse.code();if (code < 200 || code >= 300) {try {// 处理错误响应ResponseBody bufferedBody = Utils.buffer(rawBody);return Response.error(bufferedBody, rawResponse);} finally {rawBody.close();}}if (code == 204 || code == 205) {rawBody.close();return Response.success(null, rawResponse);}ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);try {// 调用响应体转换器进行转换T body = serviceMethod.toResponse(catchingBody);return Response.success(body, rawResponse);} catch (RuntimeException e) {catchingBody.throwIfCaught();throw e;}}
}// 在 ServiceMethod 类中调用响应体转换器
abstract class ServiceMethod<T, R> {final Converter<ResponseBody, T> responseBodyConverter;ServiceMethod(Builder<T, R> builder) {this.responseBodyConverter = builder.responseBodyConverter;}T toResponse(ResponseBody body) throws IOException {// 调用响应体转换器进行转换return responseBodyConverter.convert(body);}
}
在 OkHttpCall
类的 execute
方法中,调用 parseResponse
方法,该方法会调用 ServiceMethod
的 toResponse
方法,该方法会调用响应体转换器的 convert
方法,将 ResponseBody
对象转换为 Java 对象。
五、自定义转换器工厂
5.1 自定义转换器接口
java
// 自定义转换器接口
public interface CustomConverter<F, T> {T convert(F value) throws IOException;
}// 自定义转换器工厂接口
public abstract class CustomConverterFactory extends Converter.Factory {public abstract <T> CustomConverter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit);public abstract <T> CustomConverter<T, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit);
}
首先定义自定义的转换器接口 CustomConverter
和转换器工厂接口 CustomConverterFactory
。
5.2 实现自定义转换器工厂
java
// 自定义转换器工厂实现
public class MyCustomConverterFactory extends CustomConverterFactory {@Overridepublic <T> CustomConverter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {return new MyCustomResponseBodyConverter<>();}@Overridepublic <T> CustomConverter<T, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return new MyCustomRequestBodyConverter<>();}
}// 自定义响应体转换器
class MyCustomResponseBodyConverter<T> implements CustomConverter<ResponseBody, T> {@Overridepublic T convert(ResponseBody value) throws IOException {// 实现自定义的响应体转换逻辑// 这里只是简单示例,实际中需要根据具体需求实现return null;}
}// 自定义请求体转换器
class MyCustomRequestBodyConverter<T> implements CustomConverter<T, RequestBody> {@Overridepublic RequestBody convert(T value) throws IOException {// 实现自定义的请求体转换逻辑// 这里只是简单示例,实际中需要根据具体需求实现return null;}
}
实现自定义的转换器工厂 MyCustomConverterFactory
,并实现 responseBodyConverter
和 requestBodyConverter
方法,返回自定义的响应体转换器和请求体转换器。
5.3 使用自定义转换器工厂
java
// 创建 Retrofit 实例时添加自定义转换器工厂
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(new MyCustomConverterFactory()).build();
在创建 Retrofit
实例时,
六、数据转换模块的异常处理
6.1 请求体转换异常
在请求体转换过程中,可能会因为各种原因抛出异常,比如数据格式错误、序列化失败等。以下是 ServiceMethod
类中请求体转换部分可能出现异常的源码分析:
java
abstract class ServiceMethod<T, R> {final RequestFactory requestFactory;final Converter<?, RequestBody> requestBodyConverter;ServiceMethod(Builder<T, R> builder) {this.requestFactory = builder.requestFactory;this.requestBodyConverter = builder.requestBodyConverter;}RequestBody toRequestBody(Object[] args) {Object value = args[requestFactory.parameterHandlers.length - 1];try {// 调用请求体转换器进行转换return requestBodyConverter.convert(value);} catch (IOException e) {// 捕获转换过程中可能出现的 IO 异常throw new RuntimeException("Unable to convert request body", e);}}
}
在 toRequestBody
方法中,调用 requestBodyConverter
的 convert
方法进行请求体转换。如果转换过程中抛出 IOException
,会将其封装成 RuntimeException
抛出,以通知调用者请求体转换失败。
6.2 响应体转换异常
响应体转换过程同样可能出现异常,比如 JSON 解析错误、数据类型不匹配等。以下是 OkHttpCall
类中响应体转换部分的异常处理源码分析:
java
final class OkHttpCall<T> implements Call<T> {private Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();rawResponse = rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();int code = rawResponse.code();if (code < 200 || code >= 300) {try {// 处理错误响应ResponseBody bufferedBody = Utils.buffer(rawBody);return Response.error(bufferedBody, rawResponse);} finally {rawBody.close();}}if (code == 204 || code == 205) {rawBody.close();return Response.success(null, rawResponse);}ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);try {// 调用响应体转换器进行转换T body = serviceMethod.toResponse(catchingBody);return Response.success(body, rawResponse);} catch (RuntimeException e) {// 捕获转换过程中可能出现的运行时异常catchingBody.throwIfCaught();throw e;}}
}abstract class ServiceMethod<T, R> {final Converter<ResponseBody, T> responseBodyConverter;ServiceMethod(Builder<T, R> builder) {this.responseBodyConverter = builder.responseBodyConverter;}T toResponse(ResponseBody body) throws IOException {// 调用响应体转换器进行转换return responseBodyConverter.convert(body);}
}
在 parseResponse
方法中,调用 serviceMethod
的 toResponse
方法进行响应体转换。如果转换过程中抛出 RuntimeException
,会先调用 catchingBody.throwIfCaught()
检查是否有捕获到的异常,然后再将异常抛出,以通知调用者响应体转换失败。
6.3 转换器工厂创建转换器异常
在 Retrofit
类的 createResponseConverter
和 createRequestBodyConverter
方法中,遍历 converterFactories
列表创建转换器时,也可能会抛出异常。以下是相关源码分析:
java
public final class Retrofit {// 创建响应转换器private static <T> Converter<ResponseBody, T> createResponseConverter(Retrofit retrofit, Method method, Type responseType) {Annotation[] annotations = method.getAnnotations();try {// 遍历转换器工厂列表,查找合适的转换器工厂for (Converter.Factory factory : retrofit.converterFactories()) {// 调用工厂的 responseBodyConverter 方法创建响应体转换器Converter<ResponseBody, ?> converter = factory.responseBodyConverter(responseType, annotations, retrofit);if (converter != null) {// 找到合适的转换器,返回return (Converter<ResponseBody, T>) converter;}}} catch (RuntimeException e) {// 捕获创建转换器过程中可能出现的运行时异常throw methodError(method, e, "Unable to create converter for %s", responseType);}throw methodError(method, "Could not locate response converter for %s.", responseType);}// 创建请求体转换器private static <T> Converter<T, RequestBody> createRequestBodyConverter(Retrofit retrofit, Method method, Type requestType, Annotation[] parameterAnnotations) {Annotation[] methodAnnotations = method.getAnnotations();try {// 遍历转换器工厂列表,查找合适的转换器工厂for (Converter.Factory factory : retrofit.converterFactories()) {// 调用工厂的 requestBodyConverter 方法创建请求体转换器Converter<?, RequestBody> converter = factory.requestBodyConverter(requestType, parameterAnnotations, methodAnnotations, retrofit);if (converter != null) {// 找到合适的转换器,返回return (Converter<T, RequestBody>) converter;}}} catch (RuntimeException e) {// 捕获创建转换器过程中可能出现的运行时异常throw methodError(method, e, "Unable to create converter for %s", requestType);}throw methodError(method, "Could not locate request body converter for %s.", requestType);}
}
在 createResponseConverter
和 createRequestBodyConverter
方法中,调用工厂的 responseBodyConverter
或 requestBodyConverter
方法创建转换器时,如果抛出 RuntimeException
,会将其封装成 methodError
异常抛出,以通知调用者创建转换器失败。
七、数据转换模块的性能优化
7.1 缓存转换器
在 Retrofit
中,每次调用接口方法时都会尝试创建转换器,这可能会带来一定的性能开销。可以通过缓存已经创建的转换器来避免重复创建。以下是一个简单的缓存实现示例:
java
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;public class ConverterCache {private static final Map<Type, Object> converterCache = new HashMap<>();public static <T> Converter<ResponseBody, T> getResponseConverter(Type type, Converter.Factory factory, Retrofit retrofit) {@SuppressWarnings("unchecked")Converter<ResponseBody, T> converter = (Converter<ResponseBody, T>) converterCache.get(type);if (converter == null) {converter = factory.responseBodyConverter(type, new Annotation[0], retrofit);if (converter != null) {converterCache.put(type, converter);}}return converter;}public static <T> Converter<T, RequestBody> getRequestConverter(Type type, Converter.Factory factory, Retrofit retrofit) {@SuppressWarnings("unchecked")Converter<T, RequestBody> converter = (Converter<T, RequestBody>) converterCache.get(type);if (converter == null) {converter = factory.requestBodyConverter(type, new Annotation[0], new Annotation[0], retrofit);if (converter != null) {converterCache.put(type, converter);}}return converter;}
}
在 Retrofit
中使用缓存:
java
public final class Retrofit {// 创建响应转换器private static <T> Converter<ResponseBody, T> createResponseConverter(Retrofit retrofit, Method method, Type responseType) {Annotation[] annotations = method.getAnnotations();for (Converter.Factory factory : retrofit.converterFactories()) {Converter<ResponseBody, T> converter = ConverterCache.getResponseConverter(responseType, factory, retrofit);if (converter != null) {return converter;}}throw methodError(method, "Could not locate response converter for %s.", responseType);}// 创建请求体转换器private static <T> Converter<T, RequestBody> createRequestBodyConverter(Retrofit retrofit, Method method, Type requestType, Annotation[] parameterAnnotations) {Annotation[] methodAnnotations = method.getAnnotations();for (Converter.Factory factory : retrofit.converterFactories()) {Converter<T, RequestBody> converter = ConverterCache.getRequestConverter(requestType, factory, retrofit);if (converter != null) {return converter;}}throw methodError(method, "Could not locate request body converter for %s.", requestType);}
}
通过缓存转换器,可以避免重复创建相同类型的转换器,提高性能。
7.2 选择合适的转换器
不同的转换器在性能上可能会有差异,例如 GsonConverterFactory
和 MoshiConverterFactory
都可以处理 JSON 数据,但 Moshi
在某些场景下可能会有更好的性能。在选择转换器时,需要根据具体的需求和数据特点进行选择。
7.3 减少不必要的转换
在某些情况下,可以避免进行不必要的数据转换。例如,如果服务器返回的数据可以直接使用,就不需要将其转换为 Java 对象再进行处理。可以通过自定义转换器来实现直接处理原始数据。
八、数据转换模块与其他模块的交互
8.1 与 CallAdapter
模块的交互
CallAdapter
模块负责将 Call
对象转换为其他类型,如 Observable
、Completable
等。数据转换模块和 CallAdapter
模块在请求和响应处理过程中相互协作。以下是一个简单的交互示例:
java
public interface ApiService {@GET("users/{id}")Observable<User> getUser(@Path("id") int id);
}Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();ApiService apiService = retrofit.create(ApiService.class);
Observable<User> observable = apiService.getUser(1);
在这个示例中,GsonConverterFactory
负责将响应体转换为 User
对象,RxJava2CallAdapterFactory
负责将 Call
对象转换为 Observable
对象。
8.2 与 OkHttp
模块的交互
Retrofit 底层使用 OkHttp
进行网络请求,数据转换模块和 OkHttp
模块在请求体和响应体的处理上进行交互。OkHttp
负责发送请求和接收响应,数据转换模块负责将请求参数转换为 RequestBody
对象,将 ResponseBody
对象转换为 Java 对象。以下是相关源码分析:
java
final class OkHttpCall<T> implements Call<T> {@Overridepublic Request request() {// 创建请求体RequestBody body = serviceMethod.toRequestBody(args);// 创建 OkHttp 的 Request 对象return new Request.Builder().url(serviceMethod.requestFactory.url(args)).headers(serviceMethod.requestFactory.headers(args)).method(serviceMethod.httpMethod, body).build();}@Overridepublic Response<T> execute() throws IOException {okhttp3.Call call = rawCall();okhttp3.Response rawResponse = call.execute();try {// 解析响应体return parseResponse(rawResponse);} catch (Throwable t) {try {rawResponse.body().close();} catch (IOException ignored) {}throw t;}}
}
在 request
方法中,调用 serviceMethod
的 toRequestBody
方法将请求参数转换为 RequestBody
对象,然后创建 OkHttp
的 Request
对象。在 execute
方法中,调用 parseResponse
方法将 OkHttp
的 Response
对象中的 ResponseBody
转换为 Java 对象。
九、数据转换模块的未来发展趋势
9.1 支持更多的数据格式
随着技术的发展,可能会出现更多的数据格式,如 Protocol Buffers、Avro 等。Retrofit 的数据转换模块可能会支持更多的数据格式,以满足不同的需求。
9.2 更好的性能优化
未来的数据转换模块可能会进行更多的性能优化,如使用更高效的序列化和反序列化算法,减少内存开销和 CPU 占用。
9.3 与更多的框架集成
Retrofit 可能会与更多的框架进行集成,如 Kotlin 的协程、Flutter 等,以提供更好的开发体验。
9.4 增强的错误处理和调试功能
数据转换模块可能会提供更详细的错误信息和调试工具,帮助开发者更快地定位和解决问题。例如,在异常信息中提供更多的上下文信息,或者提供可视化的调试工具。
十、总结
Retrofit 的数据转换模块是一个非常重要的模块,它负责将请求参数序列化为 HTTP 请求体,以及将 HTTP 响应体反序列化为 Java 对象。通过对数据转换模块的源码分析,我们了解了其核心概念、常见的转换器工厂实现、工作流程、异常处理、性能优化、与其他模块的交互以及未来发展趋势。掌握这些知识可以帮助我们更好地使用和扩展 Retrofit 框架,提高开发效率和应用性能。在实际开发中,我们可以根据具体的需求选择合适的转换器工厂,进行自定义转换器的开发,以及对数据转换模块进行性能优化,以满足不同的业务需求。同时,我们也需要关注数据转换模块的未来发展趋势,以便及时跟上技术的发展步伐。