retrofit的实现原理(三)

前面基本的原理和流程已经弄清了.再研究下某些实现.

CallbackRunnable(异步模式时在子线程执行的部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
abstract  class  CallbackRunnable<T>  implements  Runnable {
   private  final  Callback<T> callback;
   private  final  Executor callbackExecutor;
   private  final  ErrorHandler errorHandler;
 
   CallbackRunnable(Callback<T> callback, Executor callbackExecutor, ErrorHandler errorHandler) {
     this .callback = callback;
     this .callbackExecutor = callbackExecutor;
     this .errorHandler = errorHandler;
   }
 
   @SuppressWarnings ( "unchecked" )
   @Override  public  final  void  run() {             //在异步线程中实际执行的方法.
     try  {
       final  ResponseWrapper wrapper = obtainResponse();  
       callbackExecutor.execute( new  Runnable() {
         @Override  public  void  run() {
           callback.success((T) wrapper.responseBody, wrapper.response);    //在主线程执行.
         }
       });
     catch  (RetrofitError e) {
       Throwable cause = errorHandler.handleError(e);      //这里的异常捕捉到了以后没有再次抛出,内部处理了.
       final  RetrofitError handled = cause == e ? e : unexpectedError(e.getUrl(), cause);
       callbackExecutor.execute( new  Runnable() {
         @Override  public  void  run() {
           callback.failure(handled);                                //在主线程执行.
         }
       });
     }
   }
 
   public  abstract  ResponseWrapper obtainResponse();  //交给子类实现--->其实就是执行的前面的invokeRequest().
}

ResponseWrapper封装了response和responseBody.因为方法的返回值只能是一个.所以用它包装了下.

1
2
3
4
5
6
7
8
9
final  class  ResponseWrapper {
   final  Response response;
   final  Object responseBody;
 
   ResponseWrapper(Response response, Object responseBody) {
     this .response = response;
     this .responseBody = responseBody;
   }
}

Retrofit的Client是真正进行网络访问的逻辑.来看下具体的实现.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public  interface  Client {
   /**
    * Synchronously execute an HTTP represented by {@code request} and encapsulate all response data
    * into a {@link Response} instance.
    * <p>
    * Note: If the request has a body, its length and mime type will have already been added to the
    * header list as {@code Content-Length} and {@code Content-Type}, respectively. Do NOT alter
    * these values as they might have been set as a result of an application-level configuration.
    */
   Response execute(Request request)  throws  IOException;   //抽象方法,就是给定一个Request,执行完,返回一个Response.
 
   /**
    * Deferred means of obtaining a {@link Client}. For asynchronous requests this will always be
    * called on a background thread.
    */
   interface  Provider {
     /** Obtain an HTTP client. Called once for each request. */
     Client get();
   }
}

OkClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public  class  OkClient  implements  Client {
   private  static  OkHttpClient generateDefaultOkHttp() {
     OkHttpClient client =  new  OkHttpClient();
     client.setConnectTimeout(Defaults.CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
     client.setReadTimeout(Defaults.READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
     return  client;
   }
 
   private  final  OkHttpClient client;
 
   public  OkClient() {
     this (generateDefaultOkHttp());
   }
 
   public  OkClient(OkHttpClient client) {
     if  (client ==  null throw  new  NullPointerException( "client == null" );
     this .client = client;
   }
 
   @Override  public  Response execute(Request request)  throws  IOException {
     return  parseResponse(client.newCall(createRequest(request)).execute());   //client.newCall().execute() 真正利用okHttp进行网络访问的地方.可以看到是采用的Okhttp的同步的方式.
   }
 
   static  com.squareup.okhttp.Request createRequest(Request request) {   //把retrofit的Request中url,header等信息提取出来, 封装进okhttp的Request中.
     com.squareup.okhttp.Request.Builder builder =  new  com.squareup.okhttp.Request.Builder()
         .url(request.getUrl())
         .method(request.getMethod(), createRequestBody(request.getBody()));
 
     List<Header> headers = request.getHeaders();
     for  ( int  i =  0 , size = headers.size(); i < size; i++) {
       Header header = headers.get(i);
       String value = header.getValue();
       if  (value ==  null ) value =  "" ;
       builder.addHeader(header.getName(), value);
     }
 
     return  builder.build();
   }
 
   static  Response parseResponse(com.squareup.okhttp.Response response) {
     return  new  Response(response.request().urlString(), response.code(), response.message(),
         createHeaders(response.headers()), createResponseBody(response.body()));
   }
 
   private  static  RequestBody createRequestBody( final  TypedOutput body) {
     if  (body ==  null ) {
       return  null ;
     }
     final  MediaType mediaType = MediaType.parse(body.mimeType());   //解析Response的类型.
     return  new  RequestBody() {
       @Override  public  MediaType contentType() {
         return  mediaType;
       }
 
       @Override  public  void  writeTo(BufferedSink sink)  throws  IOException {
         body.writeTo(sink.outputStream());
       }
 
       @Override  public  long  contentLength() {
         return  body.length();
       }
     };
   }
 
   private  static  TypedInput createResponseBody( final  ResponseBody body) {
     if  (body.contentLength() ==  0 ) {
       return  null ;
     }
     return  new  TypedInput() {
       @Override  public  String mimeType() {
         MediaType mediaType = body.contentType();
         return  mediaType ==  null  null  : mediaType.toString();
       }
 
       @Override  public  long  length() {
         return  body.contentLength();
       }
 
       @Override  public  InputStream in()  throws  IOException {
         return  body.byteStream();
       }
     };
   }
 
   private  static  List<Header> createHeaders(Headers headers) {
     int  size = headers.size();
     List<Header> headerList =  new  ArrayList<Header>(size);
     for  ( int  i =  0 ; i < size; i++) {
       headerList.add( new  Header(headers.name(i), headers.value(i)));
     }
     return  headerList;
   }
}

 

retrofit的大体流程.

  用户自定义配置项的设置(如client,converter,拦截器等)--->解析接口的方法(如果曾经解析过就从缓存中获取),确定http访问的url,header,method等,确定是异步还是同步的方式------>使用具体的Client进行网络访问,并将数据封装到Response---->执行Converter的逻辑(有可能不用执行),把Response数据转换为一个具体对象.--->根据同步或者异步的方式,执行方法或者callBack的逻辑.

 

retrofit框架的需要注意的几个小点.

  1.为什么同步方式不像正常的方式一样要求用户try_catch来提醒用户捕捉异常?

  通过上面的逻辑可以看到,真正进行网络访问,converter转换的逻辑都在invokeHandler.invoke()方法执行的时候执行. 而这个方法的调用是在 用户自定义接口调用接口方法的时候执行的.(不明白的可以看下动态代理的原理).而用户自定义的接口方法是没有抛出异常的.在java中,如果父类方法没有抛出异常,子类方法也不能显示的抛出异常.(子类方法只能抛出父类方法抛出异常或其子类).所以Retrofit就不能抛出各种异常(如IO异常). 并且要抓住异常后转换为RuntimeException抛出.(动态代理生成的接口的实现类其实内部也采用了同样的方法.)

  异常抓住后不能直接内部处理,应该提醒用户代码执行的时候出了问题,所以必须抓住异常后再次抛出.而对于CallBack的方式,因为有failure()方法提示用户代码逻辑出了问题,所以就不用re-throw异常了.

  2.关于 InvocationHandler的invoke()方法, 这个方法有个返回值. 那这个返回值返回的是什么呢?

  首先明确Method.invoke(Object receiver,Object.. args)是和 receiver.method(args)等价的,2个方法的返回值是一样的.

1
2
public  Object invoke(Object receiver, Object... args)  这里的Object是方法执行的的返回值.
---> Returns the result of dynamically invoking  this  method. Equivalent to { @code  receiver.methodName(arg1, arg2, ... , argN)}.

  动态代理生成了接口A的代理类B,B的同名方法内部其实调用的是invocationHandler的 invoke()方法.返回的也是invoke方法的返回值. 所以invoke返回的类型就应该和接口方法的返回值类型一样.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值