-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
724 lines (331 loc) · 40.5 KB
/
index.html
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
<!doctype html>
<html class="theme-next pisces use-motion">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/vendors/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
<link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link href="/vendors/font-awesome/css/font-awesome.min.css?v=4.4.0" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=5.0.1" rel="stylesheet" type="text/css" />
<meta name="keywords" content="Hexo, NexT" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.0.1" />
<meta name="description" content="一分耕耘,一份收获">
<meta property="og:type" content="website">
<meta property="og:title" content="小白成长记">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="小白成长记">
<meta property="og:description" content="一分耕耘,一份收获">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="小白成长记">
<meta name="twitter:description" content="一分耕耘,一份收获">
<script type="text/javascript" id="hexo.configuration">
var NexT = window.NexT || {};
var CONFIG = {
scheme: 'Pisces',
sidebar: {"position":"left","display":"post"},
fancybox: true,
motion: true,
duoshuo: {
userId: 0,
author: '博主'
}
};
</script>
<link rel="canonical" href="http://yoursite.com/"/>
<title> 小白成长记 </title>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container one-collumn sidebar-position-left
page-home
">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">小白成长记</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle"></p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />
首页
</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br />
分类
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
归档
</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about" rel="section">
<i class="menu-item-icon fa fa-fw fa-user"></i> <br />
关于
</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/01/13/Retrofit-源码解析初次尝试/" itemprop="url">
Retrofit 源码解析初次尝试
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2017-01-13T19:11:59+08:00" content="2017-01-13">
2017-01-13
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="Retrofit-源码解析的初次尝试"><a href="#Retrofit-源码解析的初次尝试" class="headerlink" title="Retrofit 源码解析的初次尝试"></a>Retrofit 源码解析的初次尝试</h3><p><img src="http://ww4.sinaimg.cn/large/006tNbRwgw1f75954laycj30qo0k0aas.jpg" alt="enter image description here"></p>
<hr>
<h4 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h4><ul>
<li>Retrofit 简介</li>
<li>Retrofit 的具体使用</li>
<li>重点分析</li>
</ul>
<hr>
<h5 id="Retrofit-简介"><a href="#Retrofit-简介" class="headerlink" title="Retrofit 简介"></a>Retrofit 简介</h5><p>Retrofit 是 Square 推出的 HTTP 框架,主要用于 Android 和 Java。Retrofit 将网络请求变成方法的调用,使用起来非常简洁方便。</p>
<blockquote>
<ul>
<li>Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to</li>
<li>define how requests are made. Create instances using {@linkplain Builder</li>
<li>the builder} and pass your interface to {@link #create} to generate an implementation.</li>
</ul>
</blockquote>
<p>这是源码开头的解释,大致意思是 Retrofit 利用方法上的注解接口转化成一个 HTTP 请求。</p>
<hr>
<h5 id="Retrofit-的使用"><a href="#Retrofit-的使用" class="headerlink" title="Retrofit 的使用"></a>Retrofit 的使用</h5><ol>
<li><p>首先建立API接口类:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">public interface ZhihuApi {</div><div class="line"> String HOST = "http://news-at.zhihu.com/api/";</div><div class="line"> @GET("4/news/latest")</div><div class="line"> Call<ZhihuList> getZhihuListNews(int page);</div><div class="line">}</div></pre></td></tr></table></figure>
</li>
<li><p>具体使用过程:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">// 创建 Retrofit 实例</div><div class="line">Retrofit retrofit = new Retrofit.Builder()</div><div class="line"> .baseUrl(ZhihuApi.HOST)</div><div class="line"> .addConverterFactory(GsonConverterFactory.create())</div><div class="line"> .build();</div><div class="line"></div><div class="line">// 生成接口实现类</div><div class="line">ZhihuApi zhihuApi = retrofit.create(ZhihuApi.class);</div><div class="line"></div><div class="line">// 调用接口定义的请求方法,并且返回 Call 对象</div><div class="line">Call<ZhihuList> call = zhihuApi .getZhihuListNews(1);</div><div class="line"></div><div class="line">// 调用 Call 对象的异步执行方法</div><div class="line">call.enqueue(Callback callback)</div></pre></td></tr></table></figure>
</li>
</ol>
<blockquote>
<p>以上就是 Retrofit 的基础用法,注意这里的 <code>addConverterFactory()</code> 方法,它是用于吧返回的 http response 转换成 Java 对象,对应方法的返回值就是 <code>ZhihuList</code> 这个自定义的类。大致流程就是获得 <code>retrofit</code> 对象之后,接着调用 <code>create()</code>方法创建 ZhihuApi 的实例,然后调用 ZhihuApi 的方法请求网络,返回的是一个 <code>Call</code>对象,然后就可以使用 <code>Call</code> 方法的 <code>enqueue</code> 或者 <code>execute</code> 来执行发起请求,<code>enqueue</code> 是是异步执行,而 <code>execute</code>是同步执行。</p>
</blockquote>
<hr>
<h5 id="Retrofit-的重点解析"><a href="#Retrofit-的重点解析" class="headerlink" title="Retrofit 的重点解析"></a>Retrofit 的重点解析</h5><ol>
<li>Retrofit 的创建( Builder 模式)<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">// 用于缓存解析出来的方法</div><div class="line"> private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();</div><div class="line"> // 请求网络的 OKHttp 的工厂,默认是 OkHttpClient</div><div class="line"> private final okhttp3.Call.Factory callFactory;</div><div class="line"> // baseurl</div><div class="line"> private final HttpUrl baseUrl;</div><div class="line"> // 请求网络得到的 response 的转换器的集合 默认会加入 BuiltInConverters </div><div class="line"> private final List<Converter.Factory> converterFactories;</div><div class="line"> // 把 Call 对象转换成其它类型,如 Call 以及 Observer</div><div class="line"> private final List<CallAdapter.Factory> adapterFactories;</div><div class="line"> // 用于执行回调 Android 中默认是 MainThreadExecutor</div><div class="line"> private final Executor callbackExecutor;</div><div class="line"> // 是否需要立即解析接口中的方法</div><div class="line"> private final boolean validateEagerly;</div></pre></td></tr></table></figure>
</li>
</ol>
<p>以上是几个 <code>Retrofit</code> 中比较关键的变量,每个都有注释,一看便知。接下来看一看 内部类 <code>Builder</code>的 <code>build()</code>方法:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line">public Retrofit build() {</div><div class="line"> if (baseUrl == null) {</div><div class="line"> throw new IllegalStateException("Base URL required.");</div><div class="line"> }</div><div class="line"></div><div class="line"> okhttp3.Call.Factory callFactory = this.callFactory;</div><div class="line"> if (callFactory == null) {</div><div class="line"> // 默认创建一个 OkHttpClient</div><div class="line"> callFactory = new OkHttpClient();</div><div class="line"> }</div><div class="line"></div><div class="line"> Executor callbackExecutor = this.callbackExecutor;</div><div class="line"> if (callbackExecutor == null) {</div><div class="line"> // Android 中返回的是 MainThreadExecutor</div><div class="line"> callbackExecutor = platform.defaultCallbackExecutor();</div><div class="line"> }</div><div class="line"></div><div class="line"> // Make a defensive copy of the adapters and add the default Call adapter.</div><div class="line"> //adapterFactories 把 Call 对象转换成其他对象,如 Observer</div><div class="line"> List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);</div><div class="line"> adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));</div><div class="line"></div><div class="line"> // Make a defensive copy of the converters.</div><div class="line"> // 请求网络得到的 response 的转换器的集合</div><div class="line"> List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);</div><div class="line"></div><div class="line"> return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,</div><div class="line"> callbackExecutor, validateEagerly);</div><div class="line"> }</div><div class="line"> }</div></pre></td></tr></table></figure></p>
<p>以上代码可以看出:<code>callAdapter</code> 是请求返回的对象,<code>Converter</code> 是转换器,转换请求的响应到对应的实体对象,<code>OkHttpClient</code> 是具体的 OkHttp 的请求客户端,在创建 Retrofit 的时候,如果没有指定 <code>OkHttpClient</code>,会创建一个默认的。如果没有指定 <code>callbackExecutor</code>,会返回平台默认的,在 Android 中是 <code>MainThreadExecutor</code>,并利用这个构建一个 <code>CallAdapter</code> 加入 <code>adapterFactories</code>。</p>
<ol>
<li><p>Create() 方法</p>
<p>有了 Retrofit 对象后,便可以通过 <code>create()</code> 方法创建网络请求接口类的对象。直接上代码:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line">public <T> T create(final Class<T> service) {</div><div class="line"> // 检查传入的类是否为接口并且无继承</div><div class="line"> Utils.validateServiceInterface(service);</div><div class="line"> if (validateEagerly) {</div><div class="line"> // 提前解析方法</div><div class="line"> eagerlyValidateMethods(service);</div><div class="line"> }</div><div class="line"> // 重点是这里</div><div class="line"> // 首先会返回一个利用代理实现的 ZhihuApi 对象</div><div class="line"> return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },</div><div class="line"> new InvocationHandler() {</div><div class="line"> private final Platform platform = Platform.get();</div><div class="line"></div><div class="line"> @Override public Object invoke(Object proxy, Method method, Object... args)</div><div class="line"> throws Throwable {</div><div class="line"> // If the method is a method from Object then defer to normal invocation.</div><div class="line"> if (method.getDeclaringClass() == Object.class) {</div><div class="line"> return method.invoke(this, args);</div><div class="line"> }</div><div class="line"> // 为了兼容 Java8 平台,Android 中不会执行</div><div class="line"> if (platform.isDefaultMethod(method)) {</div><div class="line"> return platform.invokeDefaultMethod(method, service, proxy, args);</div><div class="line"> }</div><div class="line"></div><div class="line"> // 解析方法 这里用到了注解(Runtime)</div><div class="line"> ServiceMethod serviceMethod = loadServiceMethod(method);</div><div class="line"> // 将刚刚解析完毕包装后的具体方法封装成 OkHttpCall ,你可以在该实现类找到 okhttp 请求所需要的参数</div><div class="line"> // 所以它是用来跟 okhttp 对接的。</div><div class="line"> OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);</div><div class="line"> // 将以上我们封装好的 call 返回给上层,这个时候我们就可以执行 call 的同步方法或者异步进行请求。</div><div class="line"> return serviceMethod.callAdapter.adapt(okHttpCall);</div><div class="line"> }</div><div class="line"> });</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>这里使用的是 <strong>动态代理模式</strong> ,简单的描述就是<code>Proxy.newProxyInstance</code> 根据传进来的 Class 对象生成了代理类,当这个代理类执行某个方法时总是会调用 <code>InvocationHandler</code>(Proxy.newProxyInstance 中的第三个参数) 的<code>invoke</code>方法,在这个方法中可以执行一些操作(这里是解析方法的注解参数等),通过这个方法真正的执行我们编写的接口中的网络请求。我们再来理一下思路:<br><code>Create()</code> –><br><code>return (T) Proxy.newProxyInstance(...){...}</code>–><br><code>Call<ZhihuList> call = zhihuApi .getZhihuListNews(1);</code>–><br><code>public Object invoke(...){...}</code>调用代理类的<code>invoke()</code> 。<br>记住动态代理,是在方法调用时才会真正的触发过程。</p>
</li>
<li><p>ServiceMethod</p>
<p>下面看一下在 <code>invoke</code> 中解析网络请求方法的几行,<code>ServiceMethod serviceMethod = loadServiceMethod(method);</code>代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">ServiceMethod loadServiceMethod(Method method) {</div><div class="line"> ServiceMethod result;</div><div class="line"> synchronized (serviceMethodCache) {</div><div class="line"> // 从缓存中获取该方法</div><div class="line"> result = serviceMethodCache.get(method);</div><div class="line"> if (result == null) {</div><div class="line"> // 为空就创建并且加入缓存</div><div class="line"> result = new ServiceMethod.Builder(this, method).build();</div><div class="line"> serviceMethodCache.put(method, result);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> return result;</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>Retrofit 有一个双链表用来缓存方法<br><code>private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();</code>避免一个网络请求在多次调用的时候频繁的解析注解,毕竟注解解析过程消耗比较大。</p>
<p>这个部分重点在<code>ServiceMethod.Builder(this, method).build();</code></p>
<p><code>build()</code>源码很长,只截取重点:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"> // 用来发送请求的 client</div><div class="line">callAdapter = createCallAdapter();</div><div class="line">...</div><div class="line">// 结果的转换器(Gson,FastJson …)之类</div><div class="line">responseConverter = createResponseConverter();</div><div class="line"></div><div class="line">// 遍历解析注解</div><div class="line">for (Annotation annotation : methodAnnotations) {</div><div class="line"> parseMethodAnnotation(annotation);</div><div class="line">}</div><div class="line">...省略代码</div></pre></td></tr></table></figure>
</li>
<li><p>OkHttpCall</p>
<p>在得到 <code>ServiceMethod</code> 对象后,把它连同方法调用的相关参数传给了 <code>OkHttpCall</code> 对象,就是前面的这行代码:<br><code>OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);</code></p>
<blockquote>
<p>这个OkHttpCall才是真正OkHttp请求的回调,但是针对我们使用的不同的回调,比如:RxJava的Observable、Call,所以有一层转换的关系,把OkHttpCall转成对应的Observable和Call。就是serviceMethod.callAdapter.adapt(okHttpCall)的工作。</p>
</blockquote>
<p>请求方法参数,请求客户端,返回值转换,我们都定义好了之后,便完成最后一步,构建好适合请求客户端的请求方法,Retrofit 默认的是 okhttpCall 。接下来把 <code>OkHttpCall</code> 传给 <code>serviceMethod.callAdapter</code> 对象</p>
<p>那么<code>CallAdapter</code>是干嘛的呢?上面调用了<code>adapt</code>方法,它是为了把一个<code>Call</code>转换成另一种类型,比如当 Retrofit 和 RxJava 结合使用的时候,接口中方法可以返回 <code>Observable<T></code>,这里相当于<strong>适配器模式</strong>。默认情况下得到的是一个 <code>Call</code>对象,它是<code>ExecutorCallbackCall</code>,代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">@Override</div><div class="line"> public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {</div><div class="line"> if (getRawType(returnType) != Call.class) {</div><div class="line"> return null;</div><div class="line"> }</div><div class="line"> final Type responseType = Utils.getCallResponseType(returnType);</div><div class="line"> return new CallAdapter<Call<?>>() {</div><div class="line"> @Override public Type responseType() {</div><div class="line"> return responseType;</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override public <R> Call<R> adapt(Call<R> call) {</div><div class="line"> return new ExecutorCallbackCall<>(callbackExecutor, call);</div><div class="line"> }</div><div class="line"> };</div><div class="line"> }</div></pre></td></tr></table></figure>
</li>
</ol>
<p>以上代码是在<code>ExecutorCallAdapterFactory</code>类中,这个类继承自<code>CallAdapter.Factory</code>,可以看到<code>adapt()</code>方法接受一个Call对象,看下<code>ExecutorCallbackCall</code>的部分源码:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line">static final class ExecutorCallbackCall<T> implements Call<T> {</div><div class="line"> final Executor callbackExecutor;</div><div class="line"> final Call<T> delegate;</div><div class="line"></div><div class="line"> ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {</div><div class="line"> this.callbackExecutor = callbackExecutor;</div><div class="line"> this.delegate = delegate;</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override public void enqueue(final Callback<T> callback) {</div><div class="line"> if (callback == null) throw new NullPointerException("callback == null");</div><div class="line"></div><div class="line"> delegate.enqueue(new Callback<T>() {</div><div class="line"> @Override public void onResponse(Call<T> call, final Response<T> response) {</div><div class="line"> callbackExecutor.execute(new Runnable() {</div><div class="line"> @Override public void run() {</div><div class="line"> if (delegate.isCanceled()) {</div><div class="line"> // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.</div><div class="line"> callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));</div><div class="line"> } else {</div><div class="line"> callback.onResponse(ExecutorCallbackCall.this, response);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> });</div><div class="line"> }</div><div class="line"> ...省略</div><div class="line">}</div></pre></td></tr></table></figure>
<p>在 <code>enqueue</code> 方法中,调用了 <code>OkHttpCall</code>的<code>enqueue</code>,所以这里相当于静态的代理模式。<code>OkHttpCall</code> 中的 <code>enqueue</code>其实又调用了原生的<code>OkHttp</code>中的 <code>enqueue</code>,这里才真正发出了网络请求,部分代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div></pre></td><td class="code"><pre><div class="line"> @Override public void enqueue(final Callback<T> callback) {</div><div class="line"> if (callback == null) throw new NullPointerException("callback == null");</div><div class="line"> //真正请求网络的 call</div><div class="line"> okhttp3.Call call;</div><div class="line"> Throwable failure;</div><div class="line"></div><div class="line"> synchronized (this) {</div><div class="line"> if (executed) throw new IllegalStateException("Already executed.");</div><div class="line"> executed = true;</div><div class="line"> //省略了部分发代码</div><div class="line"> ...</div><div class="line"> call = rawCall;</div><div class="line"> //enqueue 异步执行</div><div class="line"> call.enqueue(new okhttp3.Callback() {</div><div class="line"> @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)</div><div class="line"> throws IOException {</div><div class="line"> Response<T> response;</div><div class="line"> try {</div><div class="line"> //解析数据 会用到 conveterFactory,把 response 转换为对应 Java 类型</div><div class="line"> response = parseResponse(rawResponse);</div><div class="line"> } catch (Throwable e) {</div><div class="line"> callFailure(e);</div><div class="line"> return;</div><div class="line"> }</div><div class="line"> callSuccess(response);</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override public void onFailure(okhttp3.Call call, IOException e) {</div><div class="line"> try {</div><div class="line"> callback.onFailure(OkHttpCall.this, e);</div><div class="line"> } catch (Throwable t) {</div><div class="line"> t.printStackTrace();</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> private void callFailure(Throwable e) {</div><div class="line"> try {</div><div class="line"> callback.onFailure(OkHttpCall.this, e);</div><div class="line"> } catch (Throwable t) {</div><div class="line"> t.printStackTrace();</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> private void callSuccess(Response<T> response) {</div><div class="line"> try {</div><div class="line"> callback.onResponse(OkHttpCall.this, response);</div><div class="line"> } catch (Throwable t) {</div><div class="line"> t.printStackTrace();</div><div class="line"> }</div><div class="line"> }</div><div class="line"> });</div><div class="line">}</div></pre></td></tr></table></figure>
<p>OkHttp 获取数据后,解析数据并回调callback响应的方法,一次网络请求便完成了。</p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2016/07/24/hello-world/" itemprop="url">
Hello World
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2016-07-24T21:50:09+08:00" content="2016-07-24">
2016-07-24
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo server</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo generate</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo deploy</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</section>
</div>
</div>
<div class="sidebar-toggle">
<div class="sidebar-toggle-line-wrap">
<span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
</div>
</div>
<aside id="sidebar" class="sidebar">
<div class="sidebar-inner">
<section class="site-overview sidebar-panel sidebar-panel-active ">
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
<img class="site-author-image" itemprop="image"
src="https://avatars2.githubusercontent.com/u/18033495?v=3&s=460"
alt="Markable" />
<p class="site-author-name" itemprop="name">Markable</p>
<p class="site-description motion-element" itemprop="description">一分耕耘,一份收获</p>
</div>
<nav class="site-state motion-element">
<div class="site-state-item site-state-posts">
<a href="/archives">
<span class="site-state-item-count">2</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
</nav>
<div class="links-of-author motion-element">
<span class="links-of-author-item">
<a href="https://github.com/ddz-mark" target="_blank" title="GitHub">
<i class="fa fa-fw fa-github"></i>
GitHub
</a>
</span>
<span class="links-of-author-item">
<a href="https://twitter.com/dudaizhong" target="_blank" title="Twitter">
<i class="fa fa-fw fa-twitter"></i>
Twitter
</a>
</span>
<span class="links-of-author-item">
<a href="http://weibo.com/your-user-name" target="_blank" title="微博">
<i class="fa fa-fw fa-weibo"></i>
微博
</a>
</span>
<span class="links-of-author-item">
<a href="http://www.zhihu.com/people/du-dai-zhong-75" target="_blank" title="知乎">
<i class="fa fa-fw fa-tumblr"></i>
知乎
</a>
</span>
</div>
</section>
</div>
</aside>
</div>
</main>
<footer id="footer" class="footer">
<div class="footer-inner">
<div class="copyright" >
©
<span itemprop="copyrightYear">2017</span>
<span class="with-love">
<i class="fa fa-heart"></i>
</span>
<span class="author" itemprop="copyrightHolder">Markable</span>
</div>
<div class="powered-by">
由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>
<div class="theme-info">
主题 -
<a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
NexT.Pisces
</a>
</div>
</div>
</footer>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
</div>
</div>
<script type="text/javascript">
if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
window.Promise = null;
}
</script>
<script type="text/javascript" src="/vendors/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="/vendors/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
<script type="text/javascript" src="/vendors/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="/vendors/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/vendors/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/vendors/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
<script type="text/javascript" src="/js/src/utils.js?v=5.0.1"></script>
<script type="text/javascript" src="/js/src/motion.js?v=5.0.1"></script>
<script type="text/javascript" src="/js/src/affix.js?v=5.0.1"></script>
<script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.0.1"></script>
<script type="text/javascript" src="/js/src/bootstrap.js?v=5.0.1"></script>
</body>
</html>