• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Android Retrofit理解

武飞扬头像
Jamison Tam
帮助1


一、对Retrofit的理解

Retrofit底层依赖OkHttp请求网络,是一个RESTful的HTTP网络请求框架的封装,简单理解成封装了OkHttp即可,通过请求参数等方式向服务端请求数据,Retrofit会根据返回数据进行解析。

二、特点

  • 支持同步、异步
  • 通过注解配置请求(请求头,方法、返回值)
  • 通过converter将获得的数据解析和序列化
  • 支持Gson、Jackson、Protobuf等
  • 支持RxJava
  • 性能好,速度快
  • 拓展性差,因为使用的converter都是统一的

三、简明使用

配置和注解使用这里不详述,在参考文章里面都有,这里仅仅对我写过的例子进行解析。

//这里我使用的彩云天气的api,因此需要提交GET请求获得天气数据,解析返回数据
public interface PlaceService {
    @GET("v2/place?token={token}=zh_CN")//注解表明为get请求,值为相对url
    Call<PlaceResponse> searchPlaces(@Query("query")String query);//指定返回数据类型,在下面会配置解析器,这里需要提前根据json数据格式,创建对应的数据类型
}

//构建retrofit对象,设置一些配置项
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://baseUrl/")//baseUrl
        .addConverterFactory(GsonConverterFactory.create())//设置请求参数和请求结果的数据转换,通常我们可以使用retrofit提供的Gson解析,这里api返回的是json数据,因此这样设置
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//设置返回类型的解析器,retrofit默认提供的是一个Call对象,可以直接发起请求,我们也可以使用其提供的RXJava的解析器,使其可以返回Observable对象进行链式调用请求,下面会细说
        .build();//builder模式构建

RequestService requestService = retrofit.create(PlaceService.class);//通过retrofit的动态代理,创建请求接口对象
Call<DataModel> call = requestService.getData("v1");//调用请求的代理对象的相应方法,传入参数,生成Call对象

call.enqueue(new Callback<DataModel>() {//使用Call对象enqueue发起异步请求,并设置回调
    @Override
    public void onResponse(Call<DataModel> call, Response<DataModel> response) {//请求成功
        DataModel model = response.body();
        //success
    }

    @Override
    public void onFailure(Call<BookSearchModel> call, Throwable t) {//请求失败
		//failed
    }
});
 
call.cancel();//取消掉请求:回调不会再调用,socket连接被终止
学新通

四、 参数配置

  • CallFactory
    CallFactory是请求所用的客户端,默认为OkHttpClient,但可自定义。
  • ConverterFactory
    转换请求的参数和请求回来的数据,此类通过工厂模式构建出converter,提供转换的方法。
public interface Converter<F, T> {
  T convert(F value) throws IOException;//F转换为T

  abstract class Factory {//工厂模式
	//提供将ResponseBody转换的Converter
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }
	//提供将params转换为RequestBody的Converter
    public Converter<?, RequestBody> requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      return null;
    }
  }
}
 
//retrofit提供的用gson转换的ConverterFactory
public final class GsonConverterFactory extends Converter.Factory {
  ...
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
  ...
}
//retrofit提供的用gson转换ResponseBody的Converter
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  ...
  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
	return adapter.read(jsonReader);
  }
}
学新通

看得出其实就是定义convert,在factory的两个方法中用convert来解析数据。

  • CallAdapterFactory
static final class ExecutorCallbackCall<T> implements Call<T> {
  final Executor callbackExecutor;
  final Call<T> delegate;

  ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
    this.callbackExecutor = callbackExecutor;
    this.delegate = delegate;//实际的OkHttpCall对象
  }

  @Override public void enqueue(final Callback<T> callback) {
    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()) {
              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);
          }
        });
      }
    });
  }
}
学新通

常规返回的是Call对象,当想使用RXJava时,可以通过CallAdapterFactory,生成CallAdapter对象,封装原始的OkHttpCall对象为想要的返回类型,retrofit提供的是Cal对象的CallAdapter。

  • CallbackExecutor
    当异步请求结束返回数据时,需要将数据放到主线程中,因此需要回调callback,Retrofit提供了executor来回调callback,默认提供的是回调主线程的Executor。
static class MainThreadExecutor implements Executor {
  private final Handler handler = new Handler(Looper.getMainLooper());
  @Override public void execute(Runnable r) {
    handler.post(r);//回调到主线程中
  }
}

Retrofit的create

前面配置完retrofit对象,这时就需要使用create创建了

public <T> T create(final Class<T> service) {
  ...
  //创建动态代理对象返回
  return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
      new InvocationHandler() {
        @Override public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
          ...
          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);//根据这个method对象,解析生成ServiceMethod对象,其保存请求方法解析出来的url、params等各种参数
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);//构建OkHttpCall对象,保存serviceMethod和传入的参数,用户请求时生成完整的请求对象
          return serviceMethod.callAdapter.adapt(okHttpCall);//调用ServiceMethod中根据method的返回类型生成的CallAdapter的adapt方法,将OkHttpCall对象包装成相应类型返回
        }
      });
}

这里就是返回了代理对象,代理对象里面有两个成员变量值得关注:ServiceMethod、OkHttpCall。

每当我们调用接口对象某个请求方法时,代理到invoke方法,参数包含调用的方法method对象,以及传入的各种参数。

ServiceMethod对象用于解析method各种注解、参数类型、返回类型,根据这些生成相应的CallAdapter和Converter等。

至于OkHttpCall对象,传入ServiceMethod对象和调用的参数,结合两者生成完整的request对象,交给OkHttp发起请求;

最后调用ServiceMethod中,由对应的CallAdapter的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();//否则通过builder模式创建一个ServiceMethod对象,并放入缓存
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

前面提到了调用ServiceMethod,通过loadServiceMethod获取对应的method对象,并使用缓存机制,有则直接取出,无则创建并放入缓存,避免重复重建。

ServiceMethod的build
//创建时拿到各种注解
Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();//方法上的注解
  this.parameterTypes = method.getGenericParameterTypes();//参数的类型
  this.parameterAnnotationsArray = method.getParameterAnnotations();//参数上的注解
}
 
//build构建
public ServiceMethod build() {
  callAdapter = createCallAdapter();//根据method的返回类型,去retrofit里注册的CallAdapter里依次去找,找到可以处理的CallAdapter即可
  responseType = callAdapter.responseType();//CallAdapter返回类型,这里指的其实是泛型类型,即Call<DataModel>时指的是实际请求的数据类型DataModel
  ...
  responseConverter = createResponseConverter();//根据responseType生成转换ResponseBody的Converter对象

  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);//根据方法签名上的注解,解析出相应的请求类型等值,如url、headers、请求方法、是否为富文本等信息
  }
  ...
  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];//参数处理器,用于将注解等应用到实际参数上生成RequestBody
  for (int p = 0; p < parameterCount; p  ) {
    Type parameterType = parameterTypes[p];//第p个参数类型
    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];//第p个参数的所有注解
    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);//生成Handler
  }
  ...
  return new ServiceMethod<>(this);
}
学新通

主要是获取注解、参数、参数转换器convert、返回类型转换call adapter

生成request对象
Request toRequest(Object... args) throws IOException {
  RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
      contentType, hasBody, isFormEncoded, isMultipart);//使用已经解析出来的基本参数创建RequestBuilder对象
  ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
  int argumentCount = args != null ? args.length : 0;
  for (int p = 0; p < argumentCount; p  ) {
    handlers[p].apply(requestBuilder, args[p]);//每个ParameterHandler对RequestBuilder应用arg参数
  }
  return requestBuilder.build();//构建Request对象,内部使用OkHttp的Request.Builder构建出Request对象
}
 
//比如处理@Body的ParameterHandler.Body
static final class Body<T> extends ParameterHandler<T> {
  private final Converter<T, RequestBody> converter;

  Body(Converter<T, RequestBody> converter) {
    this.converter = converter;
  }

  @Override void apply(RequestBuilder builder, T value) {
    RequestBody body;
	...
    body = converter.convert(value);//使用converter转换arg为相应类型
	...
    builder.setBody(body);//设置到RequestBuilder里
  }
}
学新通

省流:添加参数到handlers中,并通过convert转换为响应类型,最后组装成所需request对象,response同理。

OkHttpCall

final class OkHttpCall<T> implements Call<T> {
  ...
  OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {//保存了ServiceMethod对象和实际参数args
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

  @Override public void enqueue(final Callback<T> callback) {//异步发起请求
    okhttp3.Call call;
    ...
	call = rawCall = createRawCall();//创建OkHttp的call对象
	...
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
		response = parseResponse(rawResponse);//转换response
        callSuccess(response);//回调callback
      }
	...
      private void callSuccess(Response<T> response) {
        callback.onResponse(OkHttpCall.this, response);//回调callback
      }
    });
  }

  private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);//这步是关键,使用serviceMethod结合(应用)args,生成完整的Request对象
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);//使用retrofit配置的CallFactory(OkHttpClient)执行request对象,生成OkHttp的call对象
    ...
    return call;
  }

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    ...
    int code = rawResponse.code();
    if (code < 200 || code >= 300) {//请求成功/失败
      ...
    }
    ...
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);//包装responseBody
	...
    T body = serviceMethod.toResponse(catchingBody);//这步也是关键,使用ServiceMethod对象,将原始的ResponseBody转换为我们想要的(返回值泛型类型)类型数据
    return Response.success(body, rawResponse);
  }
}
学新通

构建Request对象,通过CallFactory构建Call对象,通过Call对象发起请求,监听回调,将返回的数据进行解析,将解析后的结果返回。

Cancel

//OkHttpCall.cancel()
public void cancel() {
  canceled = true;//标志位置为true,请求还未发送时则不会发送了
  okhttp3.Call call;
  synchronized (this) {
    call = rawCall;
  }
  if (call != null) {
    call.cancel();//关闭OkHttp的call对象,包括socket连接
  }
}
 
//默认的代理类ExecutorCallbackCall.cancel
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()) {//如果已经被cancel掉则会模拟当作请求失败,调用onFailure,而不会调用onResponse
          callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
        } else {
          callback.onResponse(ExecutorCallbackCall.this, response);
        }
      }
    });
  }

  @Override public void onFailure(Call<T> call, final Throwable t) {
    ...
  }
});
学新通

使用callback时,一般需要使用静态内部类 弱引用,避免内存泄漏和防止如当界面销毁时,回调方法里面还持有与界面相关的变量。

五、RXJava

RXJavaCallAdapter

//CallAdapterFactory
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
  public static RxJavaCallAdapterFactory create() {//请求时使用当前线程发起请求,即调用call.execute
    return new RxJavaCallAdapterFactory(null, false);
  }
  public static RxJavaCallAdapterFactory createAsync() {//请求时使用异步发起请求,即调用call.enqueue
    return new RxJavaCallAdapterFactory(null, true);
  }
  public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {//请求时使用自定义的线程策略,即调用subscribeOn设置指定shcedulers
    return new RxJavaCallAdapterFactory(scheduler, false);
  }

  private final Scheduler scheduler;
  private final boolean isAsync;

  private RxJavaCallAdapterFactory(Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);
	...
    if (rawType != Observable.class && !isSingle && !isCompletable) {//处理类型为Observable的返回值类型
      return null;
    }
    ...
    return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
        false);
  }
}
学新通

提供了三种策略了启动RXJavaCallAdapterFactory,并可通过get返回对应的CallAdapter。

RXJavaCallAdapter

//adapt方法包装OkHttpCall对象
@Override public Object adapt(Call<R> call) {
  //根据是否异步请求创建不同的OnSubscribe对象包装call
  OnSubscribe<Response<R>> callFunc = isAsync
      ? new CallEnqueueOnSubscribe<>(call)
      : new CallExecuteOnSubscribe<>(call);
  ...
  Observable<?> observable = Observable.create(func);//创建Observable对象
  //设置schedulers的话设置subscribeOn
  if (scheduler != null) {
    observable = observable.subscribeOn(scheduler);
  }
  ...
  return observable;
} 
 
//执行异步请求的CallEnqueueOnSubscribe
final class CallEnqueueOnSubscribe<T> implements OnSubscribe<Response<T>> {
  private final Call<T> originalCall;

  CallEnqueueOnSubscribe(Call<T> originalCall) {
    this.originalCall = originalCall;//原始call对象
  }

  @Override public void call(Subscriber<? super Response<T>> subscriber) {
    Call<T> call = originalCall.clone();
    ...
    call.enqueue(new Callback<T>() {//使用异步发起请求
      ...//回调subscriber
    });
  }
}
学新通

通过adapt方法返回Observe对象,其封装了原始Call对象。

六、参考

Android Retrofit 原理解析
死磕Android_Retrofit 原理解析
由浅入深剖析Retrofit原理,收好了!!!
Carson带你学Android:这是一份详细的 Retrofit使用教程(含实例讲解)
Android Retrofit详解

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfkccb
系列文章
更多 icon
同类精品
更多 icon
继续加载