zoukankan      html  css  js  c++  java
  • 简单研究下Retrofit

    2015-09-24 15:36:26

    第一部分:

    1. 什么是Retrofit?

    (点击图片有惊喜)

    以上是来自官网的解释,言简意赅,咳咳,我就不翻译了~

    2. 如何使用Retrofit?

    2.1 具体的请大家参考官网的配置或者下载jar包~

        不过当前好像v2.0.0.1-Beta jar,改动很大(删除了RestAdapter,真不知道他们怎么考虑向后兼容的问题),而且还是beta版,所以我的研究都是基于1.9.0,这个版本实际使用的也比较多。需要的同学可自行下载相关的jar包和源码包,列表如下:

    jar包下载

    涉及到的jar包比较多,比如okhttp、rxjava、rxandroid等,由于Retrofit支持RxJava和RxAndroid,而且用到了OkHttp,所以一并打包。至于RxJava的功能和使用,有时间再研究吧,挺好的想法。

    2.2 如何使用Retrofit?

    第一步:创建一个interface,Retrofit将HTTP请求转换成一个interface

    public interface ApiManagerService {
        @GET("/weather")
        Observable<WeatherData> getWeather(@Query("q") String place, @Query("units") String units);
    
        @GET("/weather")
        WeatherData getWeatherBody(@Query("q") String place, @Query("units") String units);
    
        @GET("/weather")
        void getWeatherCallback(@Query("q") String place, @Query("units") String units, Callback<WeatherData> callback);
    
        @FormUrlEncoded
        @POST("/weather")
        WeatherData getWeatherField(@Field("name") String name, @Field("id") String id);
    }

    第二步:创建一个ApiManagerService的Proxy对象,同时设置请求的url前部,之所以叫“前部”,是因为这里设置的“http://api.openweathermap.org/data/2.5”+“/weather”才能形成一个完整的请求URL。此处的URL是一个国外的提供天气的URL。

    1     RestAdapter restAdapter = new RestAdapter.Builder()
    2             .setEndpoint("http://api.openweathermap.org/data/2.5")
    3             .setClient(new MyClient(new OkClient()))
    4             .build();
    5 
    6     final ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);

    第三步:调用。注意此调用是一个同步调用,在当前线程,如果是Android,那就是在UI线程,至于原因,我们后面解析。

    1 WeatherData data = apiManager.getWeatherBody("Budapest,hu", "metric");

    WeatherData.java是一个用来解析json的Object,部分代码如下:

    1 public class WeatherData {
    2     public String base;
    3     public long id;
    4     public long dt;
    5     public String name;
    6     public int cod;
    7 }

    很简单吧,我们很轻松的搞定了一个GET网络请求,并且了返回了一个我们自己想要的Object,而不是一大串的Json~

    2.3 Retrofit封装了多种网络请求和请求形式,比如:GETPOSTPUTDELETE,和各种丰富的参数形式,如:@Path、@Query、@QueryMap、@Field等。这些都比较简单,大家参考一下官网的介绍就好了。

    第二部分:

    大家是不是觉得特别神奇,反正我刚接触到这玩意的时候觉得挺神奇的~下面我们就来一点一点的扒开她的神秘面纱~

    1. 先从RestAdapter入手,大家可以发现RestAdapter是个关键。首先看看RestAdapter是怎么创建的,代码如下:

    1 RestAdapter restAdapter = new RestAdapter.Builder()
    2     .setEndpoint("http://api.openweathermap.org/data/2.5")
    3     .setClient(new MyClient(new OkClient()))
    4     .build();

    使用了Builder,可见创建RestAdapter对象需要的参数都是可选的,事实证明确实是这样,看源码:

     1 private RestAdapter(Endpoint server, Provider clientProvider, Executor httpExecutor, Executor callbackExecutor, RequestInterceptor requestInterceptor, Converter converter, Profiler profiler, ErrorHandler errorHandler, RestAdapter.Log log, RestAdapter.LogLevel logLevel) {
     2         this.serviceMethodInfoCache = new LinkedHashMap();
     3         this.server = server;
     4         this.clientProvider = clientProvider;
     5         this.httpExecutor = httpExecutor;
     6         this.callbackExecutor = callbackExecutor;
     7         this.requestInterceptor = requestInterceptor;
     8         this.converter = converter;
     9         this.profiler = profiler;
    10         this.errorHandler = errorHandler;
    11         this.log = log;
    12         this.logLevel = logLevel;
    13     }

    这是RestAdapter的私有构造器~再看看RestAdapter.Builder

     1 public RestAdapter build() {
     2             if(this.endpoint == null) {
     3                 throw new IllegalArgumentException("Endpoint may not be null.");
     4             } else {
     5                 this.ensureSaneDefaults();
     6                 return new RestAdapter(this.endpoint, this.clientProvider, this.httpExecutor, this.callbackExecutor, this.requestInterceptor, this.converter, this.profiler, this.errorHandler, this.log, this.logLevel, null);
     7             }
     8         }
     9 
    10         private void ensureSaneDefaults() {
    11             if(this.converter == null) {
    12                 this.converter = Platform.get().defaultConverter(); // 1
    13             }
    14 
    15             if(this.clientProvider == null) {
    16                 this.clientProvider = Platform.get().defaultClient(); // 2
    17             }
    18 
    19             if(this.httpExecutor == null) {
    20                 this.httpExecutor = Platform.get().defaultHttpExecutor(); // 3
    21             }
    22 
    23             if(this.callbackExecutor == null) {
    24                 this.callbackExecutor = Platform.get().defaultCallbackExecutor(); // 4
    25             }
    26 
    27             if(this.errorHandler == null) {
    28                 this.errorHandler = ErrorHandler.DEFAULT; // 5
    29             }
    30 
    31             if(this.log == null) {
    32                 this.log = Platform.get().defaultLog(); // 6
    33             }
    34 
    35             if(this.requestInterceptor == null) {
    36                 this.requestInterceptor = RequestInterceptor.NONE; // 7
    37             }
    38 
    39         }

    我只贴出来了关键部分的代码,至于那些set***()就没必要了吧~看红色部分代码,ensureSaneDefaults()方法确保每一个RestAdapter需要的参数都是初始化了的,所以创建RestAdapter的时候你可以不用set任何参数。下面我们逐个看看初始化的参数。

    首先说明一下,Retrofit在初始化这些参数的时候是区别对待Android和Base(Java)的,不同的platform有不同的实现。

    //1 初始化converter,这个就是帮你解析json的转换器,在Android和Base都使用的是自己定义的GsonConverter,其中使用了Google的Gson。

    //2 初始化clientProvider,就是执行http请求的HttpClient,Android平台如下

     1 Provider defaultClient() {
     2     final Object client;
     3     if(Platform.hasOkHttpOnClasspath()) {
     4         client = Platform.OkClientInstantiator.instantiate();
     5     } else if(VERSION.SDK_INT < 9) {
     6         client = new AndroidApacheClient();
     7     } else {
     8         client = new UrlConnectionClient();
     9     }
    10 
    11     return new Provider() {
    12         public Client get() {
    13             return (Client)client;
    14         }
    15     };
    16 }

    在这里考虑到了Android平台API Level 9前后的区别,赞一个~

    Base平台如下:

     1 Provider defaultClient() {
     2     final Object client;
     3     if(Platform.hasOkHttpOnClasspath()) {
     4         client = Platform.OkClientInstantiator.instantiate();
     5     } else {
     6         client = new UrlConnectionClient();
     7     }
     8 
     9     return new Provider() {
    10         public Client get() {
    11             return (Client)client;
    12         }
    13     };
    14 }

    所以推荐大家使用OKHttpClient

    //3 初始化httpExecutor,其实Retrofit在执行请求时,用的还是Executor,所以这里需要初始化。这个参数Android和Base平台是一样的,代码如下:

     1 Executor defaultHttpExecutor() {
     2     return Executors.newCachedThreadPool(new ThreadFactory() {
     3         public Thread newThread(final Runnable r) {
     4             return new Thread(new Runnable() {
     5                 public void run() {
     6                     Process.setThreadPriority(10);
     7                     r.run();
     8                 }
     9             }, "Retrofit-Idle");
    10         }
    11     });
    12 }

    其他的几个参数就不一一分析了,大家自己去看吧~

     2. 创建真正给我们使用的Interface对象,比如:

    1 final ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);
    2 WeatherData data = apiManager.getWeatherBody("Budapest,hu", "metric");

    有了ApiManagerService对象,我们就能调用它的方法了。现在我们顺着RestAdapter.create方法去看看,这个对象是怎么创建的,以及我们调用方法时是如何执行的~

    1 public <T> T create(Class<T> service) {
    2     Utils.validateServiceClass(service);
    3     return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
    new RestAdapter.RestHandler(this.getMethodInfoCache(service))); 4 }

    看代码,使用动态代理的方式返回了一个Proxy对象,不知道动态代理的可自行百度~动态代理最终调用方法是在InvocationHandler中,我们来看RestAdapter.RestHandler~

    到目前为止,我们知道了Retrofit是通过动态代理的方式来调用我们接口中的方法~

    3. RestAdapter.RestHandler继承自InvocationHandler,重点看它的invoke()。invoke()将会是真正调用方法的地方,Retrofit在这个方法中,做了大量的判断和解析,当然,这些判断和解析是基于RestMethodInfo,它为每一个method创建了一个RestMethodInfo,我们先看看RestMethodInfo对象是怎么创建的,里面有哪些信息。

    1 RestMethodInfo(Method method) {
    2     this.requestType = RestMethodInfo.RequestType.SIMPLE;
    3     this.method = method;
    4     this.responseType = this.parseResponseType();
    5     this.isSynchronous = this.responseType == RestMethodInfo.ResponseType.OBJECT;
    6     this.isObservable = this.responseType == RestMethodInfo.ResponseType.OBSERVABLE;
    7 }

    以上是RestMethodInfo的构造器

    requestType:代表的是请求类型,主要是用于解析和判断Annotation和请求类型,比如POST、GET亦或是FormUrlEncoded

    method:就是实际要调用的方法

    responseType:很重要,这里涉及到Retrofit定义方法的方式,代码如下:

     1 private RestMethodInfo.ResponseType parseResponseType() {
     2         Type returnType = this.method.getGenericReturnType();
     3         Type lastArgType = null;
     4         Class lastArgClass = null;
     5         Type[] parameterTypes = this.method.getGenericParameterTypes();
     6         if(parameterTypes.length > 0) {
     7             Type hasReturnType = parameterTypes[parameterTypes.length - 1];
     8             lastArgType = hasReturnType;
     9             if(hasReturnType instanceof ParameterizedType) {
    10                 hasReturnType = ((ParameterizedType)hasReturnType).getRawType();
    11             }
    12 
    13             if(hasReturnType instanceof Class) {
    14                 lastArgClass = (Class)hasReturnType;
    15             }
    16         }
    17 
    18         boolean hasReturnType1 = returnType != Void.TYPE;
    19         boolean hasCallback = lastArgClass != null && Callback.class.isAssignableFrom(lastArgClass);
    20         if(hasReturnType1 && hasCallback) {
    21             throw this.methodError("Must have return type or Callback as last argument, not both.", new Object[0]);
    22         } else if(!hasReturnType1 && !hasCallback) {
    23             throw this.methodError("Must have either a return type or Callback as last argument.", new Object[0]);
    24         } else if(hasReturnType1) {
    25             if(Platform.HAS_RX_JAVA) {
    26                 Class rawReturnType = Types.getRawType(returnType);
    27                 if(RestMethodInfo.RxSupport.isObservable(rawReturnType)) {
    28                     returnType = RestMethodInfo.RxSupport.getObservableType(returnType, rawReturnType);
    29                     this.responseObjectType = getParameterUpperBound((ParameterizedType)returnType);
    30                     return RestMethodInfo.ResponseType.OBSERVABLE;
    31                 }
    32             }
    33 
    34             this.responseObjectType = returnType;
    35             return RestMethodInfo.ResponseType.OBJECT;
    36         } else {
    37             lastArgType = Types.getSupertype(lastArgType, Types.getRawType(lastArgType), Callback.class);
    38             if(lastArgType instanceof ParameterizedType) {
    39                 this.responseObjectType = getParameterUpperBound((ParameterizedType)lastArgType);
    40                 return RestMethodInfo.ResponseType.VOID;
    41             } else {
    42                 throw this.methodError("Last parameter must be of type Callback<X> or Callback<? super X>.", new Object[0]);
    43             }
    44         }
    45     }

    分解如下:

    :1. 如果定义的方法有返回值,并且最后一个参数是Callback,那么该方法错误

    :2. 如果定义的方法没有返回值,并且最后一个参数不是Callback,那么该犯方法错误

    :3. 如果只有返回值,会判断返回值是否是Observable<WeatherData>,如果是,那么responseType是OBSERVABLE,否则是OBJECT

    :4. 其他的都是没有返回值,但是有Callback的,responseType是VOID

    isSynchronous:(this.responseType == RestMethodInfo.ResponseType.OBJECT),表示该方法是否是同步的,如果是同步的,则在当前线程调用,否则,异步调用。根据responseType的判断,我们发现:只有有返回值且返回值不是Observable类型的方法,是同步调用的。其他的都是异步调用。还记得前面提到过apiManager.getWeatherBody("Budapest,hu", "metric")是同步调用的吗?原因就在这里。

    isObservable:只有返回值是Observable的方法才是,这个参数有特殊的用途,所以是一个独立的参数。

    4. 真正分析invoke()方法

     1     public Object invoke(Object proxy, Method method, final Object[] args) throws Throwable {
     2         if(method.getDeclaringClass() == Object.class) {
     3             return method.invoke(this, args); //忽略
     4         } else {
     5             final RestMethodInfo methodInfo = RestAdapter.getMethodInfo(this.methodDetailsCache, method);
     6             if(methodInfo.isSynchronous) {
     7                 try {
     8                     return this.invokeRequest(RestAdapter.this.requestInterceptor, methodInfo, args);
     9                 } catch (RetrofitError var7) {
    10                 }
    11             } else if(RestAdapter.this.httpExecutor != null && RestAdapter.this.callbackExecutor != null) {
    12                 if(methodInfo.isObservable) {
    13                     if(RestAdapter.this.rxSupport == null) {
    14                         if(!Platform.HAS_RX_JAVA) {
    15                             throw new IllegalStateException("Observable method found but no RxJava on classpath.");
    16                         }
    17 
    18                         RestAdapter.this.rxSupport = new RxSupport(RestAdapter.this.httpExecutor, RestAdapter.this.errorHandler, RestAdapter.this.requestInterceptor);
    19                     }
    20 
    21                     return RestAdapter.this.rxSupport.createRequestObservable(new RxSupport.Invoker() {
    22                         public ResponseWrapper invoke(RequestInterceptor requestInterceptor) {
    23                             return (ResponseWrapper)RestHandler.this.invokeRequest(requestInterceptor, methodInfo, args);
    24                         }
    25                     });
    26                 } else {
    27                     final RequestInterceptorTape interceptorTape = new RequestInterceptorTape();
    28                     RestAdapter.this.requestInterceptor.intercept(interceptorTape);
    29                     final Callback callback = (Callback)args[args.length - 1];
    30                     RestAdapter.this.httpExecutor.execute(new CallbackRunnable(callback, RestAdapter.this.callbackExecutor, RestAdapter.this.errorHandler) {
    31                         public ResponseWrapper obtainResponse() {
    32                             return (ResponseWrapper)RestHandler.this.invokeRequest(interceptorTape, methodInfo, args);
    33                         }
    34                     });
    35                     return null;
    36                 }
    37             } else {
    38                 throw new IllegalStateException("Asynchronous invocation requires calling setExecutors.");
    39             }
    40         }
    41     }

    根据得到的RestMethodInfo:

    1. 如果methodInfo.isSynchronous为true,那么invokeRequest,这个方法中调用this.clientProvider.get().execute(request)在当前线程

    2. 如果需要异步调用,那么判断是不是Observable,

    如果是:

        判断平台是否支持RxJava环境,如果不支持,直接异常,如果支持,利用RxJava,由httpExecutor来执行。

    如果不是:

        那就是说,该方法有Callback,同样由httpExecutor执行,当然了,结果在Callback中返回,Callback方法在callbackExecutor中执行。如果是Android,那么Callback就是在UI线程。如果是Base,那个线程调用,在哪个线程中执行。

  • 相关阅读:
    如果因特网中的所有链路都提供可靠的交付服务,TCP可靠传输服务是多余的吗?
    编译运行java程序出现Exception in thread "main" java.lang.UnsupportedClassVersionError: M : Unsupported major.minor version 51.0
    chrome浏览器插件的开启快捷键
    sqlzoo练习题答案
    2019Falg
    python绘图踩的坑
    精益数据分析--测试分析
    np.random的随机数函数
    numpy中文件的存储和读取-嵩天老师笔记
    喜欢的话
  • 原文地址:https://www.cnblogs.com/wlrhnh/p/4835596.html
Copyright © 2011-2022 走看看