【笔记】Retrofit的使用以及原理

1. 实例

完整请求地址

http://apis.juhe.cn/simpleWeather/query?key=**
//key可以到聚合数据申请

返回数据

/**
* reason : 查询成功!
* result : {“city”:“武汉”,“realtime”:{“temperature”:“28”,“humidity”:“82”,“info”:“阴”,“wid”:“02”,“direct”:“东北风”,“power”:“1级”,“aqi”:“35”},“future”:[{“date”:“2020-07-17”,“temperature”:“24/32℃”,“weather”:“小雨转中雨”,“wid”:{“day”:“07”,“night”:“08”},“direct”:“西南风转东北风”},{“date”:“2020-07-18”,“temperature”:“23/32℃”,“weather”:“小雨转暴雨”,“wid”:{“day”:“07”,“night”:“10”},“direct”:“西南风转北风”},{“date”:“2020-07-19”,“temperature”:“21/25℃”,“weather”:“大雨转中雨”,“wid”:{“day”:“09”,“night”:“08”},“direct”:“北风转东北风”},{“date”:“2020-07-20”,“temperature”:“23/28℃”,“weather”:“大雨转小雨”,“wid”:{“day”:“09”,“night”:“07”},“direct”:“南风转西南风”},{“date”:“2020-07-21”,“temperature”:“25/33℃”,“weather”:“多云转阴”,“wid”:{“day”:“01”,“night”:“02”},“direct”:“南风”}]}
* error_code : 0
*/

1.定义请求接口

public interface Api {
   @GET("simpleWeather/query?key=4547344eb4def925ed40ac5d067dcab0")
   Call<WeatherBean> getWeather(@Query("city") String city);
}

2.请求数据

  private void requestData(String city) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://apis.juhe.cn/")   //baseUrl+接口中的url为完成的请求地址
                .addConverterFactory(GsonConverterFactory.create())//设置gson解析
                .build();
        Api api = retrofit.create(Api.class);
        Call<WeatherBean> data = api.getWeather(city);

        data.enqueue(new Callback<WeatherBean>() {
            @Override
            public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
                WeatherBean weatherBean = response.body();
                if (weatherBean.getError_code() == 0) {
                //可以直接在response中操作ui
                    tv.setText(weatherBean.getResult().getCity() + "天气情况:\n" + "天气详情:" + weatherBean.getResult().getRealtime().toString());
                } else {
                    tv.setText("没有查询到");
                }
            }
            
            @Override
            public void onFailure(Call<WeatherBean> call, Throwable t) {
                tv.setText("请求错误");
                Log.e(TAG, "onFailure: " + t.getMessage());
            }
        });
    }

3.效果

【笔记】Retrofit的使用以及原理_第1张图片

2.注解说明

- 网络请求

  • @GET
  • @POST
  • @PUT
  • @DELETE
  • @PATH
  • @HEAD
  • @OPTIONS
  • @HTTP

-标记

  • @FromUrlEncoded 表示请求的是表单 每个键值对用 @Field注解键名
  • @Multipart 表示请求是一个支持文件上传的Form表单
  • @Streaming 表示数据以流的形式返回

3.请求参数

  • @Headers 请求头
  • @Header 不固定值的请求头
  • @Body 非表单请求体
  • @Field @FieldMap 向表单提交参数
  • @Query @QueryMap 用于表单字段
  • @ Url @Path 用于Url的缺省值

4.与RxJava结合使用

public interface Api {
    @GET("simpleWeather/query?key=4547344eb4def925ed40ac5d067dcab0")
    Observable<WeatherBean> getWeather(@Query("city") String city);
}

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://apis.juhe.cn/")
                .addConverterFactory(GsonConverterFactory.create())//使用Gson解析
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        Api api = retrofit.create(Api.class);
        Observable<WeatherBean> data = api.getWeather(city);
        data.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<WeatherBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    
                    }

                    @Override
                    public void onNext(WeatherBean weatherBean) {
                        if (weatherBean.getError_code() == 0) {
                            tv.setText(weatherBean.getResult().getCity() + "天气情况:\n" + "天气详情:" + weatherBean.getResult().getRealtime().toString());
                            Log.e(TAG, "onResponse: " + weatherBean.getResult().getCity());
                        } else {
                            tv.setText("没有查询到");
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                    //请求失败
                    }

                    @Override
                    public void onComplete() {
                    //请求成功
                    }
                });

5.项目中使用

(略)

6.Retrofit原理

  • 使用建造者模式创建retrofit对象
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://apis.juhe.cn/")
                .addConverterFactory(GsonConverterFactory.create())//使用Gson解析
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
  • 初始化retrofit使用到了一个链式调用的设计
    首先看Builder()
public Builder() {
      this(Platform.get());
    }
    
   //Platform.get()  这里使用一个单例返回了Platform实例
    private static final Platform PLATFORM = findPlatform();
   static Platform get() {
    return PLATFORM;
  }
  • 然后看看==findPlatform()==中的处理
  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

由于retrofit同时支持Android、ios和java平台,所以在这里应该是对平台的判断

  • 顺着调用链再来看 baseUrl(url) 的源码
    public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }
    
        public Builder baseUrl(HttpUrl baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

对传入的URL进行校验,生成httpUrl对象,然后赋值给baseUrl

在Builder()的构造方法里对各种属性进行了初始化,初始化完成后调用build方法构建Retrofit对象,此时将初始化的属性值又传给了Retrofit的构造方法。

 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
       //callFactory就是一个okhttpClient,可见Retrofit的网络请求是通过OkhttpClient的
      okhttp3.Call.Factory callFactory = this.callFactory;                    
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }
  • 下一步进入 addConverterFactory() 方法
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

这里将 GsonConverterFactory.create() 创建的GsonConverterFactory对象加入了converterFactorieslist中,后面会说明

  • 然后是 addCallAdapterFactory() 方法
   private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); 
   public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

RxJava2CallAdapterFactory.create() 创建的RxJava2CallAdapterFactory对象加入adapterFactories数组中

  • 最后来看看创建retrofit对象的最后一步 build()
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

这一步进行了很多参数校验的工作,首先判断baseUrl不能为空否则抛出异常,然后callFactory就是okhttp的工厂实例,

      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      
       List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

如果我们不指定CallAdapterFactory也就是不传入RxJava的callAdapter的话,会向adapterFactories数组中添加一个defaultCallAdapterFactory,也就是我们如果不指定retrofit请求数据方法的返回值类型,默认的返回值类型就是Call。而数据解析是没有默认值的。

  • 下一步是通过 creat()方法 生成接口类的代理对象
 Api api = retrofit.create(Api.class);

来看create()方法:
通过Proxy.newProxyInstance为传入的service接口创建代理对象,代理对象调用函数的时候,会调用动态代理的==invoke()==函数

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);//验证是否传入的为接口类
    if (validateEagerly) {//提前创建,默认为false,这里跳过
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // 方法定义所在的类,这里是定义在接口里面,返回false
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //platform.isDefaultMethod不做处理,返回false
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

这里使用到了动态代理,构建一个 ServiceMethod 对象和 OkHttpCall 对象,并调用 serviceMethod.adapt(okHttpCall) 方法将二者绑定。在这里的adapt方法,当初始化retrofit没有使用addCallAdapterFactory的时候使用的是默认的DefaultCallAdapterFactory

@Override public Call<Object> adapt(Call<Object> call) {
      return call;
    }

也就是默认的返回值类型是Call类型

  • 然后我们返回上一步看看是如何将返回结果转化成Observable对象的

在创建 RxJava2CallAdapter

 public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
 Class<?> rawType = getRawType(returnType);
 if (rawType == Completable.class) {
   // Completable is not parameterized (which is what the rest of this method deals with) so it
   // can only be created with a single configuration.
   return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
       false, true);
 }
 ...

 Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
 Class<?> rawObservableType = getRawType(observableType);
 if (rawObservableType == Response.class) {
   ...
   responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
 } else if (rawObservableType == Result.class) {
   ...
   responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
   isResult = true;
 } else {
   responseType = observableType;
   isBody = true;
 }
 return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
     isSingle, isMaybe, false);
}

在RaJava2CallAdapter中:

@Override public Object adapt(Call<R> call) {
//通过RxJava的订阅来发起请求的执行,在CallEnqueueObservable和CallExecuteObservable中dispose方法中调用了call.cancel(), 因此只要取消了RxJava的订阅就直接取消了okhttp的请求。
 Observable<Response<R>> responseObservable = isAsync
     ? new CallEnqueueObservable<>(call)
     : new CallExecuteObservable<>(call);

//对结果处理,observable就是最后返回的对象
 Observable<?> observable;
 if (isResult) {
   //Observable> 类型的返回, Result持有OkHttp的Response
   observable = new ResultObservable<>(responseObservable);
 } else if (isBody) {
   //Observable 类型的返回
   observable = new BodyObservable<>(responseObservable);
 } else {
   observable = responseObservable;
 }
 if (scheduler != null) {
   observable = observable.subscribeOn(scheduler);
 }
 //Observable转化成其他的可订阅对象
 if (isFlowable) {
   return observable.toFlowable(BackpressureStrategy.LATEST);
 }
 if (isSingle) {
   return observable.singleOrError();
 }
 if (isMaybe) {
   return observable.singleElement();
 }
 if (isCompletable) {
   return observable.ignoreElements();
 }
 return observable;
}

最终返回的就是observable对象

  • 然后我们继续返回去看 ServiceMethod 对象的创建
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>)loadServiceMethod(method);

进入 loadServiceMethod(method) 方法:

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;
 }

serviceMethodCache中取 ServiceMethod 对象,如果没有,则构建 ServiceMethod 对象,然后放进去serviceMethodCache中,serviceMethodCache是一个HashMap:

private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();

继续看 new ServiceMethod.Builder<>(this, method).build(); 首先看看Builder()

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();
     responseType = callAdapter.responseType();
     responseConverter = createResponseConverter();

     for (Annotation annotation : methodAnnotations) {
       parseMethodAnnotation(annotation);
     }

     if (httpMethod == null) {
       throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
     }

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

首先获取了callAdapterresponseTyperesponseConverter三个对象,然后用for循环去遍历方法中的注解并解析。

     for (Annotation annotation : methodAnnotations) {
       parseMethodAnnotation(annotation);
     }
     
     private void parseMethodAnnotation(Annotation annotation) {
     if (annotation instanceof DELETE) {
       parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
     } else if (annotation instanceof GET) {
       parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
     } 

       ....

解析完方法的注解后,然后解析方法参数的注解数组,首先实例化了一个数组

parameterHandlers = new ParameterHandler<?>[parameterCount];

然后遍历取出参数的类型 和参数的注解 ,再把参数类型,参数注解都放在一起解析,解析的结果放入上面初始化的数组中

Type parameterType = parameterTypes[p];

Annotation[] parameterAnnotations = parameterAnnotationsArray[p];

parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);

然后看看这个方法中做了什么:

private ParameterHandler<?> parseParameter(int p, Type parameterType, Annotation[] annotations) {
      ParameterHandler<?> result = null;
      for (Annotation annotation : annotations) {
        ParameterHandler<?> annotationAction = parseParameterAnnotation(
            p, parameterType, annotations, annotation);
      }
   }

遍历解析参数注解,得到一个ParameterHandler对象。
然后进入 parseParameterAnnotation(
p, parameterType, annotations, annotation);
这个方法中是对参数注解的判断,然后会进入这个方法:

  public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    for (int i = 0, count = converterFactories.size(); i < count; i++) {
      Converter<?, String> converter =
          converterFactories.get(i).stringConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<T, String>) converter;
      }
    }

    return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
  }

返回一个 BuiltInConverters.ToStringConverter.INSTANCE,然后回到上面的parseParameterAnnotation
最后会返回:

 return new ParameterHandler.Path<>(name, converter, path.encoded());

返回一个Path对象,并用上面的参数为它初始化。

关键流程

【笔记】Retrofit的使用以及原理_第2张图片

你可能感兴趣的:(Android,java,android)