如何在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 7Future的异常规范。 - 线程池选择:回调执行器可以根据业务需求调整,比如用固定大小线程池或者Retrofit默认的回调线程池(可以通过
retrofit.callbackExecutor()获取)。
内容的提问来源于stack exchange,提问作者alessandro candolini
相关产品推荐
相关产品推荐

