Android Retrofit 概览

Retrofit

Posted by Tan Lin on May 4, 2019

Retrofit介绍

Retrofit 是基于OkHttp网络请求框架的二次封装,提供了更灵活易用的API,底层的网络请求仍然是OkHttp

AndroidAsyncHttp: 基于HttpClient,已废弃,Android5.0 不再使用 HttpClient
Volley: 基于 HttpUrlConnection, google官方推出,比较适合轻量级的网络交互,不适合大文件上传下载场景
Retrofit: API 简洁易用,注解配置高度解耦,支持RxJava

集成 Retrofit

  1. 依赖库
     versions.okhttp = "3.9.0"
     versions.retrofit = "2.5.0"
        
     // retrofit
     def retrofit = [:]
     retrofit.retrofit = "com.squareup.retrofit2:retrofit:$versions.retrofit"
     retrofit.gson = "com.squareup.retrofit2:converter-gson:$versions.retrofit"
     retrofit.rxjava2 = "com.squareup.retrofit2:adapter-rxjava2:$versions.retrofit"
     deps.retrofit = retrofit
     // okhttp
     def okhttp = [:]
     okhttp.okhttp = "com.squareup.okhttp3:okhttp:$versions.okhttp"
     okhttp.interceptor = "com.squareup.okhttp3:logging-interceptor:$versions.okhttp"
     deps.okhttp = okhttp
    
  2. 网络权限
     <use-permission android:name="android.permission.INTERNET"/>
    

创建接口设置 get/post

@GET、@POST: 请求方式,还有PUT/HEAD/OPTIONS等
@Path: 请求URL的字符代替, GET("/image/{id}") ResponseBody.example(@Path("id") int id);
@Query: 传递的参数
@QueryMap: 需要添加过多的参数时,用Map包裹起来
@Field: 传递的参数
@FieldMap: 需要添加过多的参数时,用Map包裹起来
@Body: 请求实体对象
@FormUrlEncoded: URL 编码,一般会配合@post @feild一起使用

常用的数据解析器

Moshi: squre-JSON-for-kotlin-and-Java
Protobuf: google-data-interchange-format

versions.okhttp = "3.9.0"
versions.retrofit = "2.5.0"

Gson: "com.squareup.retrofit2:converter-gson:$versions.retrofit"
Jackson: "com.squareup.retrofit2:converter-jackson:$versions.retrofit"
SimpleXML: "com.squareup.retrofit2:converter-simplexml:$versions.retrofit"
Protobuf: "com.squareup.retrofit2:converter-protobuf:$versions.retrofit"
Moshi: "com.squareup.retrofit2:converter-moshi:$versions.retrofit"
Wire: "com.squareup.retrofit2:converter-wire:$versions.retrofit"
Scalars: "com.squareup.retrofit2:converter-scalars:$versions.retrofit"

使用

Retrofit retrofit = new Retrofit.Builder()
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .baseUrl(baseUri)
    .build();

public interface UserService {
    // Resule<T> { int code; String message; T data }
    // server return most like { code: 200, message: 'success', data: {} }
    @GET
    Call<Result<UserInfo>> login(@Query("name") String name, @Query("pass") String pass)
    // rxjava
    // Flowable<Result<UserInfo>> login(@Query("name") String name, @Query("pass") String pass)
}

UserService uService = retrofit.create(UserService.class)
Call<Result<UserInfo>> call = uService.login("name", "password")
// sync:call.excute()/ async:call.enqueue()
Response<Result<UserInfo>> rsp = call.excute()
android.Util.Log.d("TAG", "" + rep.code() + " and " + rep.body().code())

// 异步方式
call.enqueue(new CallBack<Result<UserInfo>>() {
    onResponse(Call<Result<UserInfo>> call, Response<Result<UserInfo>> rsp);
    onFailer(Call<Result<UserInfo>> call, Throwable t)
})

// rxjava
// Flowable<Result<UserInfo>> flowable = uService.login("name", "password")
// ...

// --------- //
// Kotlin
// val uService: UserService = retrofit.create(UserService::class.java)
// val call: Call<UserInfo> = uService.login("name", "password")

Note
使用post请求时,如果请求参数使用了field,需要指定FormUrlEncoded

Retrofit原理

使用方通过 Retrofit 获得网络数据,必然会经历建立连接并读取网络连接数据这两个重要过程

如何构建一个请求

Retrofit在在调用create的时候,动态代理的方式创建一个Interface的实例

创建 Interface 实例

public <T> T create(final Class<T> service) {
    // 动态代理
    // Proxy.newProxyInstance(cl, interfaces, handler)
    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 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);
                    }
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                    return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
                }
            }
}

后续调用service.getHttpData(x, y)的时候在实例化一个 HttpServiceMethod。 那到底是如何实例化这个method呢? 前面提到了 CallAdapterFactory,这就是如何创建一个请求的工厂,他通过Interface中定义的方法的注解创建 对应的请求。调用步骤如下

loadServiceMethod -> ServiceMethod.parseAnnotations(retrofit, method)
    RequestFactory.parseAnnotations
    HttpServiceMethod.parseAnnotations -> createCallAdapter
    HttpServiceMethod.parseAnnotations -> createResponseConverter
invoke()

可以看到,创建了发起请求的adapter和转换response的converter,然后

abstract class ServiceMethod<T> {
    static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        // 根据方法的注解 @POST/@GET和方法的参数(post或get请求方式服务端要求的参数)获取一个请求工厂
        // parseParameter解析参数,@Field/@FieldMap等
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        Type returnType = method.getGenericReturnType();
        ...
        // 实例化一个method
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }
    abstract T invoke(Object[] args);
}

HttpServiceMethod.java extends ServiceMethod

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
    callAdapter = createCallAdapter(retrofit, method);
    ...
    responseConverter = createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}

Retrofit.java

// 寻找合适的callAdapter
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    CallAdapter<?, ?> adapter = null;
    for (i < factories.size) {
        adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
            return adapter;
        }
    }
    throw new IllegalArgumentException("xxx");
}

// 寻找合适的 convertAdapter
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    Converter<ResponseBody, ?> converter = null;
    for (i < factories.size) {
        converter = callAdapterFactories.get(i).responseBodyConverter(type, annotations, this);
        if (converter != null) {
            return (Converter<ResponseBody, T>) converter;
        }
    }
    throw new IllegalArgumentException("xxx");
}

RxJava2CallAdapterFactory.java

public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
}

// 注意看get 方法的参数,returnType,annotations
@Override
public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);
    // scheduler = null, isAsync = false
    return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
}

RxJava2CallAdapter.java

@Override
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);
}

终于创建成功了一个 httpservicemethod,已经完成了post/get的参数解析。看起来 似乎只要调用这个 httpservicemethod 的时候即可创建Http请求并获取返回值

// HttpServiceMethod.java super ServiceMethod
// final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
@Override
ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}

原理-获取请求的返回值

接着看adapt

@Override
public Object adapt(Call<R> call) {
    // 注意这里的 isAsync,默认create创建的是同步请求,isAsync = false
    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);
    }
    ...
    return RxJavaPlugins.onAssembly(observable);
}

咦,怎么就返回了一个Observable/Flowable。原来,调用servicemethod并没有发生http请求。那如何创建request呢?

创建OkHttp

// CallExecuteObservable.java
protected void subscribeActual(Observer<? super Response<T>> observer) {
    Call<T> call = originalCall.clone();
    boolean terminated = false;
    try {
        Response<T> response = call.execute();
        if (!disposable.isDisposed()) {
            observer.onNext(response);
        }
        if (!disposable.isDisposed()) {
            terminated = true;
            observer.onComplete();
        }
    } catch (Throwable t) {
        ...
    }
}
// OkHttpCall
@Override
public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
        // 一个 call 只能执行一次
        if (executed) throw new IllegalStateException("Already executed.");
        executed = true;

        ...

        call = rawCall;
        if (call == null) {
            try {
                // 创建一个 okhttp3.Call
                call = rawCall = createRawCall();
            } catch (IOException | RuntimeException | Error e) {
                throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
                creationFailure = e;
                throw e;
            }
        }
    }

    if (canceled) {
        call.cancel();
    }
    // 执行 okhttp3.call后,解析并转换请求回来的body
    return parseResponse(call.execute());
}

private okhttp3.Call createRawCall() throws IOException {
    // 就是通过 OkHttpClient 创建了一个 okhttp3.Call
    // 从哪里获取的这个 callFactory
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}

callFactory

原来,Retrofit 设置 Client 的时候,就是在设置 callFactory,即设置OkHttpClient为callFactory

// Retrofit.java
public Builder client(OkHttpClient client) {
    return callFactory(checkNotNull(client, "client == null"));
}

public Builder callFactory(okhttp3.Call.Factory factory) {
    this.callFactory = checkNotNull(factory, "factory == null");
    return this;
}

执行 http 同步请求

@Override
public Response execute() throws IOException {
    Response result = getResponseWithInterceptorChain();
}

执行 http 异步请求

@Override
public void enqueue(Callback responseCallback) {
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already Executed");
        executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

for (int i = 0, size = executableCalls.size(); i < size; i++) {
    AsyncCall asyncCall = executableCalls.get(i);
    asyncCall.executeOn(executorService());
    // executorService.execute(this);
}


// 是一个 Runable,run 方法再次调用 execute 方法
final class AsyncCall extends NamedRunnable {
    @Override
    protected void execute() {
        Response response = getResponseWithInterceptorChain();
        responseCallback.onResponse(RealCall.this, response);
    }
}

核心请求逻辑

// 同步或者异步最终都会调用这个方法
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    // 添加自定义的拦截器
    interceptors.addAll(client.interceptors());
    // 这里开始创建 StreamAllocation
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    // 建立 socket 连接
    interceptors.add(new ConnectInterceptor(client));
    // network intercepters,这些拦截器是在socket连接建立成功后才会执行的
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    // 向服务端发送请求,header+body等
    // 这个拦截器最后不会再调用 chain.process,已经处于链的末端了
    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);
}

总结

Retrofit 是OkHttp的二次封装,使用注解方式,使得网络请求参数配置更为灵活,扩展性更好 多数的开源库也使用Retrofit进行网络请求