Retrofit 与 OkHttp 实现网络请求

Retrofit

什么是Retrofit

基于 RESTful Api设计规范的 Http 网络请求框架的封装。网络请求本质上还是使用OkHttp完成,而Retrofit负责网络网络请求接口的封装。

使用步骤
  1. 创建 Retrofit 实例,使用单例模式
  2. 创建描述网络请求的接口(Interface)并使用 注解 描述并配置网络请求参数
  3. 创建网络请求接口实例 retrofit.create();
  4. 发送网络请求(Request) enqueue,交由OkHttp处理请求
  5. OkHttp得到服务端响应(Response)后,交由Retrofit解析并处理
  6. 通过callbackExecutor从子线程切换到UI线程并通过回调将数据与状态传递到前台
源码分析

1.创建Retrofit实例

使用 Builder模式 创建一个Retrofit实例

OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient httpClient = builder.build();
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.example.com/") // 设置网络请求的URL地址
        .addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
        .client(httpClient)
        .build();

2.定义接口以及请求方法


public interface ApiServicie
{
    @POST("/"+ RequestParams.VERSION+"/api/***")
    Call<ResponseBody> getCall(@Body RequestBody body);
}

3.创建网络请求接口实例

private Map<String, Object> mServicePool = new ConcurrentHashMap<>();
    /**
     * 获取指定类型的service,把service做缓存处理,避免每次都创建;
     * 创建并获取网络请求接口
     * @param clazz 网络请求接口的字节码
     * @param <T> 得到被动态代理的接口实例
     * @return
     */
    public synchronized <T> T getService(Class<T> clazz) {
        Object service = mServicePool.get(clazz.getName());
        if (service == null) {
            service = mRetrofit.create(clazz);
            mServicePool.put(clazz.getName(), service);
        }
        return (T) service;
    }
    // 使用动态代理的方式去拦截网络请求接口定义的方法
    public <T> T create(final Class<T> service) {

        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        // 使用动态代理,返回Service对象。当调用service.xxx()时会执行invoke方法并返回网络请求的对象Call
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
              @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
                    ServiceMethod<Object, Object> serviceMethod =
                        (ServiceMethod<Object, Object>) loadServiceMethod(method);
                    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    return serviceMethod.adapt(okHttpCall);
              }
            });
    }
    // 根据缓存策略实现延伸加载ServiceMethod对象
    ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = serviceMethodCache.get(method);
        if (result != null) return result;
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
  }
  Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations(); // 获取方法注解
      this.parameterTypes = method.getGenericParameterTypes(); // 获取参数类型
      this.parameterAnnotationsArray = method.getParameterAnnotations();//获取参数注解
    }
  public ServiceMethod build() {
      callAdapter = createCallAdapter(); // 获取网络请求适配器,默认使用带线程切换的适配器
      responseType = callAdapter.responseType(); // 获取响应类型
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      responseConverter = createResponseConverter(); // 获取服务器数据解析器

      // 解析方法注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        // 将参数注解以及参数类型生成参数转换器
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      return new ServiceMethod<>(this);
    }

4.执行网络请求


// 生成网络请求Call对象
// 执行getCall方法时,会被动态代理的InvocationHandler.invoke拦截
Call<ResponseBody> call = getService(ApiService.class).getCall(body);
// 执行异步网络请求
call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.code() == 200) {
                   // 处理请求成功
                } else {
                   // 处理请求失败
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                // 处理请求失败
            }
        });

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {

    static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor; // 实现将子线程线程切换到UI线程
    final Call<T> delegate; // 静态代理OkHttpCall

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
        // 执行线程切换
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }
}


OkHttpCall:

@Override public void enqueue(final Callback<T> callback) {
   
    okhttp3.Call call
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      // 生成原生的请求对象,会把请求参数通过serviceMethod.toCall()交由ParameterHandler组成网络请求头
      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }
    // 调用OkHttp的enqueue执行网络请求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      // 将服务器传回来的数据进行解析,生成对应的接收类型。
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
        // 将结果通过回调传递出去
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }
  private okhttp3.Call createRawCall() throws IOException {
  // args :网络请求传递的参数
    okhttp3.Call call = serviceMethod.toCall();
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
}

RealCall

public void enqueue(Callback responseCallback) {
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

Dispatcher

public final class Dispatcher {
    private int maxRequests = 64; // 最多缓存 64 个请求
    private int maxRequestsPerHost = 5; // 同一个host最多允许5个链接存活
    private @Nullable ExecutorService executorService; // 使用线程池执行请求
    // 请求连接池
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
    private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
    
    
    // 核心线程数为0,最大线程数为无限大,线程最多存活时间为1分钟。
    // 当执行第二个线程时,第一个请求已经完成且在存活时间内,则复用第一个线程。
    public synchronized ExcutorService excutorService() {
        if(executorService == null) {
            executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
              new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
        }
    }
    
    // 执行异步网络请求
    synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests &&  runningCallsForHost(call) < maxRequestsPerHost) {
          runningAsyncCalls.add(call);
          executorService().execute(call);
        } else {
          readyAsyncCalls.add(call);
        }
    }
    // 同步网络请求
    synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
  }
}

public class AsyncCall extends NameRunnable{
    @Override protected void execute() {
      try {
      // 使用责任链模式执行网络请求并得到结果
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
}

RealCall

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors()); //自定义的拦截器
    interceptors.add(retryAndFollowUpInterceptor); //重试拦截器,请求失败后重试, 如果出现IO异常则直接取消
    interceptors.add(new BridgeInterceptor(client.cookieJar())); //桥接拦截器,处理请求
    interceptors.add(new CacheInterceptor(client.internalCache())); //缓存拦截器,处理请求缓存
    interceptors.add(new ConnectInterceptor(client)); //连接拦截器,创建HTTP连接
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket)); //网络请求拦截器,开始网络请求

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }


拦截器

将一个请求的过程分解,然后对每一个过程进行处理(打包),得到响应后在对数据进行解包.

  1. 重试拦截器 - RetryAndFollowUpInterceptor
public Response intercept(Chain chain) throws IOException {
    //......
    int followUpCount = 0; // 重试计数器
    //通过一个循环来重新尝试请求
    while (true) {
    // 如果出现IO异常,则直接取消
      if (canceled) {
        streamAllocation.release();
        throw new IOException("Canceled");
      }
      Response response;
      boolean releaseConnection = true;
      try {
        // 1.执行下一个拦截器
        response = realChain.proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      }
      // 2.检测服务端的响应 response, 是否需要重定向和以及客户端是否支持超时重连, 如果不支持则直接返回响应。
      Request followUp = followUpRequest(response, streamAllocation.route);
      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        //3. 返回response,请求完成
        return response;
      }

      if (++followUpCount > MAX_FOLLOW_UPS) {  // 最多尝试20次
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }
      //4.重新设置请求
      request = followUp;
      //.......
    }
  }

  1. 桥接拦截器 - BridgeInterceptor
public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();
    RequestBody body = userRequest.body();
    // 处理请求体
    if (body != null) {
      // ......
    }

    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }
    // 默认支持长连接
    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }
    // 默认支持 gzip 压缩
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }
    // 默认使用cookie在用户端保存信息
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }
    // 默认支持代理
    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }
    // 执行请求
    // .....
    }
    return responseBuilder.build();
  }

总结:桥接连接器主要是优化请求头的一些配置,例如:默认支持长连接;默认支持 gzip 压缩。

  1. 请求缓存拦截器 - CacheInterceptor

该拦截器主要是处理HTTP响应缓存的,如果。

总结如下:

  1. 使用 DiskLruCache 管理Http的响应缓存;
  2. 使用 CacheControll 验证缓存是否可用。
  1. 连接拦截器 - ConnectInterceptor

首先,OkHttp 会将请求缓存在一个连接池(ConnectionPool : 最多有5个空闲链接,一个链接最多存活5分钟,使用核心线程数为0,最大线程数为1,每个线程最多存活1分钟的线程池)中;接着,收到请求时,根据请求地址从连接池中查找是否有链接,如果有则返回;否则创建一个新的链接返回并加入连接池;

  1. CallServerInterceptor

该拦截器是整个请求的最后一步: 与服务端交换数据。

public Response intercept(Chain chain) throws IOException {
    //......
    //写入请求头数据
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);
    Response.Builder responseBuilder = null;
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
      //......
      if (responseBuilder == null) {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        realChain.eventListener().requestBodyStart(realChain.call());
        long contentLength = request.body().contentLength();
        //这里写入请求体
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
        realChain.eventListener()
            .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
      } else if (!connection.isMultiplexed()) {
        streamAllocation.noNewStreams();
      }
    }
    // 执行请求
    httpCodec.finishRequest();

    if (responseBuilder == null) {
      //这里请求返回,读取响应请求头
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    // 根据响应创建 Response
    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    realChain.eventListener()
        .responseHeadersEnd(realChain.call(), response);

    int code = response.code();
    if (forWebSocket && code == 101) {
      response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
      //读取返回内容
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }
    //......
    return response;
  }

总结
  1. Retrofit使用接口与注解描述一个HTTP请求;使用动态代理(反射技术)的方式创建接口实例,在调用接口方法时实现动态拦截。 参考上面第三步:创建网络请求接口实例
  2. 调用OkHttpCall执行网络请求与数据解析,由于 OkHttpCall是不带线程切换的,Retrofit 使用适配器 CallAdapter 包装 OkHttpCall, 并通过callbackExecutor将结果由子线程切换到UI线程;
  3. 使用ParameterHandler实现传递的参数向网络请求的转换;
  4. okhttp请求流程:首先通过调度器Dispatcher处理请求任务(请求又分为同步请求和异步请求),接着通过拦截器处理请求, 最后再举哀那个
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值