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

204 阅读18分钟

一、引言

在现代的 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 的 TypeAdapter 从 ResponseBody 中读取 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 具体的转换器类

StringResponseBodyConverterByteStringResponseBodyConverter 和 ByteArrayResponseBodyConverter 分别用于将响应体转换为 StringByteString 和 byte[] 类型;StringRequestBodyConverterByteStringRequestBodyConverter 和 ByteArrayRequestBodyConverter 分别用于将 StringByteString 和 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;
    }

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

    @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 方法中,调用 ServiceMethod 的 toRequestBody 方法,该方法会调用请求体转换器的 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 方法,该方法会调用 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 {
    @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,并实现 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 对象转换为其他类型,如 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 方法中,调用 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 框架,提高开发效率和应用性能。在实际开发中,我们可以根据具体的需求选择合适的转换器工厂,进行自定义转换器的开发,以及对数据转换模块进行性能优化,以满足不同的业务需求。同时,我们也需要关注数据转换模块的未来发展趋势,以便及时跟上技术的发展步伐。