retrofit get请求_妙不可言的Retrofit

34ad9d2b91eb0b4a01020ce3fd569427.png
作者丨水煮鸡蛋也好吃
来源丨Android开发中文站
https://juejin.im/post/5e44ea086fb9a07c9e1c19b6
前言
噢! 亲爱的朋友们,快来看看这优秀的Retrofit,它实在太美妙了,如果你不看的话,我保证会用我的靴子狠狠地踢你的屁股! (狗头保命) 34824cfc99acd69a8f6b04b1840ce951.png
正文
1. 什么是Retrofit?
在 官网 中对它的描述:
A type-safe HTTP client for Android and Java
大概意思也就是针对 Java 和 Android的 一种类型安全的HTTP库. Retrofit是Square开源的一款优秀的网络框架,它不会自己去请求网络,而是对OkHttp进行了封装。 仅仅会使用还不够,学习源码有助于我们更好的成长。
2. Retrofit的使用
我们先来看看官网上的案例: 先定义你的网络接口
public interface GitHubService {    @GET("users/{user}/repos")    Call> listRepos(@Path("user") String user);}
创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()        .baseUrl("https://api.github.com/")        .build();
获得网络请求API的实例
GitHubService service = retrofit.create(GitHubService.class);
调用API方法
Call<List> call = service.listRepos("octocat");
执行网络请求
// 同步try {    List repos = call.execute().body();} catch (IOException e) {    e.printStackTrace();}// 异步call.enqueue(new Callback<List>() {    @Override    public void onResponse(Call<List> call, Response<List> response) {        // 数据返回成功    }    @Override    public void onFailure(Call<List> call, Throwable t) {       // 数据返回失败    }});
至此,Retrofit的一次网络请求就结束了,是不是很简单。 Retrofit大大减轻了开发者对于网络请求的操作。
3.Retrofit的URL和参数类型
3.1 Url规则和配置
支持的协议:GET / POST / PUT / DELETE / HEAD / PATCH 比如:
@GET("users/{user}/repos")
GET中的value 要和baseUrl整合一起 我们来看看baseUrl和value的整合规则:
第一种:
path 是 绝对路径形式:
path = "/apath", baseUrl = "http://host:port/a/b"Url = "http://host:port/apath"
第二种:
path 是相对路径,baseUrl 目录形式:
path = "apath", baseUrl = "http://host:port/a/b/"Url = "http://host:port/a/b/apath"
第三种:
path 是相对路径,baseUrl 是文件形式:
path = "apath", baseUrl = "http://host:port/a/b"Url = "http://host:port/a/apath"
第四种:
path 是完整Url:
path = "http://host:port/aa/apath", baseUrl = "http://host:port/a/b"Url = "http://host:port/aa/apath"
建议整个项目都统一使用一种路径方式,一般选择第二种方式。
3.2 参数类型
通过注解的形式令Http请求的参数更加直接。
3.2.1 Query & QueryMap
Query 其实就是Url 中 ? 之后的 key-value。 比如:
url :"www.println.net/?cate=andro…"
其中 cate=android 就是 Query。
interface PrintlnServer{ @GET("/")Call<String> cate(@Query("cate") String cate); } //参数 cate 就是 它的 key,传入的值 就是它的 value
如果拥有多个参数的话 , 可以使用 QueryMap。
3.2.2 Field & FieldMap
在项目中,大部分情况下我们是使用POST。
   @FormUrlEncoded   @POST("/")   Call example(@Field("name") String name,                              @Field("occupation") String occupation);       // 需要注意的是 使用Field 的时候,要加 @FormUrlEncoded 用来格式化。
如果 你有多个参数需要填写, 当然可以使用 FieldMap 。
3.2.3 Part & PartMap
用于上传文件 案例:
public interface FileUploadService {@Multipart@POST("upload")Call upload(@Part("description") RequestBody description,
@Part MultipartBody.Part file);}// 注意使用 注解 @Multipart************************ 使用案例 ***********************//先创建 serviceFileUploadService service = retrofit.create(FileUploadService.class);//构建要上传的文件File file = new File(filename);RequestBody requestFile =RequestBody.create(MediaType.parse("application/otcet-stream"), file);MultipartBody.Part body =MultipartBody.Part.createFormData("aFile", file.getName(), requestFile);String descriptionString = "This is a description";RequestBody description =RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);Call call = service.upload(description, body);call.enqueue(new Callback() {@Overridepublic void onResponse(Call call,
Response response) {System.out.println("success");}@Overridepublic void onFailure(Call call, Throwable t) {t.printStackTrace();}});
当然如果需要多个Part参数,可以使用PartMap 。 接下来我们来看下Retrofit的原理是如何完成的。
4. Retrofit的原理
4.1 Retrofit的create方法
我们首先进入到create方法中:
public  T create(final Class service) {  // 在这里验证 接口是否合理  validateServiceInterface(service);  // 用到了Java的动态代理技术  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 {          // 如果对象是Object,不用管它          if (method.getDeclaringClass() == Object.class) {            return method.invoke(this, args);          }          // 是否是Java8                  if (platform.isDefaultMethod(method)) {            return platform.invokeDefaultMethod(method, service, proxy, args);          }          return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);        }      });}
在这里用到了Java的动态代理,可以看到我们在invoke中,我们进入到了loadServiceMethod中:
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是比较耗时间的,而且一个api可能伴随着频繁的调用,所以在这里使用缓存技术可以有效的减少时间的消耗。 当缓存中不存在的时候,就需要我们去创建一个新的ServiceMethod,于是调用 ServiceMethod.parseAnnotations(this, method):
static  ServiceMethod 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);}
让我们再进入到 HttpServiceMethod 中看看:
static  HttpServiceMethod parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {  //....省略部分代码  CallAdapter callAdapter =    createCallAdapter(retrofit, method, adapterType, annotations); //.....Converter responseConverter =    createResponseConverter(retrofit, method, responseType);//. . . . return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);//....}
先来看看 callAdapter 是怎么创建的? 进入到 createCallAdapter 中:
private static  CallAdapter createCallAdapter(
    Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {  try {    //noinspection unchecked    return (CallAdapter) 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);  }}
再进入到 retrofit.callAdapter(returnType, annotations) :
public CallAdapter, ?> callAdapter(Type returnType, Annotation[] annotations) {  return nextCallAdapter(null, returnType, annotations);}
进入到nextCallAdapter() :
public CallAdapter, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,    Annotation[] annotations) {  Objects.requireNonNull(returnType, "returnType == null");  Objects.requireNonNull(annotations, "annotations == null");  int start = callAdapterFactories.indexOf(skipPast) + 1;  for (int i = start, count = callAdapterFactories.size(); i     CallAdapter, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);    if (adapter != null) {      return adapter;    }  } // ...... 省略部分代码}
可以看到是从 callAdapterFactories 这个list集合中获取的,如果我们没有添加过CallAdapterFactory即:
      Retrofit retrofit = new Retrofit.Builder()              .baseUrl("https://api.github.com/")              .addCallAdapterFactory(RxJavaCallAdapterFactory.create())              .build();
那么会自动使用一个默认的CallAdapterFactory: DefaultCallAdapterFactory 这个对象在build() 的时候会添加到集合中去:
public Retrofit build() {  // .....  //在这里添加 默认的 CallAdapterFactory  List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));  // .... }
我们再转回来,最终会返回一个CallAdapted的实例,这个类的父类其实就是 HttpServiceMethod
static final class CallAdaptedReturnT> extends HttpServiceMethodReturnT> 
就这样,在Retrofit的create的方法中loadServiceMethod 最终也是 返回了 一个 CallAdapted 实例,这个实例调用了 invoke方法,但是CallAdapted类没有invoke方法,那么追溯到它的父类 HttpServiceMethod :
@Override final @Nullable ReturnT invoke(Object[] args) {  Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);  return adapt(call, args);}
在这里创建了 一个 OkHttpCall ,然后调用了 adapt方法,CallAdapted类实现了这个抽象方法:
@Override protected ReturnT adapt(Call call, Object[] args) {  return callAdapter.adapt(call);}
这个 callAdapter 就是默认的DefaultCallAdapter :
@Override public Call adapt(Call call) {  return executor == null      ? call      : new ExecutorCallbackCall<>(executor, call);}
当 API调用的时候返回的Call对象就是这个了。 在这里 executor 是不为null的,所以我们得到的 Call实例 是 ExecutorCallbackCall。 因为在 Retrofit类的build() 的方法中:
Executor callbackExecutor = this.callbackExecutor;if (callbackExecutor == null) {  callbackExecutor = platform.defaultCallbackExecutor();}
所以 拿到的是 platform 的 defaultCallbackExecutor(), 先看看 platform 的创建:
private static Platform findPlatform() {  try {    Class.forName("android.os.Build");    if (Build.VERSION.SDK_INT != 0) {      return new Android();    }  } catch (ClassNotFoundException ignored) {  }  return new Platform(true);}
如果是 Android的话,则创建Andoid类:
static final class Android extends Platform {  Android() {    super(Build.VERSION.SDK_INT >= 24);  }  @Override public Executor defaultCallbackExecutor() {    return new MainThreadExecutor();  }  static class MainThreadExecutor implements Executor {    private final Handler handler = new Handler(Looper.getMainLooper());    @Override public void execute(Runnable r) {      handler.post(r);    }  }}
所以 callbackExecutor是存在的,且数据会通过handler传递到主线程中。
4.2 Retrofit的网络请求
现在我们来看一下 Retrofit的网络请求:
call.enqueue(new Callback>() {    @Override    public void onResponse(Call> call, Response> response) {        // 数据返回成功        Log.i("zxy", "onResponse: success");    }    @Override    public void onFailure(Call> call, Throwable t) {       // 数据返回失败        Log.i("zxy", "onFailure: fail");    }});
首先我们知道了 这个call 是 ExecutorCallbackCall的 实例: 让我们找到 enqueue 方法:
@Override public void enqueue(final Callback callback) {  Objects.requireNonNull(callback, "callback == null");  // 这个 delegate 就是 OKHttpCall   delegate.enqueue(new Callback() {    @Override public void onResponse(Call call, final Response response) {      // callbackExecutor 会通过handler 将数据回调到主线程      callbackExecutor.execute(() -> {        if (delegate.isCanceled()) {          callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));        } else {          callback.onResponse(ExecutorCallbackCall.this, response);        }      });    }    @Override public void onFailure(Call call, final Throwable t) {      callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));    }  });}
已经知道delegate 就是 OKHttpCall,现在进入到OKHttpCall 中去找到 enqueue方法:
@Override public void enqueue(final Callback callback) {  okhttp3.Call call;  Throwable failure;      // .....       try {           // 在这里创建 OkHttp3的Call            call = rawCall = createRawCall();           } catch (Throwable t) {             throwIfFatal(t);               failure = creationFailure = t;           }  // .....  // 如果存在异常,就回调出去  if (failure != null) {    callback.onFailure(this, failure);    return;  }    // ......  // OkHttp 执行 请求  call.enqueue(new okhttp3.Callback() {    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {      Response response;      try {       // 将 response 进行处理        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      }    }  });}
其实可以看到最终的网络请求是由OkHttp3 做出的。 我们看这个方法 createRawCall :
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;}
这里的callFactory 其实就是 OkHttp3的 OkHttpClient 的实例,在Retrofit的build()中:
okhttp3.Call.Factory callFactory = this.callFactory;if (callFactory == null) {  callFactory = new OkHttpClient();}
在让我们看requestFactory,这个对象 在ServiceMethod中 就有生成:
static  ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); // .......  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}
在requestFactory的create()方法中:
okhttp3.Request create(Object[] args) throws IOException {  //......  RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,      headers, contentType, hasBody, isFormEncoded, isMultipart);  // .....  return requestBuilder.get()      .tag(Invocation.class, new Invocation(method, argumentList))      .build();}
在create最后返回的是OkHttp3的Request对象。 所以其实Retrofit中的网络请求是由OkHttp3来执行的。
4.3 关于ConverterFactory
在最开始的实现Retrofit的对象的时候:
.addConverterFactory(GsonConverterFactory.create())
在HttPServiceMethod中的parseAnnotations:
// 这个就是 获得 responseConverterConverter responseConverter =    createResponseConverter(retrofit, method, responseType);
让我们继续进入到 createResponseConverter 中:
private static  Converter createResponseConverter(
    Retrofit retrofit, Method method, Type responseType) {  Annotation[] annotations = method.getAnnotations();  try {    return retrofit.responseBodyConverter(responseType, annotations);  } catch (RuntimeException e) { // Wide exception range because factories are user code.    throw methodError(method, e, "Unable to create converter for %s", responseType);  }}
继续进入到retrofit#responseBodyConverter 中:
public  Converter responseBodyConverter(Type type, Annotation[] annotations) {  return nextResponseBodyConverter(null, type, annotations);}public  Converter nextResponseBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {//......  int start = converterFactories.indexOf(skipPast) + 1;  for (int i = start, count = converterFactories.size(); i     // 在converter对象    Converter converter =        converterFactories.get(i).responseBodyConverter(type, annotations, this);    if (converter != null) {      //noinspection unchecked      return (Converter) converter;    }  }//......}
拿GsonConverterFactory为例:
@Overridepublic Converter?> responseBodyConverter(Type type, Annotation[] annotations,    Retrofit retrofit) {  TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));   // 在这里就是返回了Converter对象  return new GsonResponseBodyConverter<>(gson, adapter);}
那么它在哪里被使用呢? 在call 执行enqueue 的时候,通过回调onResponse返回数据,在parseResponse()方法中会对数据进行处理:
Response parseResponse(okhttp3.Response rawResponse) throws IOException {  ResponseBody rawBody = rawResponse.body();    //......  ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);  try {    // 这里的responseConverter 就是 GsonResponseBodyConverter    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;  }}
在GsonResponseBodyConverter 的重写方法convert中就会对数据进行处理:
@Override public T convert(ResponseBody value) throws IOException {  JsonReader jsonReader = gson.newJsonReader(value.charStream());  try {    return adapter.read(jsonReader);  } finally {    value.close();  }}
到这里,Retrofit的分析就结束了。
总结
Retrofit的代码简单优雅,值得我们去学习,学习源码有助于我们更好的思考。 从源码中不仅仅是学习优秀的代码也是学习大神们的思想。 这里有一些优秀的博文值得学习:
  • 从架构角度看Retrofit的作用、原理和启示
  • Retrofit是如何工作的?

fbc1891f81b21d4161614f766bdc430a.png

近期精彩内容推荐:  

525bba0d2614232d197eed83a5e9eca2.png Python是一门神奇的语言! 525bba0d2614232d197eed83a5e9eca2.png  IntelliJ IDEA 的 2020 ,真的很牛皮! 525bba0d2614232d197eed83a5e9eca2.png  删库跑路真的发生,技术总监干的! 525bba0d2614232d197eed83a5e9eca2.png  2020年Java框架排行榜,谁居榜首?

a501edd44480b6a4d70477f4ebc1d189.png

e72b83baf720db99b8ee1efcbac0e905.png

在看点这里f517ea1a9a13dd389382022c649451b2.gif好文分享给更多人↓↓

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值