You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Retrofit 2中使用Java 7 Future而非Java 8 CompletableFuture?

当然没问题!Retrofit 2完全支持适配Java 7的Future接口,不需要非得用Java 8的CompletableFuture。核心思路是利用Retrofit的自定义CallAdapter机制,把Retrofit默认的Call<T>转换成Java 7的Future<T>。下面给你详细的实现方案:

具体实现步骤

1. 编写自定义CallAdapter.Factory

首先我们需要创建一个CallAdapter.Factory的实现类,它负责识别返回类型为Java 7 Future的接口方法,并生成对应的适配器。这个适配器会把Retrofit的Call<T>包装成符合Java 7规范的Future<T>实例。

import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;

public class Java7FutureCallAdapterFactory extends CallAdapter.Factory {
    private final Executor callbackExecutor;

    // 传入回调执行线程池,可根据业务需求选择
    public Java7FutureCallAdapterFactory(Executor callbackExecutor) {
        this.callbackExecutor = callbackExecutor;
    }

    @Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        // 只处理返回类型为Future的方法
        if (getRawType(returnType) != Future.class) {
            return null;
        }
        // 获取Future的泛型参数(也就是接口方法的实际返回数据类型)
        Type responseType = getParameterUpperBound(0, (ParameterizedType) returnType);
        return new Java7FutureCallAdapter<>(responseType, callbackExecutor);
    }

    private static class Java7FutureCallAdapter<T> implements CallAdapter<T, Future<T>> {
        private final Type responseType;
        private final Executor callbackExecutor;

        Java7FutureCallAdapter(Type responseType, Executor callbackExecutor) {
            this.responseType = responseType;
            this.callbackExecutor = callbackExecutor;
        }

        @Override
        public Type responseType() {
            return responseType;
        }

        @Override
        public Future<T> adapt(final Call<T> call) {
            return new Future<T>() {
                @Override
                public boolean cancel(boolean mayInterruptIfRunning) {
                    // 直接调用Retrofit Call的cancel方法
                    return call.cancel();
                }

                @Override
                public boolean isCancelled() {
                    return call.isCanceled();
                }

                @Override
                public boolean isDone() {
                    // 判断请求是否已执行完成
                    return call.isExecuted();
                }

                @Override
                public T get() throws InterruptedException, java.util.concurrent.ExecutionException {
                    // 同步执行请求,阻塞当前线程直到结果返回
                    try {
                        return call.execute().body();
                    } catch (retrofit2.HttpException e) {
                        throw new java.util.concurrent.ExecutionException(e);
                    } catch (java.io.IOException e) {
                        throw new java.util.concurrent.ExecutionException(e);
                    }
                }

                @Override
                public T get(long timeout, java.util.concurrent.TimeUnit unit) throws InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException {
                    // 带超时的异步等待实现,用CountDownLatch配合enqueue回调
                    final java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
                    final T[] resultHolder = (T[]) new Object[1];
                    final Exception[] errorHolder = new Exception[1];

                    call.enqueue(new retrofit2.Callback<T>() {
                        @Override
                        public void onResponse(Call<T> call, retrofit2.Response<T> response) {
                            if (response.isSuccessful()) {
                                resultHolder[0] = response.body();
                            } else {
                                errorHolder[0] = new retrofit2.HttpException(response);
                            }
                            latch.countDown();
                        }

                        @Override
                        public void onFailure(Call<T> call, Throwable t) {
                            errorHolder[0] = new java.util.concurrent.ExecutionException(t);
                            latch.countDown();
                        }
                    });

                    // 等待指定时间,超时则取消请求并抛出异常
                    if (!latch.await(timeout, unit)) {
                        call.cancel();
                        throw new java.util.concurrent.TimeoutException("Request timed out after " + timeout + " " + unit.name());
                    }

                    if (errorHolder[0] != null) {
                        throw new java.util.concurrent.ExecutionException(errorHolder[0]);
                    }
                    return resultHolder[0];
                }
            };
        }
    }
}

2. 在Retrofit实例中注册自定义Factory

创建Retrofit客户端的时候,把我们刚才写的Java7FutureCallAdapterFactory添加进去,替换掉默认的CompletableFuture相关适配器(如果有的话):

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.util.concurrent.Executors;

public class RetrofitClient {
    public static Retrofit getInstance() {
        return new Retrofit.Builder()
                .baseUrl("https://your-api-domain.com/")
                .addConverterFactory(GsonConverterFactory.create())
                // 注册自定义的Java7 Future适配器
                .addCallAdapterFactory(new Java7FutureCallAdapterFactory(Executors.newCachedThreadPool()))
                .build();
    }
}

3. 定义API接口使用Java 7 Future作为返回类型

现在你的API接口就可以直接用Java 7的Future作为方法返回值了:

import java.util.concurrent.Future;
import retrofit2.http.GET;
import retrofit2.http.Path;

public interface UserApi {
    @GET("users/{userId}")
    Future<User> getUserById(@Path("userId") String userId);
}
一些注意事项
  • 同步与异步:get()方法用了call.execute()是同步阻塞的,适合在后台线程中调用;带超时的get()方法用了enqueue异步执行,更适合需要控制等待时间的场景。
  • 异常处理:Retrofit的异常(如网络异常、HTTP错误)都会被包装成ExecutionException抛出,符合Java 7 Future的异常规范。
  • 线程池选择:回调执行器可以根据业务需求调整,比如用固定大小线程池或者Retrofit默认的回调线程池(可以通过retrofit.callbackExecutor()获取)。

内容的提问来源于stack exchange,提问作者alessandro candolini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:56:53