三方框架必学系列#Retrofit

三方框架必学系列#EventBus

三方框架必学系列#Rxjava

三方框架必学系列#Retrofit

三方框架必学系列#OkHttp

三方框架必学系列#Glide

三方框架必学系列#屏幕适配

一.基本使用

1.retrofit是什么

官网的解释是一个类型安全的HTTP请求客户端。它的底层的网络请求是基于 OkHttp 的,Retrofit 对其做了封装,提供了即方便又高效的网络访问框架,解决了线程切换,嵌套调用,数据转换的问题。

2.retrofit怎么用

我们先来看个简单get请求的例子,主要有三步:

1.通过retrofit的builder构建了一个retrofit的实列;

2.声明接口和获取接口代理,我们在ApiService中声明了一个get请求的方法,并且我们通过retrofit.create(xxx.class)创建了当前接口的代理对象;

3.调用接口的方法,我们直到在接口中定义的方法返回的是一个call对象,它是retrofit的call对象,当我们调用call.equeue对象,就会执行内部okHttp的call对象去执行网络请求,然后回调返回结果给我们。

less 复制代码
OkHttpClient okHttpClient=new OkHttpClient.Builder()
//添加日志拦截器
.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
    @Override
    public void log(String message) {

        System.out.println("HttpLoggingInterceptor message:"+message);
    }
}).setLevel(HttpLoggingInterceptor.Level.BODY))
.build();

//创建retrofit实列
Retrofit retrofit=new Retrofit.Builder()
.client(okHttpClient) //设置okhttpClient
.addConverterFactory(ScalarsConverterFactory.create())//设置转换器
.baseUrl(url)
.build();
vbnet 复制代码
public interface ApiService {
    /**
         * 最简单的GET请求,无参数
         */
    @GET("get")
    Call<String> getInfo1();
}
apiService = retrofit.create(ApiMethod.class);
typescript 复制代码
apiService.getInfo1().enqueue(new Callback<String>() {
    @Override
    public void onResponse(Call<String> call, Response<String> response) {
        String body = response.body();
        System.out.println(body);
    }

    @Override
    public void onFailure(Call<String> call, Throwable t) {

    }
});

3.retrofit的注解

通过上面的例子,我们已经知道了,在声明的接口中,我们都是通过注解来给请求做标记的,然后retrofit的内部就可以根据注解来解析对应的方法,那常用的注解有那些呢?

下面我们就来简单的介绍下:

1.常用请求方法注解

它是用来标识请求方法的注解。

@GET GET请求,作用在接口的方法上,表示它是一个GET请求
@POST POST请求,作用在接口的方法上,表示它是一个POST请求
@HTTP 通过注解可以替换以上所有注解,它拥有三个属性:method、path、hasBody
@DELETE DELETE请求,作用在接口方法上,表示是一个DELETE请求
less 复制代码
/**
 * 最简单的GET请求,无参数
 */
@GET("get")
Call<String> getInfo1();

/* POST请求
 * 其中@FormUrlEncoded的含义是发送已编码的Form表单
 * 加这个注解后,请求的Content-Type会是application/x-www-form-urlencoded;
 * 加这个注解后,发送的参数必须是@Field标记的表单键值对
 */
@FormUrlEncoded
@POST("post")
Call<String> getInfo2(@Field("sid") String id);

/**
 * Delete请求
 */
@DELETE("api/fetch/guesslike/{id}")
Call<String> getInfo3(@Path("id") String id, @Body String requestEntity);

/**
 * 下面定义了一个Delete请求,其实@HTTP标签是可以替代所有的请求标签,包括GET/POST/PUT/DELETE等,
 * 都可以通过@HTTP标签来实现。hasBody表示是否有请求体,有就用参数@Body带上
 */
@HTTP(method = "DELETE", path = "api/fetch/guesslike/{id}", hasBody = true)
Call<String> getInfo4(@Path("id") String id, @Body String requestEntity);

2.请求头注解

它为我们的请求增加请求头信息。

@Headers 用于添加固定请求头,可以同时添加多个,通过该注解的请求头不会相互覆盖,而是共同存在
@Header 作为方法的参数传入,用于添加不固定的header,它会更新已有请求头
less 复制代码
/**
 * GET请求,@Headers的作用是添加单个固定的请求头
 */
@Headers("Cache-Control: max-age=640000")
@GET("api/fetch/guesslike")
Call<String> getInfo10();


/**
 * GET请求,@Headers添加了多个固定的请求头
 */
@Headers({"Cache-Control: max-age=640000", "Accept-Charset: UTF-8"})
@GET("api/fetch/guesslike")
Call<String> getInfo11();

/**
 * GET请求,@Header是用在参数上,添加单个不固定的请求头,值由外部传进来
 */
@GET("api/fetch/guesslike")
Call<String> getInfo12(@Header("Accept-Charset") String charset);

3.请求参数注解

@Query 用于Get请求中的参数
@QueryMap 与Query类似,用于不确定表单参数
@Path 用于Url中的占位符
@Filed 多用于Post方式传递参数,需要结合@FromUrlEncoded使用,即以表单的形式传递参数
@FiledMap 用于表单字段,默认接受类型是Map<String,RequestBody>,可用于实现多文件上传
@Body 多用于Post请求发送非表达数据,根据转换方式将实例对象转化为对应字符串传递参数,比如使用Post发送Json数据
@Part 用于表单字段,Part和PartMap与@multipart注解结合使用,适合文件上传的情况
@PartMap 用于表单字段,默认接受类型是Map<String,RequestBody>,可用于实现多文件上传
@Url 指定请求路径
less 复制代码
/**
 * GET请求,带请求参数
 * 请求参数用@Query注解,其中注解里的名字表示追加到URL后的参数名字,
 * URL后的参数值即为我们传进来的类型String name/String age
 * 所以该请求完整的地址是host/api/fetch/guesslike?name=name&pwd=pwd
 */
@GET("get")
Call<String> getInfo2(@Query("name") List<String> stringList, @Query("pwd") String pwd);

/**
 * GET请求,带请求参数
 * 对getInfo2的改进,多个参数可以用@ueryMap标记,都放到一个Map里
 */
@GET("get")
Call<String> getInfo3(@QueryMap Map<String, String> paramsMap);

/**
 * GET请求,@Path标记的作用就是使用传进来的值动态替换URL里的字段{id}
 */
@GET("get/fetch/{id}/guesslike")
Call<String> getInfo4(@Path("id") String id);

/**
 * POST请求
 * 其中@FormUrlEncoded的含义是发送已编码的Form表单
 * 加这个注解后,请求的Content-Type会是application/x-www-form-urlencoded;
 * 加这个注解后,发送的参数必须是@Field标记的表单键值对
 */
@FormUrlEncoded
@POST("post")
Call<String> getInfo5(@Field("sid") String id);

/**
 * POST请求
 * 和getInfo5没区别,@FieldMap仅仅表示多个请求参数可以放到一个Map里方便传递而已
 */
@FormUrlEncoded
@POST("post")
Call<String> getInfo6(@FieldMap Map<String, String> map);
/**
 * POST请求,但是没有使用Form表单的形式,即没有@FormUrlEncoded
 * 那么请求的Content-Type默认会是application/json;
 * 不添加@FormUrlEncoded,那么就不能用@Field进行传递参数了,只有一种形式就是@Body,它就是用于非表单的请求体
 * retrofit会把请求的实体序列化成一个json发送出去
 */
@POST("post")
Call<String> upLoadString(@Body String body);

/**
 * 和upLoadString一样,只是请求参数是官方的RequestBody
 * 这样做的好处是,我们自己构建的RequestBody可以修改其Media-Type
 */
@POST("post")
Call<String> upLoadRequestBody(@Body RequestBody requestBody);

/**
 * POST请求
 * 其中@Multipart表示请求体是分为多个部分的,配合参数@Part使用。
 * 如果@Part的参数类型是RequestBody,表示请求参数,那么其Key,也就是"name"和"age"是不能隐藏的,必须显式指明Key
 * 如果@Part的参数类型是MultipartBody.Part,即表示请求的上传文件,内容会直接被使用,那么是不需要Key的
 */
@Multipart
@POST("post")
Call<String> getInfo14(@Part("name") RequestBody name, @Part("age") RequestBody age,
                       @Part MultipartBody.Part file);

/**
 * POST请求,getInfo14的改良版。多个请求参数可以封装在@PartMap标记对应的Map里
 */
@Multipart
@POST("post")
Call<String> getInfo15(@PartMap Map<String, RequestBody> paramsMap,
                       @Part MultipartBody.Part file);

4.请求和响应格式(标记)注解

@FromUrlCoded 表示请求发送编码表单数据,每个键值对需要使用@Filed注解
@Multipart 表示请求发送form_encoded数据(使用于有文件上传的场景),每个键值对需要用@Part来注解键名,随后的对象需要提供值
@Streaming 表示响应用字节流的形式返回,如果没有使用注解,默认会把数据全部载入到内存中,该注解在下载大文件时特别有用

4.retrofit中的数据解析器和call转换器

1.数据解析器

retrofit可以通过addConverterFactory设置数据解释器,例如添加Gson解释器。这是为了使来自接口的json结果会自动解析成定义好的字段和类型都相符的json对象接受类,在Retrofit 2.0中已经没有Converter,需要自己创建一个Converter, 不然Retrofit只能接收字符串结果,最后需要自己去解析。

数据解析器 gradle依赖
Gson com.squareup.retrofit2:converter-gson:2.0.2
Jackson com.squareup.retrofit2:converter-jackson:2.0.2
Simple XML com.squareup.retrofit2:converter-simplexml:2.0.2
Protobuf com.squareup.retrofit2:converter-protobuf:2.0.2
Moshi com.squareup.retrofit2:converter-moshi:2.0.2
Wire com.squareup.retrofit2:converter-wire:2.0.2
Scalars com.squareup.retrofit2:converter-scalars:2.0.2

数据解析器还是蛮好理解的,它会把请求返回的结果,通过解析器解析成特定的格式,回调给用户。

2.数据转换器

retrofit同时也是支持数据转换器的将请求的retrofit的call转换成特定的对象,比如.addCallAdapterFactory(RxJava2CallAdapterFactory.create())将请求返回的call包装成Observable对象,rxjava2的gradle依赖为:

arduino 复制代码
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.2'

那数据转换器又是在哪里操作的呢?这里简单的说下,它主要有以下几个步骤:

1.获取接口中的请求的方法的返回值类型;

2.通过转换器工厂获取转换器;

3.通过转换器的adapter方法,生成特定的转换器类型,比如如果你添加了 rxjava2,他就会帮你生成一个Observable<Resonse> 这个观察者,当你订阅的时候,call请求就会执行,并且就请求的结果,通过你注册的观察者传递给你,如果你还有下游观察者,则回调流回依次往下游传递;

二.原理介绍

其实通过前面的使用学习,我们已经大致知道了retrofit的基本原理,首先它是一个对于okHttp请求的二次封装,比如:1.我们可以通过接口和注解通过动态代理生成call;2.对于call的返回我们可以通过转换器和解析器将数据返回,并且支持rxjava和协程,协程我们后面再说,那rxjava就可以做数据切换,链式调用等一系列逻辑,完美解决了回调地狱的代码。所以下面我也就从 retrofit的构建及call的生成、转换器和解析器的工作来刨析原理。

1.retrofit的构建及注解生成的call

  • retrofit的构建:

也是通过构建者模式,可以设置baseurl、okHttpClient、数据转换器和数据解析器。

  • call的生成和调用

在retrofit中,当我们向调用接口中的方法时,我们先是通过retrofit.create(xxx.class)生成一个对象,并用接口去接收这个对象,那这个create方法是如何生成对象的呢?我们跟下源码:

typescript 复制代码
public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
            Proxy.newProxyInstance(
                service.getClassLoader(),
                new Class<?>[] {service},
                new InvocationHandler() {
                    private final Platform platform = Platform.get();
                    private final Object[] emptyArgs = new Object[0];

                    @Override
                    public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                    throws Throwable {
                        // If the method is a method from Object then defer to normal invocation.
                        if (method.getDeclaringClass() == Object.class) {
                            return method.invoke(this, args);
                        }
                        args = args != null ? args : emptyArgs;
                        return platform.isDefaultMethod(method)
                        ? platform.invokeDefaultMethod(method, service, proxy, args)
                        : loadServiceMethod(method).invoke(args);//
                    }
                });
}

很明显,这里面是一个动态代码,当我们在外部使用接口调用它的xxx方法时,其实就是调用到了loadServiceMethod(method).invoke(args);这个方法,我们来看下这个方法:

sql 复制代码
//ServiceMethod缓存
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;

synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method); //解析注解
        serviceMethodCache.put(method, result);
    }
}
return result;
}

原来它是调用ServiceMethod中的解析注解,我们继续跟源码

scss 复制代码
abstract class ServiceMethod<T> {
    //解析方法上的注解
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

HttpServiceMethod.java
    
    //解析注解
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();//获取方法上的注解
    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }
    //获取转换器 这里回做比对的
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();//转化器的返回类型
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }
    //获取解析器 这里会做比对的 根据type
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
        /**非协程的走这里,传入请求、转换器、数据解析器、callFactory(实际上就是okHttpClient,它在reftrofit中赋值)
        *请求有了,转换器、解析器、和okHttpClient都有了,就可以干活了->调用invoke()方法。
        **/
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable);
    }
  }

  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
      //noinspection unchecked
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }
  
 //invoke是调用流程   
@Override
final @Nullable ReturnT invoke(Object[] args) {
  /**创建了一个Call对象,是 OkHttpCall,这个不就是在 ApiGet 这个接口声明的 
  Call 对象吗?然后再看
  *OkHttpCall 的enqueue方法,不就知道是怎么进行请求,怎么回调的了吗?   
  **/
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);//adapt
}

  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

      //adapt会执行到这里,通过转换器转换请求
    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }

通过上面的流程我们可以看到,它通过注解解析后最终返回的是一个CallAdapter对象,并且这个对象持有了数据请求工厂,解析器和转换器。

2.call转换器的工作流程

我们接着上面流程继续分析,我们通过注解解析后,当我们执行invoke方法时,实际上它会执行CallAdapter中的adapt方法,那这个方法会调到我们设置的call转换器的方法中去,这里我们就以rxjava为例吧,我们跟下rxjava适配器的代码:

ini 复制代码
public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
    ? new CallEnqueueObservable<>(call)//异步
    : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
        observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
        observable = new BodyObservable<>(responseObservable);
    } else {
        observable = responseObservable;
    }

    if (scheduler != null) {
        observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
        return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
        return observable.singleOrError();
    }
    if (isMaybe) {
        return observable.singleElement();
    }
    if (isCompletable) {
        return observable.ignoreElements();
    }
    return RxJavaPlugins.onAssembly(observable);
}

我们跟下异步的请求,可以看到,它其实就是将我们传过来的call包裹到一个CallEnqueueObservable对象中去,我们继续跟CallEnqueueObservable源码:

java 复制代码
final class CallEnqueueObservable<T> extends Observable<Response<T>> {
    private final Call<T> originalCall;

    CallEnqueueObservable(Call<T> originalCall) {
        this.originalCall = originalCall;
    }

    @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
        // Since Call is a one-shot type, clone it for each new observer.
        Call<T> call = originalCall.clone();
        CallCallback<T> callback = new CallCallback<>(call, observer);//retrofit请求回调
        observer.onSubscribe(callback);
        if (!callback.isDisposed()) {
            call.enqueue(callback);//调用retrofit的请求方法
        }
    }

    private static final class CallCallback<T> implements Disposable, Callback<T> {
        private final Call<?> call;
        private final Observer<? super Response<T>> observer;
        private volatile boolean disposed;
        boolean terminated = false;

        CallCallback(Call<?> call, Observer<? super Response<T>> observer) {
            this.call = call;
            this.observer = observer;
        }

        @Override public void onResponse(Call<T> call, Response<T> response) {
            if (disposed) return;

            try {
                observer.onNext(response);

                if (!disposed) {
                    terminated = true;
                    observer.onComplete();
                }
            } catch (Throwable t) {
                Exceptions.throwIfFatal(t);
                if (terminated) {
                    RxJavaPlugins.onError(t);
                } else if (!disposed) {
                    try {
                        observer.onError(t);
                    } catch (Throwable inner) {
                        Exceptions.throwIfFatal(inner);
                        RxJavaPlugins.onError(new CompositeException(t, inner));
                    }
                }
            }
        }

        @Override public void onFailure(Call<T> call, Throwable t) {
            if (call.isCanceled()) return;

            try {
                observer.onError(t);
            } catch (Throwable inner) {
                Exceptions.throwIfFatal(inner);
                RxJavaPlugins.onError(new CompositeException(t, inner));
            }
        }

        @Override public void dispose() {
            disposed = true;
            call.cancel();
        }

        @Override public boolean isDisposed() {
            return disposed;
        }
    }
}

原来,它在注册这个被观察者时执行了call的请求,然会将回调回来的结果通过观察者将结果返回给了用户,至此,生成观察者,调用call请求,并将call请求的结果通过观察者返回给用户的流程就结束了,但是这里并没有说数据是如何解析的呢?我们接着往下看。

3.数据解析器的工作流程

前面我们说到,在rxadapter中,当我们订阅时它会执行retrofit的call方法的equeue执行请求,我们跟下源码:

scss 复制代码
@Override
public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");

    okhttp3.Call call;
    Throwable failure;

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

        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的call请求过程
    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) {
                    throwIfFatal(e);
                    callFailure(e);
                    return;
                }

                try {
                    callback.onResponse(OkHttpCall.this, response);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace(); // TODO this is not great
                }
            }

            @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) {
                    throwIfFatal(t);
                    t.printStackTrace(); // TODO this is not great
                }
            }
        });
}

@Override
public synchronized boolean isExecuted() {
    return executed;
}

@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;

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

    call = getRawCall();
}

if (canceled) {
    call.cancel();
}

return parseResponse(call.execute());
}

private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
}
return call;
}

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse =
    rawResponse
    .newBuilder()
    .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
    .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
        try {
            // Buffer the entire body to avoid future I/O.
            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 = responseConverter.convert(catchingBody);//通过解析器解析数据
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    // If the underlying source threw an exception, propagate that rather than indicating it was
    // a runtime exception.
    catchingBody.throwIfCaught();
    throw e;
  }
}

原来它是通过okHttp请求后再将数据通过解析器去解析即可。

4.图解整个工作流程

相关推荐
安卓程序猿2 小时前
kotlin build.gradle.kts下修改APK的输出名称
android·kotlin·gradle
wuwu_q2 小时前
通俗易懂 + Android 开发实战的方式,详细讲讲 Kotlin 中的 StateFlow
android·开发语言·kotlin
峰哥的Android进阶之路2 小时前
Kotlin面试题总结
android·开发语言·kotlin
美摄科技2 小时前
android短视频sdk,灵活集成,快速上线!
android·音视频
佳哥的技术分享2 小时前
图形化android可视化开机观测工具bootchart
android
杨筱毅2 小时前
【底层机制】 Android ION内存分配器深度解析
android·底层机制
abner.Li2 小时前
基于AOSP11创建一个能用emulator启动的android tv产品
android
suki_lynn4 小时前
Facebook 引流脚本:功能、风险与合规使用指南
android·云计算