Android Retrofit 框架数据转换模块深入源码分析(四)

发布于:2025-03-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

一、引言

在现代的 Android 和 Java 开发中,网络请求是必不可少的一部分。Retrofit 作为一个强大的网络请求框架,以其简洁的 API 和高度的可定制性受到了广泛的欢迎。数据转换模块是 Retrofit 框架中至关重要的一部分,它负责将请求参数序列化为 HTTP 请求体,以及将 HTTP 响应体反序列化为 Java 对象。通过对 Retrofit 数据转换模块的源码分析,我们可以深入了解其工作原理,从而更好地使用和扩展这个框架。

二、数据转换模块的核心概念

2.1 Converter 接口

Converter 接口是数据转换模块的核心接口,它定义了数据转换的基本方法。以下是 Converter 接口的源码:

java

// Converter 接口定义了数据转换的基本方法
public interface Converter<F, T> {
    // 将输入类型 F 转换为输出类型 T
    T 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 {
    // 创建请求体转换器,用于将请求参数转换为 RequestBody
    public @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);
    }

    // 创建响应体转换器
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new GsonResponseBodyConverter<>(gson, type);
    }

    // 创建请求体转换器
    @Override
    public 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));
    }

    @Override
    public 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));
    }

    @Override
    public 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 将对象写入 JsonWriter
            adapter.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 的 TypeAdapterResponseBody 中读取 JSON 数据并转换为指定类型的 Java 对象。

3.1.3 GsonRequestBodyConverter

GsonRequestBodyConverter 类实现了 Converter<T, RequestBody> 接口,其 convert 方法使用 Gson 的 TypeAdapter 将 Java 对象转换为 JSON 数据,并创建 RequestBody 对象。

3.2 ScalarsConverterFactory

ScalarsConverterFactory 用于处理基本数据类型(如 StringByteStringbyte[])的转换。以下是其源码分析:

java

// 标量转换器工厂类
public final class ScalarsConverterFactory extends Converter.Factory {
    private static final MediaType MEDIA_TYPE = MediaType.get("text/plain; charset=UTF-8");

    // 创建响应体转换器
    @Override
    public 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;
    }

    // 创建请求体转换器
    @Override
    public 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> {
        @Override
        public String convert(ResponseBody value) throws IOException {
            try {
                return value.string();
            } finally {
                value.close();
            }
        }
    }

    // ByteString 响应体转换器
    static final class ByteStringResponseBodyConverter implements Converter<ResponseBody, ByteString> {
        @Override
        public ByteString convert(ResponseBody value) throws IOException {
            try {
                return value.source().readByteString();
            } finally {
                value.close();
            }
        }
    }

    // 字节数组响应体转换器
    static final class ByteArrayResponseBodyConverter implements Converter<ResponseBody, byte[]> {
        @Override
        public byte[] convert(ResponseBody value) throws IOException {
            try {
                return value.bytes();
            } finally {
                value.close();
            }
        }
    }

    // 字符串请求体转换器
    static final class StringRequestBodyConverter implements Converter<String, RequestBody> {
        @Override
        public RequestBody convert(String value) throws IOException {
            return RequestBody.create(MEDIA_TYPE, value);
        }
    }

    // ByteString 请求体转换器
    static final class ByteStringRequestBodyConverter implements Converter<ByteString, RequestBody> {
        @Override
        public RequestBody convert(ByteString value) throws IOException {
            return RequestBody.create(MEDIA_TYPE, value);
        }
    }

    // 字节数组请求体转换器
    static final class ByteArrayRequestBodyConverter implements Converter<byte[], RequestBody> {
        @Override
        public RequestBody convert(byte[] value) throws IOException {
            return RequestBody.create(MEDIA_TYPE, value);
        }
    }
}
3.2.1 ScalarsConverterFactory

ScalarsConverterFactory 类实现了 Converter.Factory 抽象类,responseBodyConverter 方法根据目标类型返回不同的响应体转换器,requestBodyConverter 方法根据源类型返回不同的请求体转换器。

3.2.2 具体的转换器类

StringResponseBodyConverterByteStringResponseBodyConverterByteArrayResponseBodyConverter 分别用于将响应体转换为 StringByteStringbyte[] 类型;StringRequestBodyConverterByteStringRequestBodyConverterByteArrayRequestBodyConverter 分别用于将 StringByteStringbyte[] 类型转换为请求体。

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

    // 创建响应体转换器
    @Override
    public 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);
    }

    // 创建请求体转换器
    @Override
    public 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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 的 JsonAdapterResponseBody 中读取 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 会根据方法的返回类型和参数类型,调用 createResponseConvertercreateRequestBodyConverter 方法,遍历 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;
    }

    @Override
    public 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 方法中,调用 ServiceMethodtoRequestBody 方法,该方法会调用请求体转换器的 convert 方法,将请求参数转换为 RequestBody 对象。

4.4 响应体转换

java

// 在 OkHttpCall 类中进行响应体转换
final class OkHttpCall<T> implements Call<T> {
    @Override
    public 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 方法,该方法会调用 ServiceMethodtoResponse 方法,该方法会调用响应体转换器的 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 {
    @Override
    public <T> CustomConverter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new MyCustomResponseBodyConverter<>();
    }

    @Override
    public <T> CustomConverter<T, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        return new MyCustomRequestBodyConverter<>();
    }
}

// 自定义响应体转换器
class MyCustomResponseBodyConverter<T> implements CustomConverter<ResponseBody, T> {
    @Override
    public T convert(ResponseBody value) throws IOException {
        // 实现自定义的响应体转换逻辑
        // 这里只是简单示例,实际中需要根据具体需求实现
        return null;
    }
}

// 自定义请求体转换器
class MyCustomRequestBodyConverter<T> implements CustomConverter<T, RequestBody> {
    @Override
    public RequestBody convert(T value) throws IOException {
        // 实现自定义的请求体转换逻辑
        // 这里只是简单示例,实际中需要根据具体需求实现
        return null;
    }
}

实现自定义的转换器工厂 MyCustomConverterFactory,并实现 responseBodyConverterrequestBodyConverter 方法,返回自定义的响应体转换器和请求体转换器。

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 方法中,调用 requestBodyConverterconvert 方法进行请求体转换。如果转换过程中抛出 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 方法中,调用 serviceMethodtoResponse 方法进行响应体转换。如果转换过程中抛出 RuntimeException,会先调用 catchingBody.throwIfCaught() 检查是否有捕获到的异常,然后再将异常抛出,以通知调用者响应体转换失败。

6.3 转换器工厂创建转换器异常

Retrofit 类的 createResponseConvertercreateRequestBodyConverter 方法中,遍历 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);
    }
}

createResponseConvertercreateRequestBodyConverter 方法中,调用工厂的 responseBodyConverterrequestBodyConverter 方法创建转换器时,如果抛出 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 选择合适的转换器

不同的转换器在性能上可能会有差异,例如 GsonConverterFactoryMoshiConverterFactory 都可以处理 JSON 数据,但 Moshi 在某些场景下可能会有更好的性能。在选择转换器时,需要根据具体的需求和数据特点进行选择。

7.3 减少不必要的转换

在某些情况下,可以避免进行不必要的数据转换。例如,如果服务器返回的数据可以直接使用,就不需要将其转换为 Java 对象再进行处理。可以通过自定义转换器来实现直接处理原始数据。

八、数据转换模块与其他模块的交互

8.1 与 CallAdapter 模块的交互

CallAdapter 模块负责将 Call 对象转换为其他类型,如 ObservableCompletable 等。数据转换模块和 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> {
    @Override
    public 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();
    }

    @Override
    public 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 方法中,调用 serviceMethodtoRequestBody 方法将请求参数转换为 RequestBody 对象,然后创建 OkHttpRequest 对象。在 execute 方法中,调用 parseResponse 方法将 OkHttpResponse 对象中的 ResponseBody 转换为 Java 对象。

九、数据转换模块的未来发展趋势

9.1 支持更多的数据格式

随着技术的发展,可能会出现更多的数据格式,如 Protocol Buffers、Avro 等。Retrofit 的数据转换模块可能会支持更多的数据格式,以满足不同的需求。

9.2 更好的性能优化

未来的数据转换模块可能会进行更多的性能优化,如使用更高效的序列化和反序列化算法,减少内存开销和 CPU 占用。

9.3 与更多的框架集成

Retrofit 可能会与更多的框架进行集成,如 Kotlin 的协程、Flutter 等,以提供更好的开发体验。

9.4 增强的错误处理和调试功能

数据转换模块可能会提供更详细的错误信息和调试工具,帮助开发者更快地定位和解决问题。例如,在异常信息中提供更多的上下文信息,或者提供可视化的调试工具。

十、总结

Retrofit 的数据转换模块是一个非常重要的模块,它负责将请求参数序列化为 HTTP 请求体,以及将 HTTP 响应体反序列化为 Java 对象。通过对数据转换模块的源码分析,我们了解了其核心概念、常见的转换器工厂实现、工作流程、异常处理、性能优化、与其他模块的交互以及未来发展趋势。掌握这些知识可以帮助我们更好地使用和扩展 Retrofit 框架,提高开发效率和应用性能。在实际开发中,我们可以根据具体的需求选择合适的转换器工厂,进行自定义转换器的开发,以及对数据转换模块进行性能优化,以满足不同的业务需求。同时,我们也需要关注数据转换模块的未来发展趋势,以便及时跟上技术的发展步伐。