-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
5756 lines (5191 loc) · 631 KB
/
search.xml
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
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[dumpsys的使用笔记]]></title>
<url>http://yoursite.com/2017/12/23/dumpsys%E7%9A%84%E4%BD%BF%E7%94%A8%E7%AC%94%E8%AE%B0/</url>
<content type="html"><![CDATA[<h1 id="dumpsys的使用笔记"><a href="#dumpsys的使用笔记" class="headerlink" title="dumpsys的使用笔记"></a>dumpsys的使用笔记</h1><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>   Android系统中有很多服务,不同版本的Android系统,服务不尽相同,并且不同ROM厂商也提供了其定制的服务,为了方便查看这些服务的信息与状态,Android提供了dumpsys工具。</p>
<a id="more"></a>
<p>   手机连接电脑后可以执行adb shell dumpsys -l,即可查看当前所有的系统服务名称。</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></pre></td><td class="code"><pre><div class="line">$ adb shell dumpsys -l</div><div class="line"></div><div class="line"> AAL</div><div class="line"> DmAgent</div><div class="line"> DockObserver</div><div class="line"> GbaService</div><div class="line"> GpuAppSpectatorService</div><div class="line"> GuiExtService</div><div class="line"> IIccPhoneBookMz</div><div class="line"> NvRAMAgent</div><div class="line"> PQ</div><div class="line"> SurfaceFlinger</div><div class="line"> access_control</div><div class="line"> accessibility</div><div class="line"> account</div><div class="line"> activity</div><div class="line"> alarm</div><div class="line"> alphame_server</div><div class="line"> android.hardware.fingerprint.IFingerprintDaemon</div><div class="line"> android.hardware.fingerprint.IGoodixFingerprintDaemon</div><div class="line"> android.hardware.ifaa.IIfaaDaemon</div><div class="line"> android.security.keystore</div><div class="line"> android.service.gatekeeper.IGateKeeperService</div><div class="line"> </div><div class="line"> ...</div></pre></td></tr></table></figure>
<p>   接着就可以通过<code>dumpsys + name</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></pre></td><td class="code"><pre><div class="line">$ adb shell dumpsys battery</div><div class="line"></div><div class="line"> Current Battery Service state:</div><div class="line"> AC powered: false</div><div class="line"> USB powered: true</div><div class="line"> Wireless powered: false</div><div class="line"> Max charging current: 0</div><div class="line"> Max charging voltage: 0</div><div class="line"> Charge counter: 0</div><div class="line"> status: 2</div><div class="line"> health: 2</div><div class="line"> present: true</div><div class="line"> level: 89</div><div class="line"> scale: 100</div><div class="line"> voltage: 4253</div><div class="line"> temperature: 280</div><div class="line"> technology: Li-ion</div></pre></td></tr></table></figure>
<h2 id="常用的指令"><a href="#常用的指令" class="headerlink" title="常用的指令"></a>常用的指令</h2><p>   列举一些常用的dump指令</p>
<p><strong>1. 获取包信息</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">adb shell dumpsys package packgename</div><div class="line">用以获取某个应用包的信息,不加包名则会列出所有包信息</div></pre></td></tr></table></figure>
<p><strong>2. 获取窗口信息</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">adb shell dumpsys window</div><div class="line">用以获取窗口信息</div></pre></td></tr></table></figure>
<p><strong>3. 四大组件相关信息</strong></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"></div><div class="line">adb shell dumpsys activity</div><div class="line">获取所有四大组件相关的信息</div><div class="line"></div><div class="line">adb shell dumpsys activity a packagename</div><div class="line">获取某个应用的Activity信息</div><div class="line"></div><div class="line">adb shell dumpsys activity s packagename</div><div class="line">获取某个应用的Service信息</div><div class="line"></div><div class="line">adb shell dumpsys activity b packagename</div><div class="line">获取某个应用的Broadcast信息</div><div class="line"></div><div class="line">adb shell dumpsys activity prov packagename</div><div class="line">获取某个应用的Provider信息</div><div class="line"></div><div class="line">adb shell dumpsys activity p packagename</div><div class="line">查询某个应用的进程状态</div><div class="line"></div><div class="line">adb shell dumpsys activity top | grep ACTIVITY</div><div class="line">要获取当前界面的Activity</div><div class="line"></div><div class="line">adb shell dumpsys activity top</div><div class="line">获取当前界面的UI信息</div><div class="line"></div><div class="line">adb shell dumpsys notification</div><div class="line">获取通知信息</div></pre></td></tr></table></figure>
<p><strong>4. 手机信息相关信息</strong></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></pre></td><td class="code"><pre><div class="line">adb shell dumpsys alarm</div><div class="line">获取手机闹钟信息</div><div class="line"></div><div class="line">adb shell dumpsys battery</div><div class="line">获取设备电池信息</div><div class="line"></div><div class="line">adb shell dumpsys power</div><div class="line">获取电源管理信息</div><div class="line"></div><div class="line">adb shell dumpsys wifi</div><div class="line">获取wifi相关信息</div><div class="line"></div><div class="line">adb shell dumpsys netstats</div><div class="line">获取网络状态信息</div><div class="line"></div><div class="line">adb shell dumpsys display</div><div class="line">获取显示信息</div><div class="line"></div><div class="line">adb shell dumpsys display | grep DisplayDeviceInfo</div><div class="line">获取屏幕信息</div><div class="line"></div><div class="line">adb shell dumpsys cpuinfo</div><div class="line">获取CPU信息</div><div class="line"></div><div class="line">adb shell dumpsys meminfo</div><div class="line">获取内存信息</div><div class="line"></div><div class="line">adb shell dumpsys diskstats</div><div class="line">获取磁盘信息</div><div class="line"></div><div class="line">adb shell dumpsys meminfo packagename</div><div class="line">获取某个应用的内存使用信息</div></pre></td></tr></table></figure>
<blockquote>
<p>注:大部分母指令后加-h可以获取帮助信息,如adb shell dumpsys package -h</p>
</blockquote>
<h2 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h2><p>   简单的介绍下实现原理</p>
<p>   找到其对应Android的配置文件,位于frameworks/native/cmds/dumpsys目录下,其配置如下。</p>
<figure class="highlight mk"><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">LOCAL_PATH:= <span class="variable">$(call my-dir)</span></div><div class="line">include $(CLEAR_VARS)</div><div class="line"></div><div class="line">LOCAL_SRC_FILES:= \</div><div class="line"> dumpsys.cpp</div><div class="line"></div><div class="line">...</div><div class="line"></div><div class="line">LOCAL_MODULE:= dumpsys</div><div class="line"></div><div class="line">include $(BUILD_EXECUTABLE)</div></pre></td></tr></table></figure>
<p>   可以看到配置文件很简单,最重要的是dumpsys.cpp文件,定位到位置frameworks/native/cmds/dumpsys/dumpsys.cpp,查看其main方法。</p>
<figure class="highlight"><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><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div></pre></td><td class="code"><pre><div class="line">int main(int argc, char* const argv[])</div><div class="line">{</div><div class="line"> signal(SIGPIPE, SIG_IGN);</div><div class="line"> //获取SystemServiceManager对象</div><div class="line"> sp<IServiceManager> sm = defaultServiceManager();</div><div class="line"> </div><div class="line"> ...</div><div class="line"> //保存服务的集合</div><div class="line"> Vector<String16> services;</div><div class="line"> //接收参数</div><div class="line"> Vector<String16> args;</div><div class="line"> Vector<String16> skippedServices;</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> while (1) {</div><div class="line"> int c;</div><div class="line"> int optionIndex = 0;</div><div class="line"> //根据输入参数获取对应的值</div><div class="line"> c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);</div><div class="line"></div><div class="line"> if (c == -1) {</div><div class="line"> break;</div><div class="line"> }</div><div class="line"> //根据对应的值选择输出对应的dump信息序列</div><div class="line"> switch (c) {</div><div class="line"> case 0:</div><div class="line"> //跳过服务以及帮助信息</div><div class="line"> if (!strcmp(longOptions[optionIndex].name, "skip")) {</div><div class="line"> skipServices = true;</div><div class="line"> } else if (!strcmp(longOptions[optionIndex].name, "help")) {</div><div class="line"> usage();</div><div class="line"> return 0;</div><div class="line"> }</div><div class="line"> break;</div><div class="line"></div><div class="line"> case 't':</div><div class="line"> //超时设置</div><div class="line"> {</div><div class="line"> char *endptr;</div><div class="line"> timeoutArg = strtol(optarg, &endptr, 10);</div><div class="line"> if (*endptr != '\0' || timeoutArg <= 0) {</div><div class="line"> fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);</div><div class="line"> return -1;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> break;</div><div class="line"></div><div class="line"> case 'l':</div><div class="line"> //当值为'l',只列出所有服务名</div><div class="line"> showListOnly = true;</div><div class="line"> break;</div><div class="line"></div><div class="line"> default:</div><div class="line"> fprintf(stderr, "\n");</div><div class="line"> usage();</div><div class="line"> return -1;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> ...</div><div class="line"></div><div class="line"> if (services.empty() || showListOnly) {</div><div class="line"> // gets all services</div><div class="line"> //获取所有服务</div><div class="line"> services = sm->listServices();</div><div class="line"> //排序</div><div class="line"> services.sort(sort_func);</div><div class="line"> args.add(String16("-a"));</div><div class="line"> }</div><div class="line"> //计算服务个数</div><div class="line"> const size_t N = services.size();</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> for (size_t i = 0; i < N; i++) {</div><div class="line"> //获取服务名称</div><div class="line"> String16 service_name = std::move(services[i]);</div><div class="line"> </div><div class="line"> if (IsSkipped(skippedServices, service_name)) continue;</div><div class="line"> //检查服务</div><div class="line"> sp<IBinder> service = sm->checkService(service_name);</div><div class="line"> </div><div class="line"> if (service != NULL) {</div><div class="line"> ...</div><div class="line"></div><div class="line"> // dump blocks until completion, so spawn a thread..</div><div class="line"> //通过线程打印dump信息</div><div class="line"> std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {</div><div class="line"> //打印dump信息</div><div class="line"> int err = service->dump(remote_end.get(), args);</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><div class="line"> auto timeout = std::chrono::seconds(timeoutArg);</div><div class="line"> </div><div class="line"> ...</div><div class="line"> } </div><div class="line"> }</div><div class="line"> return 0;</div></pre></td></tr></table></figure>
<p>   从上述的代码里,可以看出,dump的大致逻辑为:</p>
<ol>
<li>通过defaultServiceManager获取SystemServiceManager的对象(SystemServiceManager顾名思义就是用来管理所有的服务);</li>
<li>通过SystemServiceManager获取系统所有服务,并排序;</li>
<li>解析接收的参数,根据参数的不同设置后续的执行指令序列;</li>
<li>从SystemServiceManager中找到需要输出的服务对象,执行该服务的dump方法</li>
<li>完成所有dump信息打印。</li>
</ol>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[Android语言切换原理]]></title>
<url>http://yoursite.com/2017/11/19/Android%E8%AF%AD%E8%A8%80%E5%88%87%E6%8D%A2%E5%8E%9F%E7%90%86/</url>
<content type="html"><![CDATA[<h1 id="Android语言切换原理"><a href="#Android语言切换原理" class="headerlink" title="Android语言切换原理"></a>Android语言切换原理</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>   之前因为系统有些国家使用的字体乱码的原因,研究了下Android系统字体加载相关的知识,写了一篇Android系统字体加载流程的总结,<a href="http://blog.csdn.net/a282255307/article/details/76870441" target="_blank" rel="external">浅析Android字体加载原理</a>,然而系统的字体与系统当前的语言有密切的关系,因此抽空了解了下Android系统语言切换的流程,写下总结,加深印象。</p>
<a id="more"></a>
<h2 id="Android语言切换流程分析"><a href="#Android语言切换流程分析" class="headerlink" title="Android语言切换流程分析"></a>Android语言切换流程分析</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>   有过Android开发经验的人,应该都知道Android有一套成熟的国际化机制,通常应用或系统要走出海外,都要进行国际化适配,而Android语言切换依赖于国际化适配,但这里,我们不深入了解Android国际化的原理,有兴趣的读者可以自行Google或者百度,下面对Android语言切换流程进行分析。</p>
<h3 id="Android多语言描述"><a href="#Android多语言描述" class="headerlink" title="Android多语言描述"></a>Android多语言描述</h3><p>   有关Android系统本地化的介绍,请查看官网,<a href="https://developer.android.com/guide/topics/resources/localization.html" target="_blank" rel="external">本地化</a>。</p>
<p>   对于Android语言切换接口,在Android 6.0及以前的语言设置都是单一的语言,只能选一种语言,见下图。</p>
<p><img src="/images/2017-11-19-1.png" alt="6.0系统"></p>
<p>   Android7.0系统以上,则是更人性化了,允许用户在设置中选择多个语言,如下图,用户可以根据自己的喜好选择语言列表,并将默认的语言拖拽到首项,设为系统默认语言。</p>
<p><img src="/images/2017-11-19-2.png" alt="7.0系统"></p>
<p>   这么做的目的是为了一些国家使用多种语言,比如印度,印度语是第一母语,英语则为其第二母语,这样的话,在系统捏添加这两个语言后,会加载相应的语言资源,当第一语言没有相应资源时,会去第二语言中查找,而7.0以下的系统就只能加载一种语言下的资源文件,存在很大的限制,这里就不做扩展,有兴趣的读者可以自行了解。</p>
<h3 id="Android多语言切换"><a href="#Android多语言切换" class="headerlink" title="Android多语言切换"></a>Android多语言切换</h3><p>   如上所述,Android在不同的系统版本为用户提供不同的语言切换功能,因此在切换流程过中,调用的接口也不同,如Android6.0及以下,设置切换语言的接口调用的是<strong>updateLocale(Locale locale)</strong>,如Android7.0以上,设置切换语言的接口调用的是<strong>updateLocales(LocaleList locales)</strong>,但是大致的流程还是保持一致,多的只是文件存放位置的变化,下面笔者将以Android7.0的流程进行分析,7.0以下的,读者可自行分析。</p>
<blockquote>
<p>注:从上面的两个接口,也可以看出,高版本系统与低版本系统加载语言的区别,前者是加载多个语言的列表,后者是加载一个语言。</p>
</blockquote>
<p>   如上所述,当用户在设置中选择对应的语言后,Android会首先调frameworks/base/com/android/internal/app/LocalePicker.java中的updateLocales(LocaleList locales)方法。</p>
<blockquote>
<p>注:如果你不想用Android7.0以上的语言切换功能,可以考虑自己实现updateLocale(Locale locale)方法。</p>
</blockquote>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * Requests the system to update the list of system locales.</div><div class="line"> * Note that the system looks halted for a while during the Locale migration,</div><div class="line"> * so the caller need to take care of it.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">updateLocales</span><span class="params">(LocaleList locales)</span> </span>{</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="comment">//获取am</span></div><div class="line"> <span class="keyword">final</span> IActivityManager am = ActivityManagerNative.getDefault();</div><div class="line"> <span class="comment">//获取am配置对象</span></div><div class="line"> <span class="keyword">final</span> Configuration config = am.getConfiguration();</div><div class="line"></div><div class="line"> <span class="comment">//为配置对象重新设置语言</span></div><div class="line"> config.setLocales(locales);</div><div class="line"> <span class="comment">//重置标志位</span></div><div class="line"> config.userSetLocale = <span class="keyword">true</span>;</div><div class="line"></div><div class="line"> am.updatePersistentConfiguration(config);</div><div class="line"> <span class="comment">// Trigger the dirty bit for the Settings Provider.</span></div><div class="line"> BackupManager.dataChanged(<span class="string">"com.android.providers.settings"</span>);</div><div class="line"> } <span class="keyword">catch</span> (RemoteException e) {</div><div class="line"> <span class="comment">// Intentionally left blank</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   Google对该方法的介绍是,当更新系统语言列表的时候,就会调用这个方法。从上方展示的源码来看,该方法首先会调用ActivityManagerNative.getDefault()来获取ActivityManagerServices(以下简称AMS)在本地的代理,从而调用AMS中的updatePersistentConfiguration()并传入创建好的配置对象(Configuration)。</p>
<blockquote>
<p>注:这里是ActivityManagerNative使用远程代理通过Binder条用AMS的同名方法,由于Android的代理机制十分复杂,这里不继续介绍Android代理机制。</p>
</blockquote>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">updatePersistentConfiguration</span><span class="params">(Configuration values)</span> </span>{</div><div class="line"> <span class="comment">//强制权限校验</span></div><div class="line"> enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,</div><div class="line"> <span class="string">"updateConfiguration()"</span>);</div><div class="line"> <span class="comment">//强制写入设置权限</span></div><div class="line"> enforceWriteSettingsPermission(<span class="string">"updateConfiguration()"</span>);</div><div class="line"> <span class="keyword">if</span> (values == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException(<span class="string">"Configuration must not be null"</span>);</div><div class="line"> }</div><div class="line"> <span class="comment">//获取调用用户的ID</span></div><div class="line"> <span class="keyword">int</span> userId = UserHandle.getCallingUserId();</div><div class="line"></div><div class="line"> <span class="keyword">synchronized</span>(<span class="keyword">this</span>) {</div><div class="line"> <span class="comment">//调用方法</span></div><div class="line"> updatePersistentConfigurationLocked(values, userId);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   可以看出,该方法首先进行了权限校验,权限赋予,然后调用updatePersistentConfigurationLocked()方法,继续看下这个方法。</p>
<figure class="highlight java"><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"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">updatePersistentConfigurationLocked</span><span class="params">(Configuration values, @UserIdInt <span class="keyword">int</span> userId)</span> </span>{</div><div class="line"> <span class="comment">//清除Binder调用标识</span></div><div class="line"> <span class="keyword">final</span> <span class="keyword">long</span> origId = Binder.clearCallingIdentity();</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="comment">//重要方法</span></div><div class="line"> updateConfigurationLocked(values, <span class="keyword">null</span>, <span class="keyword">false</span>, <span class="keyword">true</span>, userId, <span class="keyword">false</span> <span class="comment">/* deferResume */</span>);</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> Binder.restoreCallingIdentity(origId);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   这个方法只是清除了Binder标识,并调用了updateConfigurationLocked()方法,该方法非常重要,注意这里的传参,继续往下看。</p>
<figure class="highlight java"><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><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * Do either or both things: (1) change the current configuration, and (2)</div><div class="line"> * make sure the given activity is running with the (now) current</div><div class="line"> * configuration. Returns true if the activity has been left running, or</div><div class="line"> * false if <var>starting</var> is being destroyed to match the new</div><div class="line"> * configuration.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> userId is only used when persistent parameter is set to true to persist configuration</div><div class="line"> * for that particular user</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">updateConfigurationLocked</span><span class="params">(Configuration values, ActivityRecord starting,</span></span></div><div class="line"> <span class="keyword">boolean</span> initLocale, <span class="keyword">boolean</span> persistent, <span class="keyword">int</span> userId, <span class="keyword">boolean</span> deferResume) {</div><div class="line"> <span class="keyword">int</span> changes = <span class="number">0</span>;</div><div class="line"></div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="keyword">if</span> (values != <span class="keyword">null</span>) {</div><div class="line"> Configuration newConfig = <span class="keyword">new</span> Configuration(mConfiguration);</div><div class="line"> changes = newConfig.updateFrom(values);</div><div class="line"> <span class="keyword">if</span> (changes != <span class="number">0</span>) {</div><div class="line"> <span class="keyword">if</span> (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,</div><div class="line"> <span class="string">"Updating configuration to: "</span> + values);</div><div class="line"></div><div class="line"> EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {</div><div class="line"> <span class="comment">//得到选择的国家语言列表</span></div><div class="line"> <span class="keyword">final</span> LocaleList locales = values.getLocales();</div><div class="line"> <span class="keyword">int</span> bestLocaleIndex = <span class="number">0</span>;</div><div class="line"> <span class="keyword">if</span> (locales.size() > <span class="number">1</span>) {</div><div class="line"> <span class="keyword">if</span> (mSupportedSystemLocales == <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">//获取系统支持国家语言列表</span></div><div class="line"> mSupportedSystemLocales =</div><div class="line"> Resources.getSystem().getAssets().getLocales();</div><div class="line"> }</div><div class="line"> <span class="comment">//匹配国家,获取选择默认国家语言下标</span></div><div class="line"> bestLocaleIndex = Math.max(<span class="number">0</span>,</div><div class="line"> locales.getFirstMatchIndex(mSupportedSystemLocales));</div><div class="line"> }</div><div class="line"> SystemProperties.set(<span class="string">"persist.sys.locale"</span>,</div><div class="line"> locales.get(bestLocaleIndex).toLanguageTag());</div><div class="line"> <span class="comment">//设置为选择的国家语言为默认国家语言</span></div><div class="line"> LocaleList.setDefault(locales, bestLocaleIndex);</div><div class="line"> <span class="comment">//发送消息通知挂载守护进程国家语言变更</span></div><div class="line"> mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,</div><div class="line"> locales.get(bestLocaleIndex)));</div><div class="line"> }</div><div class="line"></div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="comment">// Make sure all resources in our process are updated</span></div><div class="line"> <span class="comment">// right now, so that anyone who is going to retrieve</span></div><div class="line"> <span class="comment">// resource values after we return will be sure to get</span></div><div class="line"> <span class="comment">// the new ones. This is especially important during</span></div><div class="line"> <span class="comment">// boot, where the first config change needs to guarantee</span></div><div class="line"> <span class="comment">// all resources have that config before following boot</span></div><div class="line"> <span class="comment">// code is executed.</span></div><div class="line"> <span class="comment">//更新资源配置</span></div><div class="line"> mSystemThread.applyConfigurationToResources(configCopy);</div><div class="line"> <span class="comment">//如果有配置改动,就发送该消息通知配置改动</span></div><div class="line"> <span class="keyword">if</span> (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {</div><div class="line"> Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);</div><div class="line"> msg.obj = <span class="keyword">new</span> Configuration(configCopy);</div><div class="line"> msg.arg1 = userId;</div><div class="line"> mHandler.sendMessage(msg);</div><div class="line"> }</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=mLruProcesses.size()-<span class="number">1</span>; i>=<span class="number">0</span>; i--) {</div><div class="line"> ProcessRecord app = mLruProcesses.get(i);</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="keyword">if</span> (app.thread != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">if</span> (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, <span class="string">"Sending to proc "</span></div><div class="line"> + app.processName + <span class="string">" new config "</span> + mConfiguration);</div><div class="line"> app.thread.scheduleConfigurationChanged(configCopy);</div><div class="line"> }</div><div class="line"> } <span class="keyword">catch</span> (Exception e) {</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>   从Google给的注释说明可以看到,这个方法的最重要的作用如下:</p>
<ol>
<li>更新当前系统的配置到最新的配置;</li>
<li>保证所有的Activity都能更新到改变后的配置。</li>
</ol>
<blockquote>
<p>注:在更新或者清除configuration时,是通过changes位标记法来确认是configuration中的哪一项。</p>
</blockquote>
<p>   继续来看Android是如何进行配置更新的。首先调用updateFrom(),方法来更新配置,我们先看看这个方法。</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * Copies the fields from delta into this Configuration object, keeping</div><div class="line"> * track of which ones have changed. Any undefined fields in {<span class="doctag">@code</span> delta}</div><div class="line"> * are ignored and not copied in to the current Configuration.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@return</span> a bit mask of the changed fields, as per {<span class="doctag">@link</span> #diff}</div><div class="line"> */</div><div class="line"><span class="keyword">public</span> <span class="meta">@Config</span> <span class="function"><span class="keyword">int</span> <span class="title">updateFrom</span><span class="params">(@NonNull Configuration delta)</span> </span>{</div><div class="line"> <span class="comment">//变化项</span></div><div class="line"> <span class="keyword">int</span> changed = <span class="number">0</span>;</div><div class="line"> </div><div class="line"> ...</div><div class="line"> <span class="comment">//当有语言列表变化时,走这</span></div><div class="line"> <span class="keyword">if</span> (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {</div><div class="line"> changed |= ActivityInfo.CONFIG_LOCALE;</div><div class="line"> mLocaleList = delta.mLocaleList;</div><div class="line"> <span class="comment">// delta.locale can't be null, since delta.mLocaleList is not empty.</span></div><div class="line"> <span class="keyword">if</span> (!delta.locale.equals(locale)) {</div><div class="line"> locale = (Locale) delta.locale.clone();</div><div class="line"> <span class="comment">// If locale has changed, then layout direction is also changed ...</span></div><div class="line"> changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;</div><div class="line"> <span class="comment">// ... and we need to update the layout direction (represented by the first</span></div><div class="line"> <span class="comment">// 2 most significant bits in screenLayout).</span></div><div class="line"> setLayoutDirection(locale);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="keyword">if</span> (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != <span class="number">0</span>)))</div><div class="line"> {</div><div class="line"> changed |= ActivityInfo.CONFIG_LOCALE;</div><div class="line"> userSetLocale = <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> changed;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   从以上可以看到,当我们修改了语言列表,那么返回的变化项change一定大于0。继续回到updateConfigurationLocked()方法中,由于change不为0,并且根据前面的传参,updateConfigurationLocked()方法将从变更的国家语言列表中获取默认国家语言下标,然后设置默认国家语言以及默认国家列表,并发送消息通知挂载守护进程国家语言的变化,其中设置默认情况的代码如下。</p>
<figure class="highlight java"><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"><span class="comment">//设置默认国家语言以及国家语言列表</span></div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * This may be used directly by system processes to set the default locale list for apps. For</div><div class="line"> * such uses, the default locale list would always come from the user preferences, but the</div><div class="line"> * default locale may have been chosen to be a locale other than the first locale in the locale</div><div class="line"> * list (based on the locales the app supports).</div><div class="line"> *</div><div class="line"> * {<span class="doctag">@hide</span>}</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setDefault</span><span class="params">(@NonNull @Size(min=<span class="number">1</span>)</span> LocaleList locales, <span class="keyword">int</span> localeIndex) </span>{</div><div class="line"> <span class="keyword">if</span> (locales == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException(<span class="string">"locales is null"</span>);</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (locales.isEmpty()) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"locales is empty"</span>);</div><div class="line"> }</div><div class="line"> <span class="keyword">synchronized</span> (sLock) {</div><div class="line"> sLastDefaultLocale = locales.get(localeIndex);</div><div class="line"> Locale.setDefault(sLastDefaultLocale);</div><div class="line"> sLastExplicitlySetLocaleList = locales;</div><div class="line"> sDefaultLocaleList = locales;</div><div class="line"> <span class="keyword">if</span> (localeIndex == <span class="number">0</span>) {</div><div class="line"> sDefaultAdjustedLocaleList = sDefaultLocaleList;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> sDefaultAdjustedLocaleList = <span class="keyword">new</span> LocaleList(</div><div class="line"> sLastDefaultLocale, sDefaultLocaleList);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   再此之后,系统进程会首先通知Configuration改变,所以mSystemThread即系统的ActivityThread类对象调用applyConfigurationToResources()确保自己所在的进程资源更新到最新(主要指framework-res.apk中的资源,也就是上面所说的updateConfigurationLocked()方法的第一个重要作用),以便任何人检索资源的时候拿到的都是最新的资源,然后发送通知更新用户配置。</p>
<blockquote>
<p>注:这里是系统更新配置资源,后面将对pplyConfigurationToResources()方法进行描述。</p>
</blockquote>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">// Make sure all resources in our process are updated</span></div><div class="line"><span class="comment">// right now, so that anyone who is going to retrieve</span></div><div class="line"><span class="comment">// resource values after we return will be sure to get</span></div><div class="line"><span class="comment">// the new ones. This is especially important during</span></div><div class="line"><span class="comment">// boot, where the first config change needs to guarantee</span></div><div class="line"><span class="comment">// all resources have that config before following boot</span></div><div class="line"><span class="comment">// code is executed.</span></div><div class="line"><span class="comment">//更新资源配置</span></div><div class="line">mSystemThread.applyConfigurationToResources(configCopy);</div><div class="line"><span class="comment">//如果有配置改动,就发送该消息通知配置改动</span></div><div class="line"><span class="keyword">if</span> (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {</div><div class="line"> Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);</div><div class="line"> msg.obj = <span class="keyword">new</span> Configuration(configCopy);</div><div class="line"> msg.arg1 = userId;</div><div class="line"> mHandler.sendMessage(msg);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   继续往下看,以下是遍历每个应用,通知其配置的改变。</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="comment">//保存所有应用的进程</span></div><div class="line"><span class="keyword">final</span> ArrayList<ProcessRecord> mLruProcesses = <span class="keyword">new</span> ArrayList<ProcessRecord>();</div><div class="line"></div><div class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i=mLruProcesses.size()-<span class="number">1</span>; i>=<span class="number">0</span>; i--) {</div><div class="line"> ProcessRecord app = mLruProcesses.get(i);</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="keyword">if</span> (app.thread != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">if</span> (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, <span class="string">"Sending to proc "</span></div><div class="line"> + app.processName + <span class="string">" new config "</span> + mConfiguration);</div><div class="line"> app.thread.scheduleConfigurationChanged(configCopy);</div><div class="line"> }</div><div class="line"> } <span class="keyword">catch</span> (Exception e) {</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">scheduleConfigurationChanged</span><span class="params">(Configuration config)</span></span></div><div class="line"> <span class="keyword">throws</span> RemoteException {</div><div class="line"> Parcel data = Parcel.obtain();</div><div class="line"> data.writeInterfaceToken(IApplicationThread.descriptor);</div><div class="line"> config.writeToParcel(data, <span class="number">0</span>);</div><div class="line"> mRemote.transact(SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION, data, <span class="keyword">null</span>,</div><div class="line"> IBinder.FLAG_ONEWAY);</div><div class="line"> data.recycle();</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   可以看到,mLruProcesses中保存的是所有运行的进程,Android中,每个应用运行时都对应于一个进程,因此这里包含了所有运行的应用。我们注意到这里循环调用了app.thread.scheduleConfigurationChanged(configCopy),app.thread对应于每个应用的线程,其作用是通知各个应用进程Configuration改变。跳转后会发现,这里其实又是通过binder调用跨进程方法,在这里是调用ActivityThread.java中私有ApplicationThread的方法,查看该方法。</p>
<blockquote>
<p>注:ApplicationThread是ActivityThread的内部类,也是一个Binder对象,这边用以等待AMS发送消息。</p>
</blockquote>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">scheduleConfigurationChanged</span><span class="params">(Configuration config)</span> </span>{</div><div class="line"> updatePendingConfiguration(config);</div><div class="line"> <span class="comment">//发送消息给对应的主线程</span></div><div class="line"> sendMessage(H.CONFIGURATION_CHANGED, config);</div><div class="line">}</div><div class="line"></div><div class="line">...</div><div class="line"></div><div class="line"><span class="keyword">case</span> CONFIGURATION_CHANGED:</div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="string">"configChanged"</span>);</div><div class="line"> mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;</div><div class="line"> mUpdatingSystemConfig = <span class="keyword">true</span>;</div><div class="line"> <span class="comment">//接收到AMS发来的数据</span></div><div class="line"> handleConfigurationChanged((Configuration)msg.obj, <span class="keyword">null</span>);</div><div class="line"> mUpdatingSystemConfig = <span class="keyword">false</span>;</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</div><div class="line"> <span class="keyword">break</span>;</div></pre></td></tr></table></figure>
<p>   这里ApplicationThread接收到AMS的信息后,会发送消息CONFIGURATION_CHANGED给对应应用的ActivityThread。ActivityThread收到CONFIGURATION_CHANGED消息后,其会调用handleConfigurationChanged()方法。</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">handleConfigurationChanged</span><span class="params">(Configuration config, CompatibilityInfo compat)</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">int</span> configDiff = <span class="number">0</span>;</div><div class="line"></div><div class="line"> <span class="keyword">synchronized</span> (mResourcesManager) {</div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="comment">//将资源配置修改应用到资源中</span></div><div class="line"> mResourcesManager.applyConfigurationToResourcesLocked(config, compat);</div><div class="line"> <span class="comment">//更新语言列表</span></div><div class="line"> updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),</div><div class="line"> mResourcesManager.getConfiguration().getLocales());</div><div class="line"></div><div class="line"> ...</div><div class="line"> }</div><div class="line"> <span class="comment">//组件修改回调对象</span></div><div class="line"> ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(<span class="keyword">false</span>, config);</div><div class="line"></div><div class="line"> freeTextLayoutCachesIfNeeded(configDiff);</div><div class="line"> <span class="keyword">if</span> (callbacks != <span class="keyword">null</span>) {framework-res.apk</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> N = callbacks.size();</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">0</span>; i<N; i++) {</div><div class="line"> ComponentCallbacks2 cb = callbacks.get(i);</div><div class="line"> <span class="keyword">if</span> (cb <span class="keyword">instanceof</span> Activity) {</div><div class="line"> <span class="comment">// If callback is an Activity - call corresponding method to consider override</span></div><div class="line"> <span class="comment">// config and avoid onConfigurationChanged if it hasn't changed.</span></div><div class="line"> Activity a = (Activity) cb;</div><div class="line"> <span class="comment">//Activity回调响应</span></div><div class="line"> performConfigurationChangedForActivity(mActivities.get(a.getActivityToken()),</div><div class="line"> config, REPORT_TO_ACTIVITY);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//其他回调响应</span></div><div class="line"> performConfigurationChanged(cb, <span class="keyword">null</span>, config, <span class="keyword">null</span>, REPORT_TO_ACTIVITY);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   在handleConfigurationChanged()方法中,也会调用applyConfigurationToResourcesLocked()方法,去更新每个应用的配置资源(也就是上述updateConfigurationLocked()方法的第二个重要作用)。</p>
<p>   也就是说,不管是系统资源还是应用资源的更新都要调用applyConfigurationToResourcesLocked()方法。按字面意思,大概的作用就是将资源配置修改应用到资源中,而资源文件就包含语言资源文件、图片资源、布局资源等,查看其代码。</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">applyConfigurationToResourcesLocked</span><span class="params">(@NonNull Configuration config,</span></span></div><div class="line"> @Nullable CompatibilityInfo compat) {</div><div class="line"> </div><div class="line"> <span class="keyword">private</span> <span class="keyword">final</span> ArrayMap<ResourcesKey, WeakReference<ResourcesImpl>> mResourceImpls =</div><div class="line"> <span class="keyword">new</span> ArrayMap<>();</div><div class="line"> </div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="comment">//获取更新项</span></div><div class="line"> <span class="keyword">int</span> changes = mResConfiguration.updateFrom(config);</div><div class="line"> <span class="comment">// Things might have changed in display manager, so clear the cached displays.</span></div><div class="line"> mDisplays.clear();</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="comment">//更新系统资源配置</span></div><div class="line"> Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);</div><div class="line"> <span class="comment">//通知配置文件修改,清理缓存,如Icon和String</span></div><div class="line"> ApplicationPackageManager.configurationChanged();</div><div class="line"> <span class="comment">//Slog.i(TAG, "Configuration changed in " + currentPackageName());</span></div><div class="line"></div><div class="line"> Configuration tmpConfig = <span class="keyword">null</span>;</div><div class="line"> </div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = mResourceImpls.size() - <span class="number">1</span>; i >= <span class="number">0</span>; i--) {</div><div class="line"> ResourcesKey key = mResourceImpls.keyAt(i);</div><div class="line"> ResourcesImpl r = mResourceImpls.valueAt(i).get();</div><div class="line"> <span class="keyword">if</span> (r != <span class="keyword">null</span>) {</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> r.updateConfiguration(tmpConfig, dm, compat);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> r.updateConfiguration(config, dm, compat);</div><div class="line"> }</div><div class="line"> <span class="comment">//Slog.i(TAG, "Updated app resources " + v.getKey()</span></div><div class="line"> <span class="comment">// + " " + r + ": " + r.getConfiguration());</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//Slog.i(TAG, "Removing old resources " + v.getKey());</span></div><div class="line"> mResourceImpls.removeAt(i);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> changes != <span class="number">0</span>;</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   按照上面的说法,系统进程以及应用进程会分别调用applyConfigurationToResourcesLocked()方法来更新配置。</p>
<p>   当系统进程执行该方法时,Resources.updateSystemConfiguration()会更新系统资源配置(frameworks-res.apk),在执行完ApplicationPackageManager.configurationChanged()方法后,会清除进程的资源缓存,如Icon与String,并移除其他旧的资源,最终加载新的系统资源。</p>
<blockquote>
<p>注:这里并未对更新细节进行详细描述,如有兴趣可以自行研究下。</p>
</blockquote>
<p>   当应用进程执行该方法时,会通知应用进程更新资源配置,并且实现ComponentCallbacks2接口的组件,如Activity、Services、Application等会被记录,并在handleConfigurationChanged()中被遍历回调通知更新资源配置,因此我们再回到handleConfigurationChanged()方法中。</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">//组件修改回调对象</span></div><div class="line">ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(<span class="keyword">false</span>, config);</div><div class="line"></div><div class="line">freeTextLayoutCachesIfNeeded(configDiff);</div><div class="line"><span class="keyword">if</span> (callbacks != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> N = callbacks.size();</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">0</span>; i<N; i++) {</div><div class="line"> ComponentCallbacks2 cb = callbacks.get(i);</div><div class="line"> <span class="keyword">if</span> (cb <span class="keyword">instanceof</span> Activity) {</div><div class="line"> <span class="comment">// If callback is an Activity - call corresponding method to consider override</span></div><div class="line"> <span class="comment">// config and avoid onConfigurationChanged if it hasn't changed.</span></div><div class="line"> Activity a = (Activity) cb;</div><div class="line"> <span class="comment">//Activity回调响应</span></div><div class="line"> performConfigurationChangedForActivity(mActivities.get(a.getActivityToken()),</div><div class="line"> config, REPORT_TO_ACTIVITY);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//其他回调响应</span></div><div class="line"> performConfigurationChanged(cb, <span class="keyword">null</span>, config, <span class="keyword">null</span>, REPORT_TO_ACTIVITY);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   从上面可以看出,在回调中,如果是Activity,则回调performConfigurationChangedForActivity()方法,如果是Services、Application等,回调performConfigurationChanged()方法,按注释解释,这样做是为了Activity在更新配置时重写配置和避免没有修改时回调onConfigurationChanged()方法,但不管是什么组件,最终都是调用performConfigurationChanged()方法,我们来具体看下这个方法。</p>
<figure class="highlight java"><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><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">performConfigurationChanged</span><span class="params">(ComponentCallbacks2 cb,</span></span></div><div class="line"> IBinder activityToken,</div><div class="line"> Configuration newConfig,</div><div class="line"> Configuration amOverrideConfig,</div><div class="line"> <span class="keyword">boolean</span> reportToActivity) {</div><div class="line"> <span class="comment">// Only for Activity objects, check that they actually call up to their</span></div><div class="line"> <span class="comment">// superclass implementation. ComponentCallbacks2 is an interface, so</span></div><div class="line"> <span class="comment">// we check the runtime type and act accordingly.</span></div><div class="line"> Activity activity = (cb <span class="keyword">instanceof</span> Activity) ? (Activity) cb : <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">if</span> (activity != <span class="keyword">null</span>) {</div><div class="line"> activity.mCalled = <span class="keyword">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">boolean</span> shouldChangeConfig = <span class="keyword">false</span>;</div><div class="line"> <span class="keyword">if</span> ((activity == <span class="keyword">null</span>) || (activity.mCurrentConfig == <span class="keyword">null</span>)) {</div><div class="line"> shouldChangeConfig = <span class="keyword">true</span>;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// If the new config is the same as the config this Activity is already</span></div><div class="line"> <span class="comment">// running with and the override config also didn't change, then don't</span></div><div class="line"> <span class="comment">// bother calling onConfigurationChanged.</span></div><div class="line"> <span class="keyword">int</span> diff = activity.mCurrentConfig.diff(newConfig);</div><div class="line"> <span class="keyword">if</span> (diff != <span class="number">0</span> || !mResourcesManager.isSameResourcesOverrideConfig(activityToken,</div><div class="line"> amOverrideConfig)) {</div><div class="line"> <span class="comment">// Always send the task-level config changes. For system-level configuration, if</span></div><div class="line"> <span class="comment">// this activity doesn't handle any of the config changes, then don't bother</span></div><div class="line"> <span class="comment">// calling onConfigurationChanged as we're going to destroy it.</span></div><div class="line"> <span class="keyword">if</span> (!mUpdatingSystemConfig</div><div class="line"> || (~activity.mActivityInfo.getRealConfigChanged() & diff) == <span class="number">0</span></div><div class="line"> || !reportToActivity) {</div><div class="line"> shouldChangeConfig = <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (shouldChangeConfig) {</div><div class="line"> <span class="comment">// Propagate the configuration change to the Activity and ResourcesManager.</span></div><div class="line"></div><div class="line"> <span class="comment">// ContextThemeWrappers may override the configuration for that context.</span></div><div class="line"> <span class="comment">// We must check and apply any overrides defined.</span></div><div class="line"> Configuration contextThemeWrapperOverrideConfig = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">if</span> (cb <span class="keyword">instanceof</span> ContextThemeWrapper) {</div><div class="line"> <span class="keyword">final</span> ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;</div><div class="line"> contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration();</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// We only update an Activity's configuration if this is not a global</span></div><div class="line"> <span class="comment">// configuration change. This must also be done before the callback,</span></div><div class="line"> <span class="comment">// or else we violate the contract that the new resources are available</span></div><div class="line"> <span class="comment">// in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.</span></div><div class="line"> <span class="keyword">if</span> (activityToken != <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// Apply the ContextThemeWrapper override if necessary.</span></div><div class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Make sure the configurations are not modified, as they are treated</span></div><div class="line"> <span class="comment">// as immutable in many places.</span></div><div class="line"> <span class="keyword">final</span> Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(</div><div class="line"> amOverrideConfig, contextThemeWrapperOverrideConfig);</div><div class="line"> mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (reportToActivity) {</div><div class="line"> <span class="comment">// Apply the ContextThemeWrapper override if necessary.</span></div><div class="line"> <span class="comment">// <span class="doctag">NOTE:</span> Make sure the configurations are not modified, as they are treated</span></div><div class="line"> <span class="comment">// as immutable in many places.</span></div><div class="line"> <span class="keyword">final</span> Configuration configToReport = createNewConfigAndUpdateIfNotNull(</div><div class="line"> newConfig, contextThemeWrapperOverrideConfig);</div><div class="line"> cb.onConfigurationChanged(configToReport);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (activity != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">if</span> (reportToActivity && !activity.mCalled) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> SuperNotCalledException(</div><div class="line"> <span class="string">"Activity "</span> + activity.getLocalClassName() +</div><div class="line"> <span class="string">" did not call through to super.onConfigurationChanged()"</span>);</div><div class="line"> }</div><div class="line"> activity.mConfigChangeFlags = <span class="number">0</span>;</div><div class="line"> activity.mCurrentConfig = <span class="keyword">new</span> Configuration(newConfig);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   从上面代码注释,可以看到,只有Activity组件才会实现这个方法,并且只有当配置修改不是全局时,Activity会在回调前调用updateResourcesForActivity()方法来更新配置资源,最后回调onConfigurationChanged()方法。</p>
<figure class="highlight java"><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"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * Called by the system when the device configuration changes while your</div><div class="line"> * activity is running. Note that this will <em>only</em> be called if</div><div class="line"> * you have selected configurations you would like to handle with the</div><div class="line"> * {<span class="doctag">@link</span> android.R.attr#configChanges} attribute in your manifest. If</div><div class="line"> * any configuration change occurs that is not selected to be reported</div><div class="line"> * by that attribute, then instead of reporting it the system will stop</div><div class="line"> * and restart the activity (to have it launched with the new</div><div class="line"> * configuration).</div><div class="line"> * <p></div><div class="line"> * <p>At the time that this function has been called, your Resources</div><div class="line"> * object will have been updated to return resource values matching the</div><div class="line"> * new configuration.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> newConfig The new device configuration.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onConfigurationChanged</span><span class="params">(Configuration newConfig)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (DEBUG_LIFECYCLE) Slog.v(TAG, <span class="string">"onConfigurationChanged "</span> + <span class="keyword">this</span> + <span class="string">": "</span> + newConfig);</div><div class="line"> mCalled = <span class="keyword">true</span>;</div><div class="line"></div><div class="line"> mFragments.dispatchConfigurationChanged(newConfig);</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (mWindow != <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// Pass the configuration changed event to the window</span></div><div class="line"> mWindow.onConfigurationChanged(newConfig);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (mActionBar != <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// Do this last; the action bar will need to access</span></div><div class="line"> <span class="comment">// view changes from above.</span></div><div class="line"> mActionBar.onConfigurationChanged(newConfig);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   以上注释大概的意思是,当你的Activity在运行时,有设备配置发生了变化,系统就会调用这个方法。如果你在manifest中配置了configChanges属性,则表示由你自己处理配置修改,否则就会重启这个Activity,并且会加载新的资源,这样就让系统以及应用加载完新的资源,完成了语言的切换。</p>
<p><strong>总结</strong></p>
<p>   从整个流程来看,Android字体切换的流程如下:</p>
<ol>
<li>当切换或添加新的语言时,会生成新的Configuration来替换原来的Configuration,并且修改项是可追寻的;</li>
<li>根据最新的Configuration来更新系统资源以及应用资源;</li>
<li>重启所有的Activity并更新到最新的资源;</li>
<li>完成语言切换。</li>
</ol>
<p>   以下为语言切换流程大致的时序图。</p>
<p><img src="/images/2017-11-19-3.png" alt="这里写图片描述"></p>
<blockquote>
<p>注:由于个人能力有限以及时间关系,有遗漏或错误的地方,还请批评指出,谢谢。</p>
</blockquote>
<h2 id="参考博客"><a href="#参考博客" class="headerlink" title="参考博客"></a>参考博客</h2><p><strong>   <a href="http://blog.csdn.net/wqhjfree/article/details/8244520" target="_blank" rel="external">wqhjfree</a></strong><br><strong>   <a href="http://blog.csdn.net/kong92917/article/details/51463567" target="_blank" rel="external">七号大蒜</a></strong></p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[读深入理解Java虚拟机]]></title>
<url>http://yoursite.com/2017/10/17/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3java%E8%99%9A%E6%8B%9F%E6%9C%BA-4/</url>
<content type="html"><![CDATA[<h1 id="Java类加载机制"><a href="#Java类加载机制" class="headerlink" title="Java类加载机制"></a>Java类加载机制</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><hr>
<p>   看到Java类加载机制这章,简单的做下读书笔记,加深自己对Java类加载机制的理解。</p>
<a id="more"></a>
<h2 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h2><hr>
<h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>   有Java开发经验的人,应该都知道.class文件里描述二进制数据的信息,需要加载到Jvm虚拟机中才能运行和使用。因此,类的加载机制就是指,JVM把所描述的类的信息从.class文件加载到内存中,进而进行数据验证,转化解析以及初始化,最终转化为JVM可以使用的类型。</p>
<p><strong>   类文件来源</strong></p>
<ul>
<li>从本地文件系统中加载.class文件</li>
<li>从网络访问中加载.class文件</li>
<li>从相应的Jar包中加载.class文件</li>
<li>将相应Java源文件动态编译.class文件</li>
<li>从专有的数据库中提取.class文件</li>
</ul>
<h3 id="类的生命周期"><a href="#类的生命周期" class="headerlink" title="类的生命周期"></a>类的生命周期</h3><p>   Android中有很多机制都有其特定的生命周期,比Activity、Service以及广播等。类加载机制也有其生命周期,从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载共七个阶段,流程如下图所示。</p>
<p><img src="/images/2017-10-17-2.png" alt=""></p>
<p>   其中准备、验证、解析3个部分统称为连接;类加载过程则包括了加载、验证、准备、解析、初始化这五个阶段;加载、验证、准备、初始化以及卸载这五个阶段的发生顺序是确定的,而解析阶段是不一定的,在某些时候它的发送时机是在初始化之后,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。</p>
<blockquote>
<p>注:另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。</p>
</blockquote>
<p>   下面分别介绍几个重要阶段的作用</p>
<p><strong>加载</strong></p>
<p>   其主要作用是查找并加载类的二进制数据。</p>
<p>   在加载阶段,虚拟机需要完成以下3件事情:</p>
<ol>
<li>通过一个类的全限定名来获取定义此类的二进制字节流;</li>
<li>将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;</li>
<li>在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。</li>
</ol>
<p>   对于整个生命周期来说,加载阶段可控性最强,我们可以通过使用系统提供的加载器来完成加载,也可以使用自己定义的加载器来加载。</p>
<p>   加载阶段完成之后二进制字节流就按照虚拟机所需的格式存储在方法区中,并且在Java堆中也创建一个类对象,方便我们通过该对象访问方法区中的数据。</p>
<p><strong>验证</strong></p>
<p>   其主要作用是确保被加载的类的正确性。</p>
<p>   验证阶段大致会完成4个阶段的检验动作:</p>
<ol>
<li>文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以魔术0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。</li>
<li>元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。</li>
<li>字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。</li>
<li>符号引用验证:确保解析动作能正确执行。</li>
</ol>
<p>   验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。</p>
<p><strong>准备</strong></p>
<p>   其主要作用是为类的静态变量分配内存,并将其初始化为默认值。</p>
<p>   这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> value=<span class="number">30</span>;</div></pre></td></tr></table></figure>
<p>   那么变量value在准备阶段过后的初始值为0,而不是30,因为这时候尚未开始执行任何Java方法,而把value赋值为30的putstatic指令是在程序编译后,存放于类构造器<clinit>()方法之中的,所以把value赋值为30的动作将在初始化阶段才会执行。</p>
<p><strong>解析</strong></p>
<p>   解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。</p>
<p>   符号引用就是一组符号来描述目标,可以是任何字面量。</p>
<p>   直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。</p>
<p><strong>初始化</strong></p>
<p>   类初始化阶段是类加载过程的最后一步,在这个阶段JVM负责对类进行初始化,主要对类变量进行初始化,也可以说初始化阶段是执行类构造器<clinit>()方法的过程。在Java中对类变量进行初始值设定有两种方式:</p>
<ol>
<li>声明类变量是指定初始值</li>
<li>使用静态代码块为类变量指定初始值</li>
</ol>
<p>   <strong>类初始化时机</strong> </p>
<ul>
<li>创建类实例。也就是new的方式</li>
<li>调用某个类的类方法</li>
<li>访问某个类或接口的类变量,或为该类变量赋值</li>
<li>使用反射方式强制创建某个类或接口对应的java.lang.Class对象</li>
<li>初始化某个类的子类,则其父类也会被初始化</li>
<li>直接使用java.exe命令来运行某个主类</li>
</ul>
<p>   <strong>类初始化步骤</strong></p>
<ol>
<li>假如这个类还没有被加载和连接,则程序先加载并连接该类;</li>
<li>假如该类的直接父类还没有被初始化,则先初始化其直接父类;</li>
<li>假如类中有初始化语句,则系统依次执行这些初始化语句。</li>
</ol>
<h3 id="类的加载器"><a href="#类的加载器" class="headerlink" title="类的加载器"></a>类的加载器</h3><p>   类加载器(ClassLoader),顾名思义,即加载类的东西。其功能就是将类的字节码文件加载到内存中,并对字节码进行解析生成对应的类对象,类的动态加载就是使用类加载器来实现的。</p>
<h4 id="JVM类加载机制"><a href="#JVM类加载机制" class="headerlink" title="JVM类加载机制"></a>JVM类加载机制</h4><ul>
<li>全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。</li>
<li>父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。</li>
<li>缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效。</li>
</ul>
<h4 id="类加载器"><a href="#类加载器" class="headerlink" title="类加载器"></a>类加载器</h4><p>   Java 提供三种类型的系统类加载器:</p>
<ol>
<li>启动类加载器(Bootstrap ClassLoader):由C++实现,不是ClassLoader子类,加载 JAVA_HOME/lib 目录中的文件,或-Xbootclasspath指定目录下的能被虚拟机识别的类库。</li>
<li>扩展类加载器(ExtClassLoader):负责加载JAVA_HOME\lib\ext目录中或系统变量 java.ext.dirs 所指定的目录中的所有类库。</li>
<li>应用类加载器(AppClassLoader):负责加载用户类路径中的文件,一般情况下这个就是程序中默认的类加载器。</li>
</ol>
<p>   用户可以直接使用扩展类加载器或系统类加载器来加载自己的类,但是用户无法直接使用启动类加载器,除了这两种类加载器以外,用户也可以自定义类加载器(CustomClassLoader),加载流程如下图所示:</p>
<p><img src="/images/2017-10-17-1.png" alt=""></p>
<hr>
<p><strong>参考资料</strong></p>
<p>《深入理解Java虚拟机:JVM高级特性与最佳实践 第2版》 周志明 著.</p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[Android字体加载原理总结]]></title>
<url>http://yoursite.com/2017/08/12/Android%E5%AD%97%E4%BD%93%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86%E6%80%BB%E7%BB%93/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><hr>
<p>   之前在处理系统字体问题的时候,可借鉴的资料很少,遇到了很多坑,不得不了解Android字体加载原理,现抽空写一篇总结,来加深自己对这块的理解。</p>
<a id="more"></a>
<h2 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h2><hr>
<h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>   Android字体系统是由底层的Android 2D图形引擎Skia来实现的,Android3.0之后逐渐使用了新的硬件绘图模块hwui,在5.0之后正式取代了Skia,因此不同版本的系统其字体加载机制有些差异,按照Google的API Level来看,大体可以分为三个阶段:</p>
<ol>
<li>Android4.0以下的系统</li>
<li>Android4.0到Android4.4的系统</li>
<li>Android5.0以上的系统</li>
</ol>
<p>   当然这每个阶段中,可能也存在些许小差异,但大方向是没变化的,本文主要对Android5.0以上的系统的字体加载机制进行描述,围绕系统字体配置文件解析与字体加载相关内容,不涉及系统运行库的实现细节。</p>
<blockquote>
<p>注:浏览器及webView中的字体有单独的字体系统</p>
</blockquote>
<p>   下面将从Java层面、Native层面、文件配置系统三个部分来阐述Android字体加载原理。</p>
<h3 id="Java层面"><a href="#Java层面" class="headerlink" title="Java层面"></a>Java层面</h3><p>   有研究过Android的人大概都有了解,Android的Java层封装了构建应用程序时可能会用到的各种Api。而在字体这部分,起主要作用的是android.graphics.Typeface,其主要负责字体加载以及对上层提供创建字体功能的调用,下面将着重分析该类的调用过程。</p>
<p>   首先,在Android启动的过程中,ZygoteInit类中的main()方法会调用加载方法preload(),对各种类、链接库、资源等进行初始化,具体代码如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String argv[])</span> </span>{</div><div class="line"> ...</div><div class="line"> </div><div class="line"> registerZygoteSocket(socketName);</div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"ZygotePreload"</span>);</div><div class="line"> EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,</div><div class="line"> SystemClock.uptimeMillis());</div><div class="line"> <span class="comment">//调用加载方法</span></div><div class="line"> preload();</div><div class="line"> EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,</div><div class="line"> SystemClock.uptimeMillis());</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">//主要用于加载并初始化各种类、链接库、资源等。</span></div><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">preload</span><span class="params">()</span> </span>{</div><div class="line"> Log.d(TAG, <span class="string">"begin preload"</span>);</div><div class="line"> <span class="comment">//Systrace开始tag</span></div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"BeginIcuCachePinning"</span>);</div><div class="line"> <span class="comment">//开始Icu缓存开销</span></div><div class="line"> beginIcuCachePinning();</div><div class="line"> <span class="comment">//Systrace结束tag</span></div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"PreloadClasses"</span>);</div><div class="line"> <span class="comment">//预加载Classes</span></div><div class="line"> preloadClasses();</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"PreloadResources"</span>);</div><div class="line"> <span class="comment">//预加载resources</span></div><div class="line"> preloadResources();</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"PreloadOpenGL"</span>);</div><div class="line"> <span class="comment">//预加载openGL</span></div><div class="line"> preloadOpenGL();</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"> <span class="comment">//加载分享库</span></div><div class="line"> preloadSharedLibraries();</div><div class="line"> <span class="comment">//加载文本资源</span></div><div class="line"> preloadTextResources();</div><div class="line"> <span class="comment">// Ask the WebViewFactory to do any initialization that must run in the zygote process,</span></div><div class="line"> <span class="comment">// for memory sharing purposes.、</span></div><div class="line"> WebViewFactory.prepareWebViewInZygote();</div><div class="line"> endIcuCachePinning();</div><div class="line"> warmUpJcaProviders();</div><div class="line"> Log.d(TAG, <span class="string">"end preload"</span>);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   其中preloadClasses()方法会加载并初始化一些系统常用的API类,这些类都是位于frameworks/base/preloaded-classes文件中,当然也包括Typeface类。</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * Performs Zygote process initialization. Loads and initializes</div><div class="line"> * commonly used classes.</div><div class="line"> *</div><div class="line"> * Most classes only cause a few hundred bytes to be allocated, but</div><div class="line"> * a few will allocate a dozen Kbytes (in one case, 500+K).</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">preloadClasses</span><span class="params">()</span> </span>{</div><div class="line"> </div><div class="line"> ... </div><div class="line"> </div><div class="line"> InputStream is;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> is = <span class="keyword">new</span> FileInputStream(PRELOADED_CLASSES);</div><div class="line"> } <span class="keyword">catch</span> (FileNotFoundException e) {</div><div class="line"> Log.e(TAG, <span class="string">"Couldn't find "</span> + PRELOADED_CLASSES + <span class="string">"."</span>);</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> BufferedReader br</div><div class="line"> = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(is), <span class="number">256</span>);</div><div class="line"> </div><div class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</div><div class="line"> String line;</div><div class="line"> <span class="keyword">while</span> ((line = br.readLine()) != <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// Skip comments and blank lines.</span></div><div class="line"> line = line.trim();</div><div class="line"> <span class="keyword">if</span> (line.startsWith(<span class="string">"#"</span>) || line.equals(<span class="string">""</span>)) {</div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> }</div><div class="line"> </div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"PreloadClass "</span> + line);</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">false</span>) {</div><div class="line"> Log.v(TAG, <span class="string">"Preloading "</span> + line + <span class="string">"..."</span>);</div><div class="line"> }</div><div class="line"> <span class="comment">// Load and explicitly initialize the given class. Use</span></div><div class="line"> <span class="comment">// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups</span></div><div class="line"> <span class="comment">// (to derive the caller's class-loader). Use true to force initialization, and</span></div><div class="line"> <span class="comment">// null for the boot classpath class-loader (could as well cache the</span></div><div class="line"> <span class="comment">// class-loader of this class in a variable).</span></div><div class="line"> Class.forName(line, <span class="keyword">true</span>, <span class="keyword">null</span>);</div><div class="line"> count++;</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line">}</div></pre></td></tr></table></figure>
<p>   从上面的代码可以看到,Android通过反射机制Class.forName(“android.graphics.Typeface”)加载了Typeface类,在加载的同时,会调用类中的static方法块。如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">static</span> {</div><div class="line"> <span class="comment">//初始化系统字体</span></div><div class="line"> init();</div><div class="line"> <span class="comment">// Set up defaults and typefaces exposed in public API</span></div><div class="line"> DEFAULT = create((String) <span class="keyword">null</span>, <span class="number">0</span>);</div><div class="line"> DEFAULT_BOLD = create((String) <span class="keyword">null</span>, Typeface.BOLD);</div><div class="line"> SANS_SERIF = create(<span class="string">"sans-serif"</span>, <span class="number">0</span>);</div><div class="line"> SERIF = create(<span class="string">"serif"</span>, <span class="number">0</span>);</div><div class="line"> MONOSPACE = create(<span class="string">"monospace"</span>, <span class="number">0</span>);</div><div class="line"></div><div class="line"> sDefaults = <span class="keyword">new</span> Typeface[] {</div><div class="line"> DEFAULT,</div><div class="line"> DEFAULT_BOLD,</div><div class="line"> create((String) <span class="keyword">null</span>, Typeface.ITALIC),</div><div class="line"> create((String) <span class="keyword">null</span>, Typeface.BOLD_ITALIC),</div><div class="line"> };</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Typeface <span class="title">create</span><span class="params">(String familyName, <span class="keyword">int</span> style)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (sSystemFontMap != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">return</span> create(sSystemFontMap.get(familyName), style);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Typeface <span class="title">create</span><span class="params">(Typeface family, <span class="keyword">int</span> style)</span> </span>{</div><div class="line"></div><div class="line"> ...</div><div class="line"></div><div class="line"> typeface = <span class="keyword">new</span> Typeface(nativeCreateFromTypeface(ni, style));</div><div class="line"></div><div class="line"> ...</div><div class="line"> <span class="keyword">return</span> typeface;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   在上面的static方法块中,最终通过调用Native层方法nativeCreateFromTypeface(),来初始化系统字体并且设置默认的系统字体以及字体样式,可以从上面的方法看出系统默认创建sans-serif(无衬线字体),serif(衬线字体),monospace(等宽字体)三种字体,并且通过create第一个参数为null,来创建默认字体的四种style:normal,bold,italic,bolditalic。</p>
<blockquote>
<p>注:这里需要注意的是,Android4.x版本的系统与Android5.0以上的版本所调用的API基本一致,但是native层确有很大的变,这是由于5.0以上的系统添加了一个新的方法init(),其主要实现了解析系统字体配置文件,并据此加载系统字体。而Android4.x版本是在native层实现的。</p>
</blockquote>
<p>   因为现在Android阵营已经基本上都是5.0以上的系统了,所以5.0以下版本的加载不在解释。下面我们来看init()方法的具体逻辑:</p>
<figure class="highlight java"><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><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">/*</span></div><div class="line"> * (non-Javadoc)</div><div class="line"> *</div><div class="line"> * This should only be called once, from the static class initializer block.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>{</div><div class="line"> <span class="comment">// Load font config and initialize Minikin state</span></div><div class="line"> <span class="comment">//获取系统字体配置文件位置放置于system/etc目录下</span></div><div class="line"> File systemFontConfigLocation = getSystemFontConfigLocation();</div><div class="line"> <span class="comment">//获取配置文件fonts.xml</span></div><div class="line"> File configFilename = <span class="keyword">new</span> File(systemFontConfigLocation, FONTS_CONFIG);</div><div class="line"> <span class="comment">//以下代码是对fonts.xml的解析,即是对系统字体的解析</span></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> FileInputStream fontsIn = <span class="keyword">new</span> FileInputStream(configFilename);</div><div class="line"> FontListParser.Config fontConfig = FontListParser.parse(fontsIn);</div><div class="line"></div><div class="line"> Map<String, ByteBuffer> bufferForPath = <span class="keyword">new</span> HashMap<String, ByteBuffer>();</div><div class="line"> <span class="comment">//用来承载fonts.xml中的每个family节点</span></div><div class="line"> List<FontFamily> familyList = <span class="keyword">new</span> ArrayList<FontFamily>();</div><div class="line"> <span class="comment">// Note that the default typeface is always present in the fallback list;</span></div><div class="line"> <span class="comment">// this is an enhancement from pre-Minikin behavior.</span></div><div class="line"> <span class="comment">//从每个family节点中解析字体样式,这里解析系统默认字体</span></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < fontConfig.families.size(); i++) {</div><div class="line"> FontListParser.Family f = fontConfig.families.get(i);</div><div class="line"> <span class="keyword">if</span> (i == <span class="number">0</span> || f.name == <span class="keyword">null</span>) {</div><div class="line"> familyList.add(makeFamilyFromParsed(f, bufferForPath));</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">//系统默认字体集合</span></div><div class="line"> sFallbackFonts = familyList.toArray(<span class="keyword">new</span> FontFamily[familyList.size()]);</div><div class="line"> <span class="comment">//设置默认系统字体</span></div><div class="line"> setDefault(Typeface.createFromFamilies(sFallbackFonts));</div><div class="line"> <span class="comment">//这里加载系统字体,包括默认字体</span></div><div class="line"> Map<String, Typeface> systemFonts = <span class="keyword">new</span> HashMap<String, Typeface>();</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < fontConfig.families.size(); i++) {</div><div class="line"> Typeface typeface;</div><div class="line"> FontListParser.Family f = fontConfig.families.get(i);</div><div class="line"> <span class="keyword">if</span> (f.name != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">if</span> (i == <span class="number">0</span>) {</div><div class="line"> <span class="comment">// The first entry is the default typeface; no sense in</span></div><div class="line"> <span class="comment">// duplicating the corresponding FontFamily.</span></div><div class="line"> typeface = sDefaultTypeface;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//从每个family节点中解析字体</span></div><div class="line"> FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);</div><div class="line"> FontFamily[] families = { fontFamily };</div><div class="line"> typeface = Typeface.createFromFamiliesWithDefault(families);</div><div class="line"> }</div><div class="line"> <span class="comment">//解析的字体添加到系统字体中</span></div><div class="line"> systemFonts.put(f.name, typeface);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">//通过权重别号解析字体,别名必须与字体对应</span></div><div class="line"> <span class="keyword">for</span> (FontListParser.Alias alias : fontConfig.aliases) {</div><div class="line"> Typeface base = systemFonts.get(alias.toName);</div><div class="line"> Typeface newFace = base;</div><div class="line"> <span class="keyword">int</span> weight = alias.weight;</div><div class="line"> <span class="keyword">if</span> (weight != <span class="number">400</span>) {</div><div class="line"> newFace = <span class="keyword">new</span> Typeface(nativeCreateWeightAlias(base.native_instance, weight));</div><div class="line"> }</div><div class="line"> systemFonts.put(alias.name, newFace);</div><div class="line"> }</div><div class="line"> <span class="comment">//系统字体集合</span></div><div class="line"> sSystemFontMap = systemFonts;</div><div class="line"></div><div class="line"> } <span class="keyword">catch</span> (RuntimeException e) {</div><div class="line"> Log.w(TAG, <span class="string">"Didn't create default family (most likely, non-Minikin build)"</span>, e);</div><div class="line"> <span class="comment">// <span class="doctag">TODO:</span> normal in non-Minikin case, remove or make error when Minikin-only</span></div><div class="line"> } <span class="keyword">catch</span> (FileNotFoundException e) {</div><div class="line"> Log.e(TAG, <span class="string">"Error opening "</span> + configFilename, e);</div><div class="line"> } <span class="keyword">catch</span> (IOException e) {</div><div class="line"> Log.e(TAG, <span class="string">"Error reading "</span> + configFilename, e);</div><div class="line"> } <span class="keyword">catch</span> (XmlPullParserException e) {</div><div class="line"> Log.e(TAG, <span class="string">"XML parse exception for "</span> + configFilename, e);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   通过以上代码,可以看出,系统解析过程中,一共有三种字体模式。一种的是系统默认字体;一种是系统字体,所有字体,包括自己添加的字体;一种是设置别名的字体,字体的衍生。而这三种字体都会在init()中被加载,而它们加载主要涉及以下方法。</p>
<figure class="highlight java"><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><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">//通过family节点解析FontFamily</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> FontFamily <span class="title">makeFamilyFromParsed</span><span class="params">(FontListParser.Family family,</span></span></div><div class="line"> Map<String, ByteBuffer> bufferForPath) {</div><div class="line"> <span class="comment">//这里的lang表示国家缩写,variant表示字体的排列格式一般有compact与elegant两种</span></div><div class="line"> FontFamily fontFamily = <span class="keyword">new</span> FontFamily(family.lang, family.variant);</div><div class="line"> <span class="keyword">for</span> (FontListParser.Font font : family.fonts) {</div><div class="line"> ByteBuffer fontBuffer = bufferForPath.get(font.fontName);</div><div class="line"> <span class="keyword">if</span> (fontBuffer == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">try</span> (FileInputStream file = <span class="keyword">new</span> FileInputStream(font.fontName)) {</div><div class="line"> FileChannel fileChannel = file.getChannel();</div><div class="line"> <span class="keyword">long</span> fontSize = fileChannel.size();</div><div class="line"> fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, <span class="number">0</span>, fontSize);</div><div class="line"> bufferForPath.put(font.fontName, fontBuffer);</div><div class="line"> } <span class="keyword">catch</span> (IOException e) {</div><div class="line"> Log.e(TAG, <span class="string">"Error mapping font file "</span> + font.fontName);</div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (!fontFamily.addFontWeightStyle(fontBuffer, font.ttcIndex, font.axes,</div><div class="line"> font.weight, font.isItalic)) {</div><div class="line"> Log.e(TAG, <span class="string">"Error creating font "</span> + font.fontName + <span class="string">"#"</span> + font.ttcIndex);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> fontFamily;</div><div class="line">}</div><div class="line"><span class="comment">/*</span></div><div class="line">以下是通过不同的格式解析出不同的family</div><div class="line">*/</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">FontFamily</span><span class="params">()</span> </span>{</div><div class="line"> mNativePtr = nCreateFamily(<span class="keyword">null</span>, <span class="number">0</span>);</div><div class="line"> <span class="keyword">if</span> (mNativePtr == <span class="number">0</span>) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"error creating native FontFamily"</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">FontFamily</span><span class="params">(String lang, String variant)</span> </span>{</div><div class="line"> <span class="keyword">int</span> varEnum = <span class="number">0</span>;</div><div class="line"> <span class="keyword">if</span> (<span class="string">"compact"</span>.equals(variant)) {</div><div class="line"> varEnum = <span class="number">1</span>;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">"elegant"</span>.equals(variant)) {</div><div class="line"> varEnum = <span class="number">2</span>;</div><div class="line"> }</div><div class="line"> mNativePtr = nCreateFamily(lang, varEnum);</div><div class="line"> <span class="keyword">if</span> (mNativePtr == <span class="number">0</span>) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"error creating native FontFamily"</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable </span>{</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> nUnrefFamily(mNativePtr);</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> <span class="keyword">super</span>.finalize();</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">addFont</span><span class="params">(String path, <span class="keyword">int</span> ttcIndex)</span> </span>{</div><div class="line"> <span class="keyword">try</span> (FileInputStream file = <span class="keyword">new</span> FileInputStream(path)) {</div><div class="line"> FileChannel fileChannel = file.getChannel();</div><div class="line"> <span class="keyword">long</span> fontSize = fileChannel.size();</div><div class="line"> ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, <span class="number">0</span>, fontSize);</div><div class="line"> <span class="keyword">return</span> nAddFont(mNativePtr, fontBuffer, ttcIndex);</div><div class="line"> } <span class="keyword">catch</span> (IOException e) {</div><div class="line"> Log.e(TAG, <span class="string">"Error mapping font file "</span> + path);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">addFontWeightStyle</span><span class="params">(ByteBuffer font, <span class="keyword">int</span> ttcIndex, List<FontListParser.Axis> axes,</span></span></div><div class="line"> <span class="keyword">int</span> weight, <span class="keyword">boolean</span> style) {</div><div class="line"> <span class="keyword">return</span> nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">addFontFromAsset</span><span class="params">(AssetManager mgr, String path)</span> </span>{</div><div class="line"> <span class="keyword">return</span> nAddFontFromAsset(mNativePtr, mgr, path);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">long</span> <span class="title">nCreateFamily</span><span class="params">(String lang, <span class="keyword">int</span> variant)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">nUnrefFamily</span><span class="params">(<span class="keyword">long</span> nativePtr)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">boolean</span> <span class="title">nAddFont</span><span class="params">(<span class="keyword">long</span> nativeFamily, ByteBuffer font, <span class="keyword">int</span> ttcIndex)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">boolean</span> <span class="title">nAddFontWeightStyle</span><span class="params">(<span class="keyword">long</span> nativeFamily, ByteBuffer font,</span></span></div><div class="line"> <span class="keyword">int</span> ttcIndex, List<FontListParser.Axis> listOfAxis,</div><div class="line"> <span class="keyword">int</span> weight, <span class="keyword">boolean</span> isItalic);</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">boolean</span> <span class="title">nAddFontFromAsset</span><span class="params">(<span class="keyword">long</span> nativeFamily, AssetManager mgr,</span></span></div><div class="line"> String path);</div></pre></td></tr></table></figure>
<figure class="highlight java"><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"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * Create a new typeface from an array of font families.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> families array of font families</div><div class="line"> * <span class="doctag">@hide</span></div><div class="line"> */</div><div class="line"><span class="comment">//通过FontFamily解析创建字体</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Typeface <span class="title">createFromFamilies</span><span class="params">(FontFamily[] families)</span> </span>{</div><div class="line"> <span class="keyword">long</span>[] ptrArray = <span class="keyword">new</span> <span class="keyword">long</span>[families.length];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < families.length; i++) {</div><div class="line"> ptrArray[i] = families[i].mNativePtr;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Typeface(nativeCreateFromArray(ptrArray));</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * Create a new typeface from an array of font families, including</div><div class="line"> * also the font families in the fallback list.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> families array of font families</div><div class="line"> * <span class="doctag">@hide</span></div><div class="line"> */</div><div class="line"><span class="comment">//通过FontFamily解析创建字体</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Typeface <span class="title">createFromFamiliesWithDefault</span><span class="params">(FontFamily[] families)</span> </span>{</div><div class="line"> <span class="keyword">long</span>[] ptrArray = <span class="keyword">new</span> <span class="keyword">long</span>[families.length + sFallbackFonts.length];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < families.length; i++) {</div><div class="line"> ptrArray[i] = families[i].mNativePtr;</div><div class="line"> }</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < sFallbackFonts.length; i++) {</div><div class="line"> ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Typeface(nativeCreateFromArray(ptrArray));</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   从上面的代码可看到,系统通过解析/system/etc/fonts.xml(字体配置文件),然后接收Native层方法回调上来的值,来创建指定的Typeface即字体,保存在sSystemFontMap中。而相关native方法列表以及注册(在frameworks/base/core/jni/android/graphics/Typeface.cpp中注册)如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">long</span> <span class="title">nativeCreateFromTypeface</span><span class="params">(<span class="keyword">long</span> native_instance, <span class="keyword">int</span> style)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">long</span> <span class="title">nativeCreateWeightAlias</span><span class="params">(<span class="keyword">long</span> native_instance, <span class="keyword">int</span> weight)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">nativeUnref</span><span class="params">(<span class="keyword">long</span> native_instance)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">int</span> <span class="title">nativeGetStyle</span><span class="params">(<span class="keyword">long</span> native_instance)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">long</span> <span class="title">nativeCreateFromArray</span><span class="params">(<span class="keyword">long</span>[] familyArray)</span></span>;</div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">nativeSetDefault</span><span class="params">(<span class="keyword">long</span> native_instance)</span></span>;</div><div class="line"></div><div class="line"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span></div><div class="line"></div><div class="line"><span class="keyword">static</span> <span class="keyword">const</span> JNINativeMethod gTypefaceMethods[] = {</div><div class="line"> { <span class="string">"nativeCreateFromTypeface"</span>, <span class="string">"(JI)J"</span>, (<span class="keyword">void</span>*)Typeface_createFromTypeface },</div><div class="line"> { <span class="string">"nativeCreateWeightAlias"</span>, <span class="string">"(JI)J"</span>, (<span class="keyword">void</span>*)Typeface_createWeightAlias },</div><div class="line"> { <span class="string">"nativeUnref"</span>, <span class="string">"(J)V"</span>, (<span class="keyword">void</span>*)Typeface_unref },</div><div class="line"> { <span class="string">"nativeGetStyle"</span>, <span class="string">"(J)I"</span>, (<span class="keyword">void</span>*)Typeface_getStyle },</div><div class="line"> { <span class="string">"nativeCreateFromArray"</span>, <span class="string">"([J)J"</span>,</div><div class="line"> (<span class="keyword">void</span>*)Typeface_createFromArray },</div><div class="line"> { <span class="string">"nativeSetDefault"</span>, <span class="string">"(J)V"</span>, (<span class="keyword">void</span>*)Typeface_setDefault },</div><div class="line">};</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">register_android_graphics_Typeface</span><span class="params">(JNIEnv* env)</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">return</span> RegisterMethodsOrDie(env, <span class="string">"android/graphics/Typeface"</span>, gTypefaceMethods,</div><div class="line"> NELEM(gTypefaceMethods));</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   最终,通过这一层的关系,调用到Native层的方法。</p>
<p>   到此,字体加载Java层面就结束了,下面将调用Native层的方法。</p>
<h3 id="Native层面"><a href="#Native层面" class="headerlink" title="Native层面"></a>Native层面</h3><p>   Native层主要是skia图形引擎的Android移植版,项目源码位于external\skia目录下。</p>
<p>   在Android4.X版本中主要是用skia来进行软件绘制,所以解析配置文件并加载字体是在skia中完成,这里不在描述过程,可以参看相关博客中的描述。而由于绘制性能等问题,Android5.0之后使用了新的硬件绘图模块hwui,hwui主要则是使用opengles来进行gpu硬件绘图,提升整个系统的绘制性能。</p>
<p>   在上述Java层调用过程后,字体加载指向了Native层。在Native层调用首先进入jni/android/graphics/Typeface.cpp,调用对应的方法,然后进入hwui/Typeface.h和hwui/Typeface.cpp中定制的函数,从而解析配置文件并加载字体。</p>
<figure class="highlight cpp"><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><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//jni/android/graphics/Typeface.cpp</span></div><div class="line"></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"jni.h"</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"core_jni_helpers.h"</span></span></div><div class="line"></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"GraphicsJNI.h"</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ScopedPrimitiveArray.h"</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"SkTypeface.h"</span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><android_runtime/android_util_AssetManager.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><androidfw/AssetManager.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><hwui/Typeface.h></span></span></div><div class="line"></div><div class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> android;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">static</span> jlong <span class="title">Typeface_createFromTypeface</span><span class="params">(JNIEnv* env, jobject, jlong familyHandle, jint style)</span> </span>{</div><div class="line"> Typeface* family = <span class="keyword">reinterpret_cast</span><Typeface*>(familyHandle);</div><div class="line"> Typeface* face = Typeface::createFromTypeface(family, (SkTypeface::Style)style);</div><div class="line"> <span class="comment">// <span class="doctag">TODO:</span> the following logic shouldn't be necessary, the above should always succeed.</span></div><div class="line"> <span class="comment">// Try to find the closest matching font, using the standard heuristic</span></div><div class="line"> <span class="keyword">if</span> (<span class="literal">NULL</span> == face) {</div><div class="line"> face = Typeface::createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));</div><div class="line"> }</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; <span class="literal">NULL</span> == face && i < <span class="number">4</span>; i++) {</div><div class="line"> face = Typeface::createFromTypeface(family, (SkTypeface::Style)i);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">reinterpret_cast</span><jlong>(face);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">static</span> jlong <span class="title">Typeface_createWeightAlias</span><span class="params">(JNIEnv* env, jobject, jlong familyHandle, jint weight)</span> </span>{</div><div class="line"> Typeface* family = <span class="keyword">reinterpret_cast</span><Typeface*>(familyHandle);</div><div class="line"> Typeface* face = Typeface::createWeightAlias(family, weight);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">reinterpret_cast</span><jlong>(face);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Typeface_unref</span><span class="params">(JNIEnv* env, jobject obj, jlong faceHandle)</span> </span>{</div><div class="line"> Typeface* face = <span class="keyword">reinterpret_cast</span><Typeface*>(faceHandle);</div><div class="line"> <span class="keyword">if</span> (face != <span class="literal">NULL</span>) {</div><div class="line"> face->unref();</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">static</span> jint <span class="title">Typeface_getStyle</span><span class="params">(JNIEnv* env, jobject obj, jlong faceHandle)</span> </span>{</div><div class="line"> Typeface* face = <span class="keyword">reinterpret_cast</span><Typeface*>(faceHandle);</div><div class="line"> <span class="keyword">return</span> face->fSkiaStyle;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">static</span> jlong <span class="title">Typeface_createFromArray</span><span class="params">(JNIEnv *env, jobject, jlongArray familyArray)</span> </span>{</div><div class="line"> <span class="function">ScopedLongArrayRO <span class="title">families</span><span class="params">(env, familyArray)</span></span>;</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">vector</span><FontFamily*> familyVec;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i < families.size(); i++) {</div><div class="line"> FontFamily* family = <span class="keyword">reinterpret_cast</span><FontFamily*>(families[i]);</div><div class="line"> familyVec.push_back(family);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">reinterpret_cast</span><jlong>(Typeface::createFromFamilies(familyVec));</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">Typeface_setDefault</span><span class="params">(JNIEnv *env, jobject, jlong faceHandle)</span> </span>{</div><div class="line"> Typeface* face = <span class="keyword">reinterpret_cast</span><Typeface*>(faceHandle);</div><div class="line"> <span class="keyword">return</span> Typeface::setDefault(face);</div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight cpp"><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></pre></td><td class="code"><pre><div class="line"><span class="comment">//hwui/Typeface.h</span></div><div class="line"></div><div class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_</span></div><div class="line"><span class="meta">#<span class="meta-keyword">define</span> _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_</span></div><div class="line"></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"SkTypeface.h"</span></span></div><div class="line"></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cutils/compiler.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><minikin/FontCollection.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></div><div class="line"></div><div class="line"><span class="keyword">namespace</span> android {</div><div class="line"></div><div class="line"><span class="keyword">struct</span> ANDROID_API Typeface {</div><div class="line"> FontCollection *fFontCollection;</div><div class="line"></div><div class="line"> <span class="comment">// style used for constructing and querying Typeface objects</span></div><div class="line"> SkTypeface::Style fSkiaStyle;</div><div class="line"> <span class="comment">// base weight in CSS-style units, 100..900</span></div><div class="line"> <span class="keyword">int</span> fBaseWeight;</div><div class="line"></div><div class="line"> <span class="comment">// resolved style actually used for rendering</span></div><div class="line"> FontStyle fStyle;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">void</span> <span class="title">unref</span><span class="params">()</span></span>;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">static</span> Typeface* <span class="title">resolveDefault</span><span class="params">(Typeface* src)</span></span>;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">static</span> Typeface* <span class="title">createFromTypeface</span><span class="params">(Typeface* src, SkTypeface::Style style)</span></span>;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">static</span> Typeface* <span class="title">createWeightAlias</span><span class="params">(Typeface* src, <span class="keyword">int</span> baseweight)</span></span>;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">static</span> Typeface* <span class="title">createFromFamilies</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">vector</span><FontFamily*>& families)</span></span>;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setDefault</span><span class="params">(Typeface* face)</span></span>;</div><div class="line">};</div><div class="line">}</div><div class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">// _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_</span></span></div></pre></td></tr></table></figure>
<p>   Native层的c/c++方法调用比较复杂,通过一系列的调用,返回值给Java层,这里就不在阐述,有兴趣的人可以自己下个源码深入理解下,到这里Android的字体加载原理基本完成了,不得不感叹Google工程师的丰功伟绩。</p>
<h3 id="文件配置系统"><a href="#文件配置系统" class="headerlink" title="文件配置系统"></a>文件配置系统</h3><p>   前面介绍的是加载的原理,现在简单的描述下字体加载过程中所用到的字体加载文件。</p>
<p>   在4.x版本的系统字体配置文件位于system/etc/system_fonts.xml,备用字体配置文件位于system/etc/fallback_fonts.xml和vendor/etc/fallback_fonts.xml。而5.0以上的版本的系统字体及备用字体配置均位于system/etc/fonts.xml文件中,下面展示部分fonts.xml内容。</p>
<figure class="highlight xml"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="tag"><<span class="name">familyset</span> <span class="attr">version</span>=<span class="string">"22"</span>></span></div><div class="line"> <span class="comment"><!-- first font is default --></span></div><div class="line"> <span class="tag"><<span class="name">family</span> <span class="attr">name</span>=<span class="string">"sans-serif"</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"100"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>Roboto-Thin.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"100"</span> <span class="attr">style</span>=<span class="string">"italic"</span>></span>Roboto-ThinItalic.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"300"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>Roboto-Light.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"300"</span> <span class="attr">style</span>=<span class="string">"italic"</span>></span>Roboto-LightItalic.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>Roboto-Regular.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"italic"</span>></span>Roboto-Italic.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"500"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>Roboto-Medium.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"500"</span> <span class="attr">style</span>=<span class="string">"italic"</span>></span>Roboto-MediumItalic.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"900"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>Roboto-Black.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"900"</span> <span class="attr">style</span>=<span class="string">"italic"</span>></span>Roboto-BlackItalic.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"700"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>Roboto-Bold.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"700"</span> <span class="attr">style</span>=<span class="string">"italic"</span>></span>Roboto-BoldItalic.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"></<span class="name">family</span>></span></div><div class="line"></div><div class="line"> <span class="comment"><!-- Note that aliases must come after the fonts they reference. --></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"sans-serif-thin"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> <span class="attr">weight</span>=<span class="string">"100"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"sans-serif-light"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> <span class="attr">weight</span>=<span class="string">"300"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"sans-serif-medium"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> <span class="attr">weight</span>=<span class="string">"500"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"sans-serif-black"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> <span class="attr">weight</span>=<span class="string">"900"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"arial"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"helvetica"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"tahoma"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">alias</span> <span class="attr">name</span>=<span class="string">"verdana"</span> <span class="attr">to</span>=<span class="string">"sans-serif"</span> /></span></div><div class="line"> </div><div class="line">...</div><div class="line"></div><div class="line"> <span class="comment"><!-- fallback fonts --></span></div><div class="line"> <span class="tag"><<span class="name">family</span> <span class="attr">lang</span>=<span class="string">"und-Arab"</span> <span class="attr">variant</span>=<span class="string">"elegant"</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoNaskhArabic-Regular.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"700"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoNaskhArabic-Bold.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"></<span class="name">family</span>></span></div><div class="line"> <span class="tag"><<span class="name">family</span> <span class="attr">lang</span>=<span class="string">"und-Arab"</span> <span class="attr">variant</span>=<span class="string">"compact"</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoNaskhArabicUI-Regular.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"700"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoNaskhArabicUI-Bold.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"></<span class="name">family</span>></span></div><div class="line"> <span class="tag"><<span class="name">family</span> <span class="attr">lang</span>=<span class="string">"und-Ethi"</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoSansEthiopic-Regular.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"700"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoSansEthiopic-Bold.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"></<span class="name">family</span>></span></div><div class="line"> <span class="comment"><!-- 简体中文字体 --></span></div><div class="line"> <span class="tag"><<span class="name">family</span> <span class="attr">lang</span>=<span class="string">"zh-Hans"</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoSansSC-Regular.otf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"></<span class="name">family</span>></span></div><div class="line"> <span class="comment"><!-- 繁体中文字体 --></span></div><div class="line"> <span class="tag"><<span class="name">family</span> <span class="attr">lang</span>=<span class="string">"zh-Hant"</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>NotoSansTC-Regular.otf<span class="tag"></<span class="name">font</span>></span></div><div class="line"> <span class="tag"></<span class="name">family</span>></span></div></pre></td></tr></table></figure>
<p>   如上所示,第一个family节点为系统默认字体。nameset节点的各个name子节点定义可用的字体名称,fileset节点的file子节点分别对应normal、bold、italic、bold-italic四种字体样式,如果file节点个数少于四个,相应字体样式会对应已有兄弟file节点的字体文件。family属性中lang代表国家的缩写,系统在切换语言的时候会从加载的字体中匹配国家的缩写,从而调出对于的系统字体、variant属性指的是字体的排列格式通常有compact(紧凑型)以及(简洁型)。</p>
<p>   fallback_fonts配置了系统备用字体。只有在系统内置字体中找不到相应字符时,才会到备用字体中去寻找,family节点的顺序对应搜索顺序,搜索匹配规则采用BCP47的定义。</p>
<p>   5.0以后的字体配置文件与之前版本的相比,最大的一个改进是将之前字体样式中的单一bold样式改为各种不同过的weight,这样可以更加细粒度的控制字重。</p>
<h3 id="为系统添加新的字体"><a href="#为系统添加新的字体" class="headerlink" title="为系统添加新的字体"></a>为系统添加新的字体</h3><p>   现在的手机产商都对Android系统进行了定制,当然也会加上属于自己的字体,下面简单描述下添加新字体的流程,以缅甸字体为例。</p>
<p><strong>   1.在frameworks/base/data/fonts/fonts.xml中添加字体节点</strong></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">family</span> <span class="attr">lang</span>=<span class="string">"my"</span>></span></div><div class="line"> <span class="tag"><<span class="name">font</span> <span class="attr">weight</span>=<span class="string">"400"</span> <span class="attr">style</span>=<span class="string">"normal"</span>></span>ZawgyiOne.ttf<span class="tag"></<span class="name">font</span>></span></div><div class="line"><span class="tag"></<span class="name">family</span>></span></div></pre></td></tr></table></figure>
<p><strong>   2.在frameworks/base/data/fonts/fonts.mk的最后加入新加的字体文件</strong></p>
<figure class="highlight mk"><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">PRODUCT_COPY_FILES := \</div><div class="line"> frameworks/base/data/fonts/fonts.xml:$(TARGET_COPY_OUT_SYSTEM)/etc/fonts.xml</div><div class="line"></div><div class="line">PRODUCT_PACKAGES := \</div><div class="line"> DroidSansFallback.ttf \</div><div class="line"> DroidSansMono.ttf \</div><div class="line"> AndroidClock.ttf \</div><div class="line"> DINPro-Black.otf \</div><div class="line"> DINPro-Bold.otf \</div><div class="line"> DINPro-Light.otf \</div><div class="line"> DINPro-Medium.otf \</div><div class="line"> DINPro-Regular.otf \</div><div class="line"> Flyme-Light.ttf \</div><div class="line"> ZawgyiOne.ttf</div></pre></td></tr></table></figure>
<p><strong>   3.在frameworks/base/data/fonts/Android.mk的font_src_files最后加入新加的字体文件</strong></p>
<figure class="highlight mk"><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"></div><div class="line">font_src_files := \</div><div class="line"> AndroidClock.ttf \</div><div class="line"> Flyme-Light.ttf \</div><div class="line"> ZawgyiOne.ttf</div></pre></td></tr></table></figure>
<p><strong>   4.将下载的字体放入frameworks/base/data/fonts下</strong></p>
<p>   其中第2、第3步是为了让字体能够编译进入系统中。</p>
<h2 id="参考博客"><a href="#参考博客" class="headerlink" title="参考博客"></a>参考博客</h2><p><strong>   <a href="http://blog.csdn.net/yangzhiloveyou/article/details/21867095" target="_blank" rel="external">knight</a></strong></p>
<p><strong>   <a href="http://blog.csdn.net/flyeek/article/details/44057999" target="_blank" rel="external">flyeek</a></strong></p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[浅析onWindowsFocusChanged()方法]]></title>
<url>http://yoursite.com/2017/07/12/%E6%B5%85%E6%9E%90onWindowsFocusChanged()%E6%96%B9%E6%B3%95/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><hr>
<p><strong>在接手的项目中,看到了onWindowsFocusChanged()的方法,抽空了解下它的用途</strong></p>
<a id="more"></a>
<h2 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h2><hr>
<h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>   从字面上来讲,onWindowsFocusChanged()方法是指当窗口焦点变化的时候;从意义来说,onWindowsFocusChanged()就是指当前的Activity的Windows(窗口)获取或者失去焦点时这个方法就会被调用,并且当回调这个方法时,Activity是完全可见的。</p>
<p>   在Activity生命周期中,onStart(), onResume(), onCreate()都不是布局visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。从onWindowFocusChanged()被执行起,用户可以与应用进行交互了,换句话说,如果你想要在Activity加载后做些操作,可以在这个方法里调用而这之前,对用户的操作需要做一点限制。</p>
<h3 id="onWindowFocusChanged-的使用情景与作用"><a href="#onWindowFocusChanged-的使用情景与作用" class="headerlink" title="onWindowFocusChanged()的使用情景与作用"></a>onWindowFocusChanged()的使用情景与作用</h3><p>   根据介绍可以了解,onWindowFocusChanged()使用于以下等情景:</p>
<ol>
<li><p>首次进入一个Activity后会在onResume()方法后面调用;</p>
</li>
<li><p>从Activity 跳到另一个Activity,新的窗口会获取焦点, 就的Activity的窗口会失去焦点;</p>
</li>
<li><p>打开软键盘进行输入时,窗口失去焦点;</p>
</li>
<li><p>软键盘输入完毕消失时,窗口重新获取焦点;</p>
</li>
<li><p>应用进入后台,窗口失去焦点;</p>
</li>
<li><p>应用从后台返回当前, 窗口重新获取焦点;</p>
</li>
<li><p>…</p>
</li>
</ol>
<p>   因此其可以有如下作用:</p>
<ol>
<li><p>监控一个Activity是否载完毕;</p>
</li>
<li><p>在Activity加载后进行一些操作,如获取手机屏幕的高度和宽度;</p>
</li>
<li><p>当Activity挂起或恢复时,可以在方法内进行一些数据的保存或恢复的操作;</p>
</li>
<li><p>…</p>
</li>
</ol>
<h3 id="onWindowFocusChanged-调用详解"><a href="#onWindowFocusChanged-调用详解" class="headerlink" title="onWindowFocusChanged()调用详解"></a>onWindowFocusChanged()调用详解</h3><p>   介绍完onWindowFocusChanged()基本的使用情景以及作用后,撸个demo来看下onWindowFocusChanged()具体的调用情况。</p>
<p>   首先在Activity中重写的onWindowFocusChanged()方法如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="comment">/** </span></div><div class="line"> * 添加窗体在视图初始化完成过后 </div><div class="line"> * </div><div class="line"> * <span class="doctag">@param</span> hasFocus </div><div class="line"> */ </div><div class="line"> <span class="meta">@Override</span> </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onWindowFocusChanged</span><span class="params">(<span class="keyword">boolean</span> hasFocus)</span> </span>{ </div><div class="line"> <span class="keyword">super</span>.onWindowFocusChanged(hasFocus); </div><div class="line"> <span class="keyword">if</span> (hasFocus) { </div><div class="line"> <span class="comment">//add Window..... </span></div><div class="line"> } </div><div class="line"> }</div></pre></td></tr></table></figure>
<p>   其中参数hasFocus表示窗口是否获取或失去焦点,true表示获取焦点,false表示失去焦点。</p>
<p>   然后我们看下总体的代码:</p>
<figure class="highlight java"><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><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WindosFoucesDemo</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">"LifeCycleDemo"</span>;</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">//Activity创建时被调用</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onCreate(savedInstanceState);</div><div class="line"> Log.i(TAG, <span class="string">"onCreate is called."</span>);</div><div class="line"> setContentView(R.layout.activity_main);</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">//Activity创建或者从后台重新回到前台时被调用</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStart</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onStart();</div><div class="line"> Log.i(TAG, <span class="string">"onStart is called."</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">//Activity创建或者从被覆盖、后台重新回到前台时被调用</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onResume</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onResume();</div><div class="line"> Log.i(TAG, <span class="string">"onResume is called."</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//Activity窗口获得或失去焦点时被调用,在onResume之后或onPause之后</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onWindowFocusChanged</span><span class="params">(<span class="keyword">boolean</span> hasFocus)</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onWindowFocusChanged(hasFocus);</div><div class="line"> <span class="keyword">if</span>(hasFocus){</div><div class="line"> Log.i(TAG, <span class="string">"onWindowFocusChanged is called and"</span> + <span class="string">"hasFocus is true"</span>);</div><div class="line"> }<span class="keyword">else</span> {</div><div class="line"> Log.i(TAG, <span class="string">"onWindowFocusChanged is called and"</span> + <span class="string">"hasFocus is false"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//Activity被覆盖到下面或者锁屏时被调用</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onPause</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onPause();</div><div class="line"> Log.i(TAG, <span class="string">"onPause is called."</span>);</div><div class="line"> <span class="comment">//有可能在执行完onPause或onStop后,系统资源紧张将Activity杀死,所以有必要在此保存持久数据</span></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//退出当前Activity或者跳转到新Activity时被调用</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onStop</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onStop();</div><div class="line"> Log.i(TAG, <span class="string">"onStop is called."</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//退出当前Activity时被调用,调用之后Activity就结束了</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onDestroy();</div><div class="line"> Log.i(TAG, <span class="string">"onDestory is called."</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">//Activity从后台重新回到前台时被调用</span></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onRestart</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onRestart();</div><div class="line"> Log.i(TAG, <span class="string">"onRestart called."</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   运行该Demo,查看Log日志,可以得到以下日志结果。</p>
<p>   1. 启动Activity时:</p>
<p><img src="/images/2017-07-09 14_19_00屏幕截图.png" alt="image"></p>
<p>   2. 按下任务栏键,Activity被遮挡时:</p>
<p><img src="/images/2017-07-09 14_19_13屏幕截图.png" alt="image"></p>
<blockquote>
<p>注意:按锁屏键和按任务栏或者Home键的生命周期是不同的,按Home执行onPause –> onStop –> onRestart –> onStart —> onResume 按锁屏键和对话框覆盖界面的生命周期是一样的,都只会进行onPause --> onResume .不会执行onStop,onRestart,onStart。</p>
</blockquote>
<p>   3. Activity恢复到前台时:</p>
<p><img src="/images/2017-07-09 14_19_25屏幕截图.png" alt="image"></p>
<p>   4. Activity退出时:</p>
<p><img src="/images/2017-07-09 14_19_39屏幕截图.png" alt="image"></p>
<p>   从上面的例子以及结果可以清楚的onWindowFocusChanged()在整个Activity生命周期内的调用情况,可以根据这些结果,在开发中来充分利用onWindowFocusChanged()方法的作用。</p>
<h3 id="onWindowFocusChanged-源码分析"><a href="#onWindowFocusChanged-源码分析" class="headerlink" title="onWindowFocusChanged()源码分析"></a>onWindowFocusChanged()源码分析</h3><p>   通过Activity源码去查看,发现onWindowFocusChanged()这个方法出现在WindowCallbackWrapper.java和View.java这两个类中,而WindowCallbackWrapper.java中其实也是调用View.java中的onWindowFocusChanged(),其代码如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"> <span class="comment">/**</span></div><div class="line"> * Called when the window containing this view gains or loses focus. Note</div><div class="line"> * that this is separate from view focus: to receive key events, both</div><div class="line"> * your view and its window must have focus. If a window is displayed</div><div class="line"> * on top of yours that takes input focus, then your own window will lose</div><div class="line"> * focus but the view focus will remain unchanged.</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> hasWindowFocus True if the window containing this view now has</div><div class="line"> * focus, false otherwise.</div><div class="line"> * 当前的window(窗口)获取或者失去焦点的时候会回调这个方法.请注意,这个焦点和</div><div class="line"> * view焦点是分离的,为了获取按键事件,view和view所在的窗口都必须获得焦点.如果 * 一个窗口处于你的输入事件的最上层,那么该窗口将失去焦点而view的焦点会保持不</div><div class="line"> * 变.</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onWindowFocusChanged</span><span class="params">(<span class="keyword">boolean</span> hasWindowFocus)</span> </span>{</div><div class="line"> <span class="comment">//获取软键盘a system window such as the keyguard may </span></div><div class="line"> InputMethodManager imm = InputMethodManager.peekInstance();</div><div class="line"> <span class="keyword">if</span> (!hasWindowFocus) {</div><div class="line"> <span class="keyword">if</span> (isPressed()) { </div><div class="line"> <span class="comment">//键盘有按下事件,则强制将该view包含的所有子控件全部setPressed()设置为false</span></div><div class="line"> setPressed(<span class="keyword">false</span>);</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (imm != <span class="keyword">null</span> && (mPrivateFlags & FOCUSED) != <span class="number">0</span>) {</div><div class="line"> <span class="comment">//这是一个隐藏的方法(带@hide标签),当view失去焦点时会调用该方法</span></div><div class="line"> imm.focusOut(<span class="keyword">this</span>);</div><div class="line"> }</div><div class="line"> <span class="comment">//移onWindowFocusChanged(boolean hasFocus) 被回调的触发时机是窗口获取或失去焦点的时候.除长按事件回调的接口方法</span></div><div class="line"> removeLongPressCallback();</div><div class="line"> <span class="comment">//移除轻触探测器,源码中叫 "Remove the tap detection timer."</span></div><div class="line"> removeTapCallback();</div><div class="line"> <span class="comment">//当焦点(fucos)从按下变成取消的时候会调用,属于隐藏方法</span></div><div class="line"> onFocusLost();</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (imm != <span class="keyword">null</span> && (mPrivateFlags & FOCUSED) != <span class="number">0</span>) {</div><div class="line"> <span class="comment">//当view获得焦点时调用该方法,属于隐藏方法</span></div><div class="line"> imm.focusIn(<span class="keyword">this</span>);</div><div class="line"> }</div><div class="line"> <span class="comment">//强制view刷新drawable state,并且会回调drawableStateChanged()方法</span></div><div class="line"> refreshDrawableState();</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   从源码可以验证出,onWindowFocusChanged()方法被回调的触发时机是窗口获取或失去焦点的时候。并且在onResume()方法中的官方解释 <strong>Use {@link #onWindowFocusChanged} to know for certain that your activity is visible to the user (for example, to resume a game).</strong> 可以知道onWindowFocusChanged()第一次调用是在onResume()方法后面。</p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[JSON数据格式以及GSON的使用]]></title>
<url>http://yoursite.com/2017/05/29/JSON%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F%E4%BB%A5%E5%8F%8AGSON%E7%9A%84%E4%BD%BF%E7%94%A8%20/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>   作为一个Android开发者来说,Json数据是经常接触到的一种数据结构,并且现在越来越多的项目和开发插件等默认都会支持和使用Json数据格式,本文我们就来浅谈下Json数据结构以及Gson库的使用。</p>
<hr>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="JSON数据结构"><a href="#JSON数据结构" class="headerlink" title="JSON数据结构"></a>JSON数据结构</h2><h3 id="JSON的定义"><a href="#JSON的定义" class="headerlink" title="JSON的定义"></a>JSON的定义</h3><p>   什么是Json?</p>
<ol>
<li>JSON指的是 JavaScript 对象表示法(JavaScript Object Notation);</li>
<li>JSON是轻量级的文本数据交换格式;</li>
<li>JSON独立于编程语言与平台;</li>
<li>JSON具有自我描述性,更易理解;</li>
<li>JSON 解析器和 JSON 库支持许多不同的编程语言。</li>
</ol>
<h3 id="JSON的两种结构"><a href="#JSON的两种结构" class="headerlink" title="JSON的两种结构"></a>JSON的两种结构</h3><p>   1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。</p>
<p>   2. 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。</p>
<p>   JSON具有以下这些形式:</p>
<p>   对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。</p>
<p>   数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。</p>
<h3 id="JSON实例"><a href="#JSON实例" class="headerlink" title="JSON实例"></a>JSON实例</h3><p>   简单的JSON对象如下所示:</p>
<figure class="highlight json"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line">{</div><div class="line"><span class="attr">"category"</span>:<span class="string">"普通"</span>, </div><div class="line"><span class="attr">"time"</span>:<span class="string">"2017-05-09#17:18:55"</span>,</div><div class="line"><span class="attr">"content"</span>:<span class="string">"主楼502病人突发状况"</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>   该对象有三个属性,分别为categor、time、content,属性后面紧接着是属性的值。</p>
<p>   简单的JSON数组如下所示:</p>
<figure class="highlight json"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line">{</div><div class="line"><span class="attr">"employees"</span>:[</div><div class="line"> {<span class="attr">"firstName"</span>:<span class="string">"John"</span>, <span class="attr">"lastName"</span>:<span class="string">"Doe"</span>}, </div><div class="line"> {<span class="attr">"firstName"</span>:<span class="string">"Anna"</span>, <span class="attr">"lastName"</span>:<span class="string">"Smith"</span>}, </div><div class="line"> {<span class="attr">"firstName"</span>:<span class="string">"Peter"</span>, <span class="attr">"lastName"</span>:<span class="string">"Jones"</span>}</div><div class="line">]</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   在以上实例中,对象”employees”是一个数组。包含了三个对象,每个为个对象为员工的记录(姓和名)。</p>
<h3 id="JSON与XML比较"><a href="#JSON与XML比较" class="headerlink" title="JSON与XML比较"></a>JSON与XML比较</h3><p>   1. 可读性</p>
<p>   JSON和XML的可读性可谓不相上下,一边是简易的语法,一边是规范的标签形式,很难分出胜负。</p>
<p>   2. 可扩展性</p>
<p>   XML天生有很好的扩展性,JSON当然也有,没有什么是XML可以扩展而JSON却不能扩展的。不过JSON在Javascript主场作战,可以存储Javascript复合对象,有着XML不可比拟的优势。</p>
<p>   3. 工具对比</p>
<p>   XML有丰富的工具,比如Dom4j、JDom等,JSON也有提供的工具,如FastJson,Gson等。</p>
<p>   4. 两者实例对比</p>
<p>   用XML表示中国部分省市数据如下:</p>
<figure class="highlight xml"><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"></div><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><span class="tag"><<span class="name">country</span>></span></div><div class="line"> <span class="tag"><<span class="name">name</span>></span>中国<span class="tag"></<span class="name">name</span>></span></div><div class="line"> <span class="tag"><<span class="name">province</span>></span></div><div class="line"> <span class="tag"><<span class="name">name</span>></span>福建<span class="tag"></<span class="name">name</span>></span></div><div class="line"> <span class="tag"><<span class="name">cities</span>></span></div><div class="line"> <span class="tag"><<span class="name">city</span>></span>福州<span class="tag"></<span class="name">city</span>></span></div><div class="line"> <span class="tag"><<span class="name">city</span>></span>厦门<span class="tag"></<span class="name">city</span>></span></div><div class="line"> <span class="tag"></<span class="name">cities</span>></span></div><div class="line"> <span class="tag"></<span class="name">province</span>></span></div><div class="line"> <span class="tag"><<span class="name">province</span>></span></div><div class="line"> <span class="tag"><<span class="name">name</span>></span>广东<span class="tag"></<span class="name">name</span>></span></div><div class="line"> <span class="tag"><<span class="name">cities</span>></span></div><div class="line"> <span class="tag"><<span class="name">city</span>></span>广州<span class="tag"></<span class="name">city</span>></span></div><div class="line"> <span class="tag"><<span class="name">city</span>></span>深圳<span class="tag"></<span class="name">city</span>></span></div><div class="line"> <span class="tag"><<span class="name">city</span>></span>珠海<span class="tag"></<span class="name">city</span>></span></div><div class="line"> <span class="tag"></<span class="name">cities</span>></span></div><div class="line"> <span class="tag"></<span class="name">province</span>></span></div><div class="line"> <span class="tag"><<span class="name">province</span>></span></div><div class="line"> <span class="tag"><<span class="name">name</span>></span>台湾<span class="tag"></<span class="name">name</span>></span></div><div class="line"> <span class="tag"><<span class="name">cities</span>></span></div><div class="line"> <span class="tag"><<span class="name">city</span>></span>台北<span class="tag"></<span class="name">city</span>></span></div><div class="line"> <span class="tag"><<span class="name">city</span>></span>高雄<span class="tag"></<span class="name">city</span>></span></div><div class="line"> <span class="tag"></<span class="name">cities</span>></span></div><div class="line"> <span class="tag"></<span class="name">province</span>></span></div><div class="line"><span class="tag"></<span class="name">country</span>></span></div></pre></td></tr></table></figure>
<p>   用JSON表示如下:</p>
<figure class="highlight"><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"></div><div class="line">{</div><div class="line"> "name": "中国",</div><div class="line"> "province": [{</div><div class="line"> "name": "福建",</div><div class="line"> "cities": {</div><div class="line"> "city": ["福州", "厦门"]</div><div class="line"> }</div><div class="line"> }, {</div><div class="line"> "name": "广东",</div><div class="line"> "cities": {</div><div class="line"> "city": ["广州", "深圳", "珠海"]</div><div class="line"> }</div><div class="line"> }, {</div><div class="line"> "name": "台湾",</div><div class="line"> "cities": {</div><div class="line"> "city": ["台北", "高雄"]</div><div class="line"> }</div><div class="line"> }]</div><div class="line">}</div><div class="line">``` </div><div class="line"></div><div class="line">## GSON的使用</div><div class="line"></div><div class="line">&#160;&#160;&#160;通常在安卓开发中,我们常用的两种方式:一种是JSON原生的方法,即用org.json包来解析;另一种是使用谷歌提供的GSON工具来解析。下面笔者将介绍下二者的使用,例子如下所示。</div><div class="line"></div><div class="line">```Json</div><div class="line"></div><div class="line">{</div><div class="line">"person":[</div><div class="line">{"name":"zhangsan","age":20},</div><div class="line">{"name":"lisi","age":21},</div><div class="line">{"name":"wangwu","age":32}]</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   对应的JavaBean如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>{ </div><div class="line"> <span class="keyword">private</span> String name; </div><div class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age; </div><div class="line"> </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(String name, <span class="keyword">int</span> age)</span> </span>{ </div><div class="line"> <span class="keyword">super</span>(); </div><div class="line"> <span class="keyword">this</span>.name = name; </div><div class="line"> <span class="keyword">this</span>.age = age; </div><div class="line"> } </div><div class="line"> </div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{ </div><div class="line"> <span class="keyword">return</span> name; </div><div class="line"> } </div><div class="line"> </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{ </div><div class="line"> <span class="keyword">this</span>.name = name; </div><div class="line"> } </div><div class="line"> </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>{ </div><div class="line"> <span class="keyword">return</span> age; </div><div class="line"> } </div><div class="line"> </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAge</span><span class="params">(<span class="keyword">int</span> age)</span> </span>{ </div><div class="line"> <span class="keyword">this</span>.age = age; </div><div class="line"> } </div><div class="line"> </div><div class="line"> <span class="meta">@Override</span> </div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{ </div><div class="line"> <span class="keyword">return</span> <span class="string">"Person [name="</span> + name + <span class="string">", age="</span> + age + <span class="string">"]"</span>; </div><div class="line"> } </div><div class="line"> </div><div class="line"> }</div></pre></td></tr></table></figure>
<h3 id="使用JSON(org-json)包解析"><a href="#使用JSON(org-json)包解析" class="headerlink" title="使用JSON(org.json)包解析"></a>使用JSON(org.json)包解析</h3><figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JSONDEMO</span> </span>{ </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> JSONException </span>{ </div><div class="line"> String str = <span class="string">"{person:[{name:'zhangsan',age:20},{name:'lisi',age:2},{name:'wangwu',age:3}]}"</span>; </div><div class="line"> List<Person> l = <span class="keyword">new</span> ArrayList<>(); </div><div class="line"> <span class="comment">//创建JSONObject对象 </span></div><div class="line"> JSONObject ob = <span class="keyword">new</span> JSONObject(str); </div><div class="line"> <span class="comment">//获取JSONObject对象的值,该值是一个JSON数组</span></div><div class="line"> JSONArray array = ob.getJSONArray(<span class="string">"person"</span>); </div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < array.length(); i++) { </div><div class="line"> <span class="comment">//获得JSON数组中的每一个JSONObject对象 </span></div><div class="line"> JSONObject o = array.getJSONObject(i); </div><div class="line"> <span class="comment">//获得每一个JSONObject对象中的键所对应的值</span></div><div class="line"> String name = o.getString(<span class="string">"name"</span>); </div><div class="line"> <span class="keyword">int</span> age = o.getInt(<span class="string">"age"</span>); </div><div class="line"> <span class="comment">//将解析出来的属性值存入Person对象</span></div><div class="line"> Person p = <span class="keyword">new</span> Person(name, age); </div><div class="line"> <span class="comment">//将解析出来的每一个Person对象添加到List中</span></div><div class="line"> l.add(p); </div><div class="line"> } </div><div class="line"> <span class="keyword">for</span> (Person person : l) { </div><div class="line"> System.out.println(person); </div><div class="line"> } </div><div class="line"> </div><div class="line"> } </div><div class="line">}</div></pre></td></tr></table></figure>
<p>   输出结果如下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">Person[name=zhangsan,age=<span class="number">20</span>]</div><div class="line">Person[name=lisi,age=<span class="number">22</span>]</div><div class="line">Person[name=wangwu,age=<span class="number">32</span>]</div></pre></td></tr></table></figure>
<p>   使用这种方法解析JSON,看注释,没什么好多的,总结一句话就是:遇到{}用JSONObject,遇到[]用JSONArray,这样你就可以说你精通org.json解析JSON了。</p>
<h3 id="使用GSON解析"><a href="#使用GSON解析" class="headerlink" title="使用GSON解析"></a>使用GSON解析</h3><figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GSONDEMO</span> </span>{ </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> JSONException </span>{ </div><div class="line"> String str = <span class="string">"{person:[{name:'zhangsan',age:20},{name:'lisi',age:2},{name:'wangwu',age:3}]}"</span>; </div><div class="line"> <span class="comment">//创建Gson对象</span></div><div class="line"> Gson gson = <span class="keyword">new</span> Gson();</div><div class="line"> <span class="comment">//将JSON转化成Person对象集合</span></div><div class="line"> List<Person> ps = gson.fromJson(str, <span class="keyword">new</span> TypeToken<List<Person>>(){}.getType());</div><div class="line"> <span class="comment">//输出</span></div><div class="line"> <span class="keyword">for</span> (Person person : ps) { </div><div class="line"> System.out.println(person); </div><div class="line"> } </div><div class="line"> </div><div class="line"> } </div><div class="line">}</div></pre></td></tr></table></figure>
<p>   输出结果如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line">Person[name=zhangsan,age=<span class="number">20</span>]</div><div class="line">Person[name=lisi,age=<span class="number">22</span>]</div><div class="line">Person[name=wangwu,age=<span class="number">32</span>]</div></pre></td></tr></table></figure>
<p>   可以从上面的例子看出,使用GSON工具来解析JSON比原生方法简单的多,所以一般在开发过程中,推荐使用GSON来解析网络数据JSON。</p>
<h3 id="Gson的常见用法"><a href="#Gson的常见用法" class="headerlink" title="Gson的常见用法"></a>Gson的常见用法</h3><p>   1. JSON转化成对象</p>
<p>   这种用法通过创建GSON对象,调用fromJson()方法来将JSON数据转化成对应对象,用法如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="comment">// 使用new方法,创建对象</span></div><div class="line">Gson gson = <span class="keyword">new</span> Gson();</div><div class="line"></div><div class="line"><span class="comment">// fromJson 将json字符串转为bean对象</span></div><div class="line">Person person= gson.fromJson(jsonStr, Person.class);</div><div class="line"></div><div class="line"><span class="comment">// **反序列化成List时需要使用到TypeToken getType()**</span></div><div class="line">List<Person> retList = gson.fromJson(jsonStr2,<span class="keyword">new</span> TypeToken<List<Person>>(){}.getType());</div></pre></td></tr></table></figure>
<p>   2. 对象转化成JSON</p>
<p>   这种用法通过创建GSON对象,调用toJson()方法来将对象化转化成对应JSON数据,用法如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="comment">// 使用new方法,创建对象</span></div><div class="line">Gson gson = <span class="keyword">new</span> Gson();</div><div class="line"></div><div class="line"><span class="comment">// toJson 将bean对象转换为json字符串</span></div><div class="line">String jsonStr = gson.toJson(person, Person.class);</div><div class="line"></div><div class="line"><span class="comment">// **序列化List**</span></div><div class="line">String jsonStr2 = gson.toJson(list);</div></pre></td></tr></table></figure>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[舒适区终有一天会毁掉你的青春]]></title>
<url>http://yoursite.com/2017/04/03/%E8%88%92%E9%80%82%E5%8C%BA%E7%BB%88%E6%9C%89%E4%B8%80%E5%A4%A9%E4%BC%9A%E6%AF%81%E6%8E%89%E4%BD%A0%E7%9A%84%E9%9D%92%E6%98%A5/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>在大城市里,搞废一个人的方式特别简单,给你一个安静狭小的空间,给你一根网线,最好再加一个外卖电话。好了,你开始废了。以自己为圆心,自己的手为半径,开始画个圆。你会发现所有需要的东西,都在这个圆圈里。</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<p>   在大城市里,搞废一个人的方式特别简单,给你一个安静狭小的空间,给你一根网线,最好再加一个外卖电话。好了,你开始废了。以自己为圆心,自己的手为半径,开始画个圆。你会发现所有需要的东西,都在这个圆圈里。</p>
<p>   这个圈,叫作舒适圈。这一个月我一直在全国各地出差,回到北京,见到一个许久没见的朋友,一起去KTV唱歌,他刚刚被公司解雇。我问他,一个月没见,最近忙啥呢。</p>
<p>   他说,没忙啥,待着呢。</p>
<p>   我说,其实我特别能理解你,你这个月是不是觉得自己过得特别无忧无虑,恨不得连电话都想丢了。他说,电话还是得要的,不过确实电话每次响起还是有点紧张,总觉得自己安稳的小世界要被打破了。</p>
<p>   我点点头,想起了《肖申克救赎》里的一句话:这些墙挺有意思,一开始你抵触它,然后你习惯它,最后你不得不依赖它。</p>
<p>   人有一种习惯,就是总喜欢在舒适熟悉的环境待着,这种“舒适区”一旦被建立,就会变得无比依赖,慢慢地爱上了周围的墙,恋上了这舒适的小屋,从而不愿意飞出去看看,怕看到外面熙熙攘攘的世界。</p>
<p>   我想起另一个朋友,毕业去了一家国企上班,每天朝九晚四,日子像上了发条一样,只有周末,才像被赋予了灵魂一样,穿着打扮逛街约会去了。我跟她聊过舒适区,她告诉我,我这才不是舒适区,我可是每天都要按时工作的,不迟到不早退,很规律很努力的。</p>
<p>   我说,那工作一年了,感觉到自己有什么变化吗?她想了想,说,你别说,好像还真没有。</p>
<p>   其实,舒适区分为两种,一种是成天无所事事,另一种更可怕,因为很难意识到,就是无意义有规律的循环。而后者,更是许多人的生活状态:看起来很努力,看起来很累很忙,不过是重复无意义地循环着,这样的生活,过着过着只会觉得舒服,却没有本质的变化。</p>
<p>   我曾经见到一个在医院门口收费的哥们儿,每天摆着一副臭脸,谁也不能多问他一个问题,否则他会大发雷霆。可是他一下班,脸上就露出了笑容。后来,我明白了,只有下班后,他才走出了自己的舒适区,开始了多姿多彩的生活。所以,只有一个人舒适区被打破,才能见到突破和卓越,从而带来持久的幸福。</p>
<p>   我特别怕自己在年轻的日子里,把日子过成发条,只剩下滴答滴答。于是,从开始工作第一天起,就没有坐过班,即使是现在创业,董事会非要求坐班,我也断然拒绝。甚至有一段时间闹得很僵,他们问我为什么这么不愿意全心投入这份工作?</p>
<p>   我跟他们说,不去坐班不是不全力投入,相反,很多人每天坐八小时一周坐五天,也就干了十个小时的活,搞得自己也郁闷。</p>
<p>   后来,我拿实际行动证明了自己不坐班效率反而更高,我能用大把属于自己的时间做许多事情,跨了几个领域,这些领域能互相协作,而且都做得不错。</p>
<p>   其实,我还有个原因不愿意坐班,就是我特别了解自己的惰性,一旦我的日子变得循规蹈矩每天都有固定的方式方法,慢慢地就失去这么强的创造力和闯劲儿。我怕自己习惯了一种生活模式,换了环境就不适应了。</p>
<p>   关于走出舒适区,并不是盲目地辞职,相反,你应该有一份保底活下来的工作,除此之外,一定要给自己生活中埋下一些彩蛋:去吃一次没吃过的超辣鸡翅;去表白一个只见过一次的姑娘;去看一本一直想看的书。</p>
<p>   所以,别让舒适区毁掉青春,相反,应该趁着青春,去围墙的外面看看,你要相信,故步自封的人,舒适区会越来越小,终有一天,会发现世界早已无立足之处。真正的强者,他们在年轻的时候,经历了沧桑,化解了迷茫,学会了坚强,懂得了疗伤,他们在哪里都能活,哪里都是自己的天堂。</p>
<hr>
<p><strong>版权声明:本文为博主转载文章,转载请注明出处<a href="http://www.rensheng5.com/duzhewenzhai/rensheng/id-148122.html" target="_blank" rel="external">点这</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[Adb常用指令]]></title>
<url>http://yoursite.com/2017/03/19/Adb%E5%B8%B8%E7%94%A8%E6%8C%87%E4%BB%A4/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>对于Android开发者来说,Adb应该都不陌生,作为Android调试的桥梁,熟练使用其主要的指令,可以提升我们的开发效率,下面就对常见的Adb指令进行介绍</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="Adb概述"><a href="#Adb概述" class="headerlink" title="Adb概述"></a>Adb概述</h2><p>   adb的全称为Android Debug Bridge,就是起到调试桥的作用。通过adb我们可以在Eclipse中方便通过DDMS来调试Android程序,说白了就是debug工具。adb的工作方式比较特殊,采用监听Socket TCP 5554等端口的方式让IDE和Qemu通讯,默认情况下adb会daemon相关的网络端口,所以当我们运行Eclipse时adb进程就会自动运行。作为开发人员,掌握适当所需要的ADB操作命令是非常必须的。就把平时工作中用得相对比较多的adb命令作个小总结。</p>
<p>   Adb工具位于SDK的platform-tools目录下,所以要使用该工具的时候,需要通过cd命令,切换到该目录下,或者将platform-tools的路径添加到系统环境变量中,这样就可以直接使用了(针对windows系统,linux系统会自动配置)</p>
<h2 id="Adb常用指令"><a href="#Adb常用指令" class="headerlink" title="Adb常用指令"></a>Adb常用指令</h2><p>   下面我们来看一些Adb常用命令</p>
<ol>
<li>显示系统Android全部平台:<br> android list targets </li>
<li>显示系统中全部AVD(模拟器):<br> android list avd </li>
<li>创建AVD(模拟器):<br> android create avd –name 名称 –target 平台编号 </li>
<li>启动模拟器:<br> emulator -avd 名称 -sdcard ~/名称.img (-skin 1280x800) </li>
<li>删除AVD(模拟器):<br> android delete avd –name 名称 </li>
<li>显示当前运行的全部模拟器或真机:<br> adb devices </li>
<li>安装应用程序:<br> adb install -r 应用程序.apk</li>
<li>获取模拟器中的文件:<br> adb pull <remote> <local> </local></remote></li>
<li>向模拟器中写文件:<br> adb push <local> <remote> </remote></local></li>
<li>进入模拟器的shell模式:<br>adb shell </li>
<li>缷载apk包: 这个操作需要执行以下步骤<br>adb shell<br>cd data/app<br>rm apk包<br>exit<br>adb uninstall apk包的主包名<br>adb install -r apk包 </li>
<li>查看adb命令帮助信息:<br>adb help </li>
<li>在命令行中查看LOG信息:<br>adb logcat -s 标签名 </li>
<li>删除系统应用:<br> adb remount (重新挂载系统分区,使系统分区重新可写)。<br> adb shell<br> cd system/app<br> rm *.apk </li>
<li>获取管理员权限:<br>adb root </li>
<li>remount命令的作用是加载文件系统</li>
<li>模拟器重启命令:<br>adb reboot</li>
</ol>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[Android运行环境Context理解]]></title>
<url>http://yoursite.com/2017/03/10/%E8%B0%88%E8%B0%88%E5%AF%B9Context%E7%9A%84%E7%90%86%E8%A7%A3/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>   Context相信有Android开发经验的人不陌生,基本上每天都在接触,谈谈自己对Context的理解</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="Context类型"><a href="#Context类型" class="headerlink" title="Context类型"></a>Context类型</h2><p>   Context通常被翻译为上下文,我通常理解为Android的运行环境,在Android中,Activity、Service、Application都是继承自Context。Android程序不像Java程序一样,随便创建一个类,写个main()方法就能跑了,而是要有一个完整的Android工程环境,在这个环境下,我们有像Activity、Service、BroadcastReceiver等系统组件,而这些组件并不是像一个普通的Java对象new一下就能创建实例的了,而是要有它们各自的上下文环境,也就是这里讨论的Context。</p>
<p>   Android应用程序如下几个时间点创建应用的上下文Context:</p>
<ol>
<li><p>创建Application时</p>
</li>
<li><p>创建Activity时</p>
</li>
<li><p>创建Service时</p>
</li>
</ol>
<p>   细心的人可以发现,创建Context的时机就是创建Context的实现类。在应用第一次启动的时候,系统就会创建Application对象,同时创建ApplicationContext,而系统所有的组件都拥有一个这样的上下文对象,这个上下文对象贯穿整个应用程序的生命周期,为系统提供了全局的功能和环境支持,当然创建组件的时候,系统也会给组件创建他们自己相应的上下问对象,但是从原理上来说某些时候二者是有一些区别的。</p>
<h2 id="getContext-、getApplicationContext-、this的区别"><a href="#getContext-、getApplicationContext-、this的区别" class="headerlink" title="getContext()、getApplicationContext()、this的区别"></a>getContext()、getApplicationContext()、this的区别</h2><p>   使用this,说明当前类是context类的子类,一般是application activity等</p>
<p>   getApplicationContext()指的是app所使用的application,是在AndroidManifest唯一指定的意味着,在当前app的任意位置使用这个函数得到的是同一个Context,而使用getContext获取的是当前对象所在的Context。</p>
<p>   举个简单的例子。</p>
<p>   我们在公司上班, 我们是一个类,公司是一个类,公司.this是context()即公司的环境,我.this不是context,而我getcontext()是指公司的环境。而getApplicationContext()则可以看做是所有公司的集合,发生的所有事情都在这个集合中,有且只有一个。 </p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[开源库LitePal的用法]]></title>
<url>http://yoursite.com/2017/02/23/Activity%E5%BC%80%E6%BA%90%E6%95%B0%E6%8D%AE%E5%BA%93LitePal%E4%BD%BF%E7%94%A8/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>   LitePal是一个开源的Android库,允许开发人员使用SQLite数据库非常容易。您可以完成大多数数据库操作,甚至不需要编写SQL语句,包括创建或升级表,压缩操作,聚合函数等。LitePal的设置也很简单,您可以将它集成到您的项目中少于5分钟。</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="LitePal的快速配置"><a href="#LitePal的快速配置" class="headerlink" title="LitePal的快速配置"></a>LitePal的快速配置</h2><h3 id="1-引入Jar包或源码"><a href="#1-引入Jar包或源码" class="headerlink" title="1.引入Jar包或源码"></a>1.引入Jar包或源码</h3><p>   使用Android Studio在项目的build.gradle中添加下面依赖:</p>
<figure class="highlight groovy"><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></pre></td><td class="code"><pre><div class="line"></div><div class="line">dependencies {</div><div class="line"> compile <span class="string">'org.litepal.android:core:1.3.2'</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>   使用Eclipse到<a href="https://github.com/LitePalFramework/LitePal#latest-downloads/" target="_blank" rel="external">这里</a>下载好了jar包之后,把它复制到项目的libs目录中就算是引入成功了。</p>
<h3 id="2-配置litepal-xml"><a href="#2-配置litepal-xml" class="headerlink" title="2.配置litepal.xml"></a>2.配置litepal.xml</h3><p>   在项目的assets目录下面新建一个litepal.xml文件,内容如下:</p>
<figure class="highlight xml"><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"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><span class="tag"><<span class="name">litepal</span>></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">dbname</span> <span class="attr">value</span>=<span class="string">"cool_weather"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">version</span> <span class="attr">value</span>=<span class="string">"1"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">list</span>></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.Province"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.City"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.County"</span> /></span></div><div class="line"> <span class="tag"></<span class="name">list</span>></span></div><div class="line"></div><div class="line"><span class="tag"></<span class="name">litepal</span>></span></div></pre></td></tr></table></figure>
<p>   其中:</p>
<ul>
<li><dbname>是数据库的名字</dbname></li>
<li><version>是数据库的版本号</version></li>
<li><list>是数据库的映射模型(数据库表)</list></li>
<li><mapping>是数据库的映射模型的地址(数据库表结构)</mapping></li>
</ul>
<h3 id="3-配置LitePalApplication"><a href="#3-配置LitePalApplication" class="headerlink" title="3. 配置LitePalApplication"></a>3. 配置LitePalApplication</h3><p>   在AndroidManifest.xml中配置LitePalApplication,如下:</p>
<figure class="highlight xml"><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></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">application</span></span></div><div class="line"> <span class="attr">android:name</span>=<span class="string">"org.litepal.LitePalApplication"</span></div><div class="line"> <span class="attr">...</span></div><div class="line"> ></div><div class="line"> ...</div><div class="line"> ...</div><div class="line"><span class="tag"></<span class="name">application</span>></span></div></pre></td></tr></table></figure>
<p>   如果是已经有自己的application,则可以继承LitePalApplication或者在代码中加入如下代码:</p>
<figure class="highlight java"><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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyApplication</span> <span class="keyword">extends</span> <span class="title">LitePalApplication</span> </span>{ </div><div class="line"> ... </div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyApplication</span> <span class="keyword">extends</span> <span class="title">AnotherApplication</span></span>{ </div><div class="line"></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">super</span>.onCreate();</div><div class="line"> LitePal.initialize(<span class="keyword">this</span>);</div><div class="line"> }</div><div class="line"> ... </div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="LitePal的建表"><a href="#LitePal的建表" class="headerlink" title="LitePal的建表"></a>LitePal的建表</h2><p>   根据对象关系映射模式的理念,每一张表都应该对应一个模型(Model),建表先要新建一个模型类,新建一个Province类,如下:</p>
<figure class="highlight java"><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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Province</span> <span class="keyword">extends</span> <span class="title">DataSupport</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">private</span> <span class="keyword">int</span> id;</div><div class="line"> <span class="keyword">private</span> String provinceName;</div><div class="line"> <span class="keyword">private</span> <span class="keyword">int</span> provinceCode;</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getProvinceCode</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> provinceCode;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setProvinceCode</span><span class="params">(<span class="keyword">int</span> provinceCode)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.provinceCode = provinceCode;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getId</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> id;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setId</span><span class="params">(<span class="keyword">int</span> id)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.id = id;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getProvinceName</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> provinceName;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setProvinceName</span><span class="params">(String provinceName)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.provinceName = provinceName;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   LitePal的映射规则是非常轻量级的,不像一些其它的数据库框架,需要为每个模型类单独配置一个映射关系的XML,LitePal的所有映射都是自动完成的。根据LitePal的数据类型支持,可以进行对象关系映射的数据类型一共有8种,int、short、long、float、double、boolean、String和Date。只要是声明成这8种数据类型的字段都会被自动映射到数据库表中,并不需要进行任何额外的配置。</p>
<blockquote>
<p>注意:只有private修饰的字段才会被映射到数据库表中,即如果有某一个字段不想映射的话,就设置为public、protected或者default修饰符就可以了。</p>
</blockquote>
<p>   建立好Model后,我们就把他配置到映射列表中,即编辑assest目录下的litepal.xml文件,在<list>标签中加入DEST类的声明,这里要注意,要类的完整类名。</list></p>
<figure class="highlight xml"><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></pre></td><td class="code"><pre><div class="line"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><span class="tag"><<span class="name">litepal</span>></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">dbname</span> <span class="attr">value</span>=<span class="string">"cool_weather"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">version</span> <span class="attr">value</span>=<span class="string">"1"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">list</span>></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.Province"</span> /></span></div><div class="line"> <span class="tag"></<span class="name">list</span>></span></div><div class="line"></div><div class="line"><span class="tag"></<span class="name">litepal</span>></span></div></pre></td></tr></table></figure>
<p>   到这里,就完成了LitePal数据库的配置。</p>
<h2 id="LitePal的升级表"><a href="#LitePal的升级表" class="headerlink" title="LitePal的升级表"></a>LitePal的升级表</h2><h3 id="1-添加新表"><a href="#1-添加新表" class="headerlink" title="1.添加新表"></a>1.添加新表</h3><p>   首先创建一个新的模型类,然后把它设置到litepal.xml中,如下:</p>
<figure class="highlight xml"><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"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><span class="tag"><<span class="name">litepal</span>></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">dbname</span> <span class="attr">value</span>=<span class="string">"cool_weather"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">version</span> <span class="attr">value</span>=<span class="string">"1"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">list</span>></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.Province"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.City"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.County"</span> /></span></div><div class="line"> <span class="tag"></<span class="name">list</span>></span></div><div class="line"></div><div class="line"><span class="tag"></<span class="name">litepal</span>></span></div></pre></td></tr></table></figure>
<p>   然后,把litepal.xml中的version的值加一即可,如下:</p>
<figure class="highlight xml"><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"><?xml version="1.0" encoding="utf-8"?></div><div class="line"><span class="tag"><<span class="name">litepal</span>></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">dbname</span> <span class="attr">value</span>=<span class="string">"cool_weather"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">version</span> <span class="attr">value</span>=<span class="string">"2"</span> /></span></div><div class="line"></div><div class="line"> <span class="tag"><<span class="name">list</span>></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.Province"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.City"</span> /></span></div><div class="line"> <span class="tag"><<span class="name">mapping</span> <span class="attr">class</span>=<span class="string">"com.example.yuxuehai.coolweather.bean.County"</span> /></span></div><div class="line"> <span class="tag"></<span class="name">list</span>></span></div><div class="line"></div><div class="line"><span class="tag"></<span class="name">litepal</span>></span></div></pre></td></tr></table></figure>
<h3 id="2-旧表添加新列"><a href="#2-旧表添加新列" class="headerlink" title="2.旧表添加新列"></a>2.旧表添加新列</h3><p>   首先在需要升级的模型类中添加新的private修饰的字段,然后再把litepal.xml中的version的值加一即可,这里就不展示代码了,读者可以自己去体验。</p>
<h2 id="LitePal的操作"><a href="#LitePal的操作" class="headerlink" title="LitePal的操作"></a>LitePal的操作</h2><p>   LitePal要存储数据,首先模型类要继承DataSupport,即:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Province</span> <span class="keyword">extends</span> <span class="title">DataSupport</span> </span>{</div><div class="line"> ...</div><div class="line"> ...</div><div class="line">}</div></pre></td></tr></table></figure>
<p>   继承了DataSupport类之后,这些实体类就拥有了进行CRUD操作的能力。</p>
<h3 id="1-存储操作"><a href="#1-存储操作" class="headerlink" title="1.存储操作"></a>1.存储操作</h3><p>   创建对象,为对象的属性进行赋值,最后调用save()方法即可存储,如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line">Province province = <span class="keyword">new</span> Province();</div><div class="line">province.setProvinceName(provinceObject.getString(<span class="string">"name"</span>));</div><div class="line">province.setProvinceCode(provinceObject.getInt(<span class="string">"id"</span>));</div><div class="line">province.save();</div></pre></td></tr></table></figure>
<p>   更好的是,save()方法是有返回值的,读者可以根据自己需要对其进行判断后做出一些操作:</p>
<figure class="highlight java"><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"><span class="keyword">if</span> (mDest.save()) { </div><div class="line"> Toast.makeText(context, <span class="string">"存储成功"</span>, Toast.LENGTH_SHORT).show(); </div><div class="line">} <span class="keyword">else</span> { </div><div class="line"> Toast.makeText(context, <span class="string">"存储失败"</span>, Toast.LENGTH_SHORT).show(); </div><div class="line">}</div></pre></td></tr></table></figure>
<h3 id="2-修改操作"><a href="#2-修改操作" class="headerlink" title="2.修改操作"></a>2.修改操作</h3><p>   如果想把Province表中id为1的provinceCode改为”1”,可以这样写:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line">ContentValues values = <span class="keyword">new</span> ContentValues(); </div><div class="line">values.put(<span class="string">"provinceCode"</span>, <span class="string">"1"</span>); </div><div class="line">DataSupport.update(Pronvice.class, values, <span class="number">1</span>); </div><div class="line"></div><div class="line"><span class="comment">//或者用下面这种方法</span></div><div class="line"></div><div class="line">Province updateNews = <span class="keyword">new</span> Province(); </div><div class="line">updateNews.setProvinceCode(<span class="number">1</span>) </div><div class="line">updateNews.update(<span class="number">1</span>);</div></pre></td></tr></table></figure>
<p>   如果想把Province表中所有id为”1”的改为”2”可以这样写:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line">ContentValues values = <span class="keyword">new</span> ContentValues(); </div><div class="line">values.put(<span class="string">"provinceCode"</span>, <span class="string">"2"</span>); </div><div class="line">DataSupport.updateAll(DEST.class, values, <span class="string">"provinceCode = ?"</span>, <span class="string">"1"</span>); </div><div class="line"></div><div class="line"><span class="comment">//或者用下面这种方法</span></div><div class="line"></div><div class="line">Province updateNews = <span class="keyword">new</span> Province(); </div><div class="line">updateNews.setProvinceCode(<span class="string">"2"</span>); </div><div class="line">updateNews.updateAll(<span class="string">"setProvinceCode = ?"</span>, <span class="string">"1"</span>);</div></pre></td></tr></table></figure>
<h3 id="3-LitePal的删除操作"><a href="#3-LitePal的删除操作" class="headerlink" title="3.LitePal的删除操作"></a>3.LitePal的删除操作</h3><p>   比如说我们想删除Province表中id为2的记录,就可以这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">DataSupport.delete(Province.class, <span class="number">2</span>);</div></pre></td></tr></table></figure>
<p>   想把Province表中id为“1”的所有数据删除,就可以这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">DataSupport.deleteAll(Province.class, <span class="string">"destId = ? "</span>, <span class="string">"1"</span>);</div></pre></td></tr></table></figure>
<p>   想把Province表中所有数据删除,就可以这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">DataSupport.deleteAll(Province.class);</div></pre></td></tr></table></figure>
<h3 id="LitePal的查询操作"><a href="#LitePal的查询操作" class="headerlink" title="LitePal的查询操作"></a>LitePal的查询操作</h3><p>   查询Province表中id为1的这条记录,使用LitePal就可以这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Province mProvince = DataSupport.find(Province.class, <span class="number">1</span>);</div></pre></td></tr></table></figure>
<p>   想要获取Province表中的第一条数据,只需要这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Province mProvince = DataSupport.findFirst(Province.class);</div></pre></td></tr></table></figure>
<p>   想要获取Province表中的最后一条数据,只需要这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Province mProvince = DataSupport.findLast(Province.class);</div></pre></td></tr></table></figure>
<p>   查询Province表中id为1,2,3的这条记录,使用LitePal就可以这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">List<Province> mProvince = DataSupport.findAll(Province.class,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>);</div></pre></td></tr></table></figure>
<p>   查询所有数据,只需要这样写:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">List<Province> mProvince = DataSupport.findAll(Province.class);</div></pre></td></tr></table></figure>
<p>   笔者只是对一些简单的操作进行介绍,如想学习更多操作请浏览guolin郭霖老师的博客点<a href="http://blog.csdn.net/guolin_blog/article/details/38083103" target="_blank" rel="external">这里</a></p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[Recyclerview的用法]]></title>
<url>http://yoursite.com/2017/01/14/recycleview%E7%9A%84%E4%BD%BF%E7%94%A8/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>简单的介绍下Recyclerview的用法</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="Android5-0-RecyclerView特点、用法、及自定义动画"><a href="#Android5-0-RecyclerView特点、用法、及自定义动画" class="headerlink" title="Android5.0 RecyclerView特点、用法、及自定义动画"></a>Android5.0 RecyclerView特点、用法、及自定义动画</h2><p>   RecyclerView派生于ViewGroup,是一种更先进的柔性版的ListView。这个小工具是一个容器,用于显示,它能非常有效地维护了数量有限而滚动大的数据集。相对于ListView来说RecyclerView使用起来更加灵活但同时也增加了一定的复杂度,它在最新的support-V7版本中提供支持.本文主要分为以下2个部分:</p>
<ol>
<li>RecyclerView的简单使用</li>
<li>简单介绍RecyclerView的四大组件</li>
</ol>
<h3 id="RecyclerView的简单使用"><a href="#RecyclerView的简单使用" class="headerlink" title="RecyclerView的简单使用"></a>RecyclerView的简单使用</h3><p>   虽说相对于以前的ListView,RecyclerView基本上没有新增的功能,但在功能的具体实现和使用的方法上两者却有着很大的区别。要使用RecyclerView,需要先了解这几个个元素:LayoutManager,RecyclerView.Adapter,Itemanimator以及itemDecoration。LayoutManager控制RecyclerView的布局以及资源的回收,RecyclerView.Adapter用于设置数据,ItemAnimator用于创建列表的Item动画,而ItemDecoration则用于绘制列表子项额外的内容。以上四个均为RecyclerView中的抽象类,带有最基本的接口和参数,开发者可以通过继承以上几个类进行扩展实现不同的功能效果。下面首先通过附件中的SimpleDemo介绍一下RecyclerVIew的使用方法:</p>
<h4 id="1-定义布局文件"><a href="#1-定义布局文件" class="headerlink" title="1. 定义布局文件"></a>1. 定义布局文件</h4><p>   activity_main.xml的主要布局如下:</p>
<figure class="highlight xml"><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"><span class="tag"><<span class="name">android.support.v7.widget.RecyclerView</span></span></div><div class="line"><span class="attr">android:id</span>=<span class="string">"@+id/recyclerview_vertical"</span></div><div class="line"><span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></div><div class="line"><span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span></div><div class="line"><span class="attr">android:scrollbars</span>=<span class="string">"vertical"</span> /></div></pre></td></tr></table></figure>
<p>   RecyclerView是android.support.v7包下提供的控件,要使用RecyclerView可以直接把源码上整个的v7包导入到工程中, 或者把当前的API升级到21,在sdk/extras/android/support/v7目录下找到android-support-v7-recyclerview.jar(其实也可以直接从网上的Demo中直接copy对应的jar包过去,不过应当注意最近的版本中部分接口已经做了相应的变化 ,应下载最新的jar包),将其导入到工程内即可。</p>
<h4 id="2-设置RecyclerView-Adapter"><a href="#2-设置RecyclerView-Adapter" class="headerlink" title="2. 设置RecyclerView.Adapter"></a>2. 设置RecyclerView.Adapter</h4><p>   Demo中的SimpleAdapter.java中的主要代码如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="comment">//定义ViewHolder,包含两个控件</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ViewHolder</span> <span class="keyword">extends</span> <span class="title">RecyclerView</span>.<span class="title">ViewHolder</span></span>{</div><div class="line"></div><div class="line"> <span class="keyword">public</span> TextView mTextView;</div><div class="line"> <span class="keyword">public</span> ImageView mImageView;</div><div class="line"> </div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ViewHolder</span><span class="params">(View itemView)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(itemView);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> ViewHolder <span class="title">onCreateViewHolder</span><span class="params">(ViewGroup viewGroup, <span class="keyword">int</span> i)</span> </span>{</div><div class="line"> View view = View.inflate(viewGroup.getContext(), R.layout.item_layout, <span class="keyword">null</span>);</div><div class="line"> <span class="comment">// 创建ViewHolder</span></div><div class="line"> ViewHolder holder = <span class="keyword">new</span> ViewHolder(view);</div><div class="line"> holder.mImageView = (ImageView)view.findViewById(R.id.id_index_item_image);</div><div class="line"> holder.mTextView = (TextView)view.findViewById(R.id.id_index_item_text);</div><div class="line"> <span class="keyword">return</span> holder;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onBindViewHolder</span><span class="params">(ViewHolder viewHolder,<span class="keyword">int</span> i)</span> </span>{</div><div class="line"> <span class="comment">//设置TextView内容</span></div><div class="line"> viewHolder.mTextView.setText(mData[i]);</div><div class="line"> <span class="comment">//设置ImageView资源</span></div><div class="line"> viewHolder.mImageView.setImageResource(R.drawable.mail); </div><div class="line">}</div></pre></td></tr></table></figure>
<h4 id="3-定义Decoration"><a href="#3-定义Decoration" class="headerlink" title="3. 定义Decoration"></a>3. 定义Decoration</h4><p>   Decoration.java的主要代码如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onDrawOver</span><span class="params">(Canvas c, RecyclerView parent)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (mDivider == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">super</span>.onDrawOver(c, parent);</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//为横向布局的RecyclerView的每个Item设置下划线</span></div><div class="line"> <span class="keyword">if</span> (getOrientation(parent) == LinearLayoutManager.VERTICAL) {</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> left = parent.getPaddingLeft();</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> right = parent.getWidth() - parent.getPaddingRight();</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> childCount = parent.getChildCount();</div><div class="line"> </div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < childCount; i++) {</div><div class="line"> <span class="keyword">final</span> View child = parent.getChildAt(i);</div><div class="line"> <span class="keyword">final</span> RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child</div><div class="line"> .getLayoutParams();</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> size = mDivider.getIntrinsicHeight();</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> top = child.getTop() - params.topMargin;</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> bottom = top + size;</div><div class="line"> mDivider.setBounds(left, top, right, bottom);</div><div class="line"> mDivider.draw(c);</div><div class="line"> }</div></pre></td></tr></table></figure>
<h4 id="4-初始化操作"><a href="#4-初始化操作" class="headerlink" title="4. 初始化操作"></a>4. 初始化操作</h4><p>   在MainActivity.java的主要代码如下:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line">mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview_vertical);</div><div class="line">SimpleAdapter simpleAdapter = <span class="keyword">new</span> SimpleAdapter(dataset, <span class="keyword">this</span>);</div><div class="line">mRecyclerView.setAdapter(simpleAdapter);</div><div class="line"><span class="comment">// 创建一个线性布局管理器</span></div><div class="line">LinearLayoutManager layoutManager = <span class="keyword">new</span> LinearLayoutManager(<span class="keyword">this</span>);</div><div class="line">layoutManager.setOrientation(LinearLayoutManager.VERTICAL);</div><div class="line"><span class="comment">// 设置布局管理器&#160;&#160;&#160;</span></div><div class="line">mRecyclerView.setLayoutManager(layoutManager);</div><div class="line">mRecyclerView.addItemDecoration(<span class="keyword">new</span> Decoration(<span class="keyword">this</span>));</div></pre></td></tr></table></figure>
<p>   Demo中实现的效果如下:</p>
<p><img src="/images/2017-1-14-1.jpg" alt="image"></p>
<h3 id="RecyclerView的四大组件"><a href="#RecyclerView的四大组件" class="headerlink" title="RecyclerView的四大组件"></a>RecyclerView的四大组件</h3><h4 id="Adapter"><a href="#Adapter" class="headerlink" title="Adapter"></a>Adapter</h4><p>   RecyclerView使用的Adapter与ListView使用的BaseAdapter类似,但是,前者定义的Adapter必须继承自RecyclerView.Adapter,内部必须重写三个方法,oncreateViewHolder()onbindViewHolder()getItemCount(),onCreateViewHolder()类似于BaseAdapter中的getview(),ListView可以选择使用ViewHolder()但RecyclerView为了回收资源,必须使用ViewHolder。先对比两者子类部分代码:</p>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> View <span class="title">getView</span><span class="params">(<span class="keyword">int</span> position, View convertView, ViewGroup parent)</span> </span>{</div><div class="line"> ViewHolder holder = <span class="keyword">null</span>;</div><div class="line"> <span class="comment">//如果缓存convertView为空,则需要创建View</span></div><div class="line"> <span class="keyword">if</span>(convertView == <span class="keyword">null</span>)</div><div class="line"> {</div><div class="line"> holder = <span class="keyword">new</span> ViewHolder();</div><div class="line"> <span class="comment">//根据自定义的Item布局加载布局</span></div><div class="line"> convertView = mInflater.inflate(R.layout.list_item, <span class="keyword">null</span>);</div><div class="line"> holder.img = (ImageViewShadow)convertView.findViewById(R.id.img);</div><div class="line"> holder.title = (TextView)convertView.findViewById(R.id.tv);</div><div class="line"> holder.info = (TextView)convertView.findViewById(R.id.info);</div><div class="line"> <span class="comment">//将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag</span></div><div class="line"> convertView.setTag(holder);</div><div class="line"> }<span class="keyword">else</span></div><div class="line"> {</div><div class="line"> holder = (ViewHolder)convertView.getTag();</div><div class="line"> }</div><div class="line"></div><div class="line"> Drawable D = StrokeDrawableUtils.createStrokeDrawable(getResources().getDrawable(R.drawable.mail), getResources());</div><div class="line"> holder.img.setImageDrawable(D);</div><div class="line"> ho.setText((String)data.get(position).get(<span class="string">"title"</span>));</div><div class="line"> holder.info.setText((String)data.get(position).get(<span class="string">"info"</span>));</div><div class="line"></div><div class="line"> <span class="keyword">return</span> convertView;</div><div class="line">}</div></pre></td></tr></table></figure>
<hr>
<figure class="highlight java"><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></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> ViewHolder <span class="title">onCreateViewHolder</span><span class="params">(ViewGroup viewGroup, <span class="keyword">int</span> i)</span> </span>{</div><div class="line"> View view = mInflater.inflate(R.layout.activity_index_item,</div><div class="line"> viewGroup, <span class="keyword">false</span>);</div><div class="line"> <span class="comment">//创建viewHolder对象和绑定viewHolder內的所有组件</span></div><div class="line"> ViewHolder viewHolder = <span class="keyword">new</span> ViewHolder(view);</div><div class="line"></div><div class="line"> viewHolder.mImg = (ImageView) view</div><div class="line"> .findViewById(R.id.id_index_gallery_item_image);</div><div class="line"> viewHolder.mTxt = (TextView)view.findViewById(R.id.id_index_gallery_item_text);</div><div class="line"> <span class="keyword">return</span> viewHolder;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onBindViewHolder</span><span class="params">(<span class="keyword">final</span> ViewHolder viewHolder, <span class="keyword">final</span> <span class="keyword">int</span> i)</span> </span>{</div><div class="line"> viewHolder.mImg.setImageResource(mDatas.get(i));</div><div class="line"> viewHolder.mTxt.setText(String.valueOf(i));</div><div class="line"> ....</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure>
<p>   对比以上代码,可以看出在RecyclerView中, ViewHolder直接充当缓存的单位,然后convertView作为ViewHolder的成员变量保持在ViewHolder中,也就是说,假设没有屏幕显示10个条目,则会创建10个ViewHolder缓存起来,每次复用的是ViewHolder,所以他把getView这个方法变为了onCreateViewHolder,而ListView的复用机制则是利用静态的holder把conertiew里面包含的所有组件保存起来,并通过setTag将其与conertView捆绑在一起,convertView是复用对象。</p>
<h4 id="ItemDecoration"><a href="#ItemDecoration" class="headerlink" title="ItemDecoration"></a>ItemDecoration</h4><p>   Decoration意为修饰,android的开发文档中有这样的说明:ItemDecoration允许程序添加自定义的绘画或者布局边距,常用于分割列表子项,突显视觉上的界限。这类似于listView中的devider,但listView中所画的分割线是在Listview内部实现,对于开发者来说,灵活性较低。在新的RecyclerView中很好的解决这个问题,RecycView把对Decoration的控制交给了开发者,RecyclerView默认不带Decoration,但继承自RecyclerView.ItemDecoration开发者通过重写public void onDrawOver(Canvas c, RecyclerView parent)和public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent)等,结合CardView的使用可以实现不错的视觉效果,下面为默认模式和加入简单划线对比:</p>
<p> <img src="/images/2017-1-14-3.png" alt="image"> <img src="/images/2017-1-14-2.png" alt="image"></p>
<h4 id="LayoutManager"><a href="#LayoutManager" class="headerlink" title="LayoutManager"></a>LayoutManager</h4><p>   这个类决定视图被放在画面中哪个位置,但这只是它的众多职责之一。它可以管理滚动和循环利用,ListView则不能设置为横向。在最新的support v7 中LayoutManager有三个实现类,LinearlayoutManager,GridLayoutManager和StaggeredGridLayoutManager,LayoutManager可以模拟列表的视图,但是没有页眉和页尾。开发者可以仿照原生给出的LinearLayoutManager代码创建一个BaseLayoutManager,并且基于此进行扩展。而在Android L以前,为了给LIstView后期进行扩展,ListVIew的主体功能实现都放在AbsListView,然后通过ListView,和GridVIew实现不同的布局,而在RecyclerVIew中则可以通过设置不同的LayoutManager达到此效果。下面给出RecyclerVIew不同的布局效果:</p>
<p> <img src="/images/2017-1-14-4.png" alt="image"> <img src="/images/2017-1-14-5.png" alt="image"><br> <img src="/images/2017-1-14-6.png" alt="image"></p>
<p>   另外需要说明一下,使用RecylerView时必须加入LayoutManager,否则会出现报错。</p>
<h4 id="ItemAnimator"><a href="#ItemAnimator" class="headerlink" title="ItemAnimator"></a>ItemAnimator</h4><p>   在ListView中我们通常在Adatper 的getview()的时候对特定的item做动画。在RecyclerView中加入了新的实现方法。ItemAnimator同样是RecyclerView中的的抽象类,在V7包中给出了默认的实现类DefaultItemAnimator(渐隐),开发者同样的可以通过继承RecyclerView.ItemAnimator,参考DefaultAnimator建立BaseItemAnimator,然后对其进行扩展打造不同的动画效果,使用时通过调用Recycler.Adapter中的notifyItemChanged()notifyItemInserted()等方法触发,如果是使用默认的动画效果,直接添加如下代码即可。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> DefaultItemAnimator defaultItemAnimator = <span class="keyword">new</span> DefaultItemAnimator();</div><div class="line">recyclerView.setItemAnimator(defaultItemAnimator);</div></pre></td></tr></table></figure>
<p> <img src="/images/2017-1-14-7.gif" alt="image"></p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[Mvc、Mvp、Mvvm的使用]]></title>
<url>http://yoursite.com/2017/01/09/Mvc%E3%80%81Mvp%E3%80%81Mvvm%E7%9A%84%E5%8C%BA%E5%88%AB/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>MVC的概念很早就知道,现在发现还有MVP、MVVM,那么这些设计模式有什么区别呢?简单谈一下自己的理解</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><h2 id="前言-1"><a href="#前言-1" class="headerlink" title="前言"></a>前言</h2><p>   MVC、MVP和MVVM都是为了解决界面呈现和逻辑代码分离而出现的模式。经典的MVC模式是M-V-X模式的老祖宗,MVP和MVVM都是在MVC的基础上演化而来,和MVC框架模式一样,Model模型处理数据代码。这些架构的目的都是为了提高代码的复用率、降低代码的耦合度、便于模块测试、版本的迭代更新,下面对每个架构进行简单的介绍与使用。</p>
<h2 id="Mvc架构"><a href="#Mvc架构" class="headerlink" title="Mvc架构"></a>Mvc架构</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>   MVC全名是Model View Controller,如下图,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑,是Java企业级应用的典型架构,当然Android中界面部分也采用了当前比较流行的MVC框架,笔者在最开始接触android的时候用的比较多的是Mvc架构。</p>
<p><img src="/images/2017-1-4.png" alt="image"></p>
<p align="center">Mvc模式</p>
<p>   如上图所示,其中M层处理数据,业务逻辑等;V层处理界面的显示结果;C层起到桥梁的作用,来控制V层和M层通信以此来达到分离视图显示和业务逻辑层。</p>
<h3 id="Android中的Mvc"><a href="#Android中的Mvc" class="headerlink" title="Android中的Mvc"></a>Android中的Mvc</h3><p>   在Android中:</p>
<ol>
<li>视图层:一般采用XML文件进行界面的描述,这些XML可以理解为AndroidApp的View。使用的时候可以非常方便的引入。同时便于后期界面的修改。逻辑中与界面对应的id不变化则代码不用修改,大大增强了代码的可维护性。</li>
<li>控制层:Android的控制层的重任通常落在了众多的Activity的肩上。这句话也就暗含了不要在Activity中写代码,要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Actiivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。</li>
<li>模型层(Model):我们针对业务模型,建立的数据结构和相关的类,就可以理解为AndroidApp的Model,Model是与View无关,而与业务相关的。对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。就是应用程序中二进制的数据。</li>
</ol>
<h3 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h3><p>   请访问下面地址下载代码<a href="https://github.com/KidSea/CasualProject" target="_blank" rel="external">Mvc</a>,例子很简单,就是一个验证登入的例子,但是能很好的代入Mvc的特点。</p>
<h3 id="Android中的Mvc的缺点"><a href="#Android中的Mvc的缺点" class="headerlink" title="Android中的Mvc的缺点"></a>Android中的Mvc的缺点</h3><p>   MVC虽然将界面呈现和逻辑代码分离了,但是在实际的Android开发中并没有完全起到想要的作用。View对应的XML文件实际能做的事情很少,很多界面显示由Controllor对应的Activity给做了,这样使得Activity变成了一个类似View和Controllor之间的一个东西。如果是小型项目,MVC是没任何问题的。因为项目比较小嘛,开发周期比较短,Controllor臃肿点也可以理解。假设项目越来越来,尤其是再加上比较复杂的逻辑,这时候一个Activity几千行代码就比较蛋疼了,再加点迷之缩进,那酸爽~~啧啧。所以MVC比较适用于快速开发的小型项目。</p>
<p>   因为在在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户 界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。</p>
<h2 id="Mvp架构"><a href="#Mvp架构" class="headerlink" title="Mvp架构"></a>Mvp架构</h2><h3 id="概述-1"><a href="#概述-1" class="headerlink" title="概述"></a>概述</h3><p>   MVP从更早的MVC框架演变过来,与MVC有一定的相似性:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。</p>
<p><img src="/images/2017-1-4-2.png" alt="image"></p>
<p align="center">Mvp模式</p>
<p>   MVP框架由3部分组成:View负责显示,Presenter负责逻辑处理,Model提供数据。在MVP模式里通常包含3个要素(加上View interface是4个):</p>
<ul>
<li><p>View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity)</p>
</li>
<li><p>Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合)</p>
</li>
<li><p>Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。</p>
</li>
<li><p>View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试</p>
</li>
</ul>
<h3 id="与Mvc的区别"><a href="#与Mvc的区别" class="headerlink" title="与Mvc的区别"></a>与Mvc的区别</h3><p>   两种模式的主要区别:<br>View与Model并不直接交互,而是通过与Presenter交互来与Model间接交互。而在MVC中View可以与Model直接交互<br>通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。而Controller是基于行为的,并且可以被多个View共享,Controller可以负责决定显示哪个View<br>Presenter与View的交互是通过接口来进行的,更有利于添加单元测试。</p>
<h3 id="例子-1"><a href="#例子-1" class="headerlink" title="例子"></a>例子</h3><p>   请访问下面地址下载代码<a href="https://github.com/KidSea/CasualProject" target="_blank" rel="external">Mvp</a> ,例子是在Mvc的基础先进行改进的,从Mvp的例子里可以看出:</p>
<ul>
<li>在MVP中,Activity的代码不臃肿;</li>
<li>在MVP中,Model(IUserModel的实现类)的改动不会影响Activity(View),两者也互不干涉,而在MVC中会;</li>
<li>在MVP中,IUserView这个接口可以实现方便地对Presenter的测试;</li>
<li>在MVP中,UserPresenter可以用于多个视图,但是在MVC中的Activity就不行。</li>
</ul>
<h3 id="Mvp的缺点"><a href="#Mvp的缺点" class="headerlink" title="Mvp的缺点"></a>Mvp的缺点</h3><p>   MVP模式虽然很好,但是增加了很多的接口和实现类。代码逻辑虽然清晰,但是代码量要庞大一些。当刚接手一个烂尾的MVP模式,如果事先没了解过MVP,会不会一脸的懵逼。所以MVP比较适用于中小型的项目,大型项目慎用。</p>
<h2 id="Mvvm架构"><a href="#Mvvm架构" class="headerlink" title="Mvvm架构"></a>Mvvm架构</h2><h3 id="概述-2"><a href="#概述-2" class="headerlink" title="概述"></a>概述</h3><p>   MVVM可以算是MVP的升级版,其中的VM是ViewModel的缩写,ViewModel可以理解成是View的数据模型和Presenter的合体,ViewModel和View之间的交互通过Data Binding完成,而Data Binding可以实现双向的交互,这就使得视图和控制层之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity的压力。</p>
<p><img src="/images/2017-1-4-3.png" alt="image"></p>
<p align="center">Mvc模式</p>
<h3 id="架构的演进"><a href="#架构的演进" class="headerlink" title="架构的演进"></a>架构的演进</h3><p>   MVC -> MVP -> MVVM 这几个软件设计模式是一步步演化发展的,MVVM 是从 MVP 的进一步发展与规范,MVP 隔离了MVC中的 M 与 V 的直接联系后,靠 Presenter 来中转,所以使用 MVP 时 P 是直接调用 View 的接口来实现对视图的操作的,这个 View 接口的东西一般来说是 showData、showLoading等等。M 与 V已经隔离了,方便测试了,但代码还不够优雅简洁,所以 MVVM 就弥补了这些缺陷。在 MVVM 中就出现的 Data Binding 这个概念,意思就是 View 接口的 showData 这些实现方法可以不写了,通过 Binding 来实现。</p>
<h3 id="例子-2"><a href="#例子-2" class="headerlink" title="例子"></a>例子</h3><p>   请访问下面地址下载代码<a href="https://github.com/KidSea/CasualProject" target="_blank" rel="external">Mvvm</a> ,对于Mvvm读者用的不多,所以只能是班门弄斧了,想要多了解的话,去问问度娘或谷歌吧。</p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[读深入理解Java虚拟机]]></title>
<url>http://yoursite.com/2017/01/08/%E7%AC%AC%E4%B8%89%E7%AB%A0/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>简单谈下Java虚拟机的垃圾回收机制</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><h2 id="垃圾回收机制"><a href="#垃圾回收机制" class="headerlink" title="垃圾回收机制"></a>垃圾回收机制</h2><h3 id="前言-1"><a href="#前言-1" class="headerlink" title="前言"></a>前言</h3><p>   对于Java来说,垃圾回收大部分人都把这个技术作为其伴生的产物,但是实际上GC技术的历史远比Java久远。并且对于我们的程序来说,垃圾回收机制的存在是十分有必要的,在通常情况下,垃圾收集对性能的影响一般有以下几个一般有以下几点:</p>
<ul>
<li>内存泄露</li>
<li>程序暂停</li>
<li>程序吞吐量下降</li>
<li>响应时间慢</li>
</ul>
<h3 id="垃圾收集的一些基本概念"><a href="#垃圾收集的一些基本概念" class="headerlink" title="垃圾收集的一些基本概念"></a>垃圾收集的一些基本概念</h3><ul>
<li>Concurrent Collector: 收集的同时可运行其他的工作进程。</li>
<li>Parallel Collector: 使用多CPU进行垃圾收集。</li>
<li>Stop-the-word(STW): 收集时必须暂停其他所有的工作进程。</li>
<li>Sticky-reference-count: 对于使用“引用计数”(reference count)算法的GC,如果对象的计数器溢出,则起不到标记某个对象是垃圾的作用了,这种错误称为sticky-reference-count problem,通常可以增加计数器的bit数来减少出现这个问题的几率,但是那样会占用更多空间。一般如果GC算法能迅速清理完对象,也不容易出现这个问题。</li>
<li>Mutator:mutate的中文是变异,在GC中即是指一种JVM程序,专门更新对象的状态的,也就是让对象“变异”成为另一种类型,比如变为垃圾。</li>
<li>On-the-fly:用来描述某个GC的类型:on-the-fly reference count garbage collector,此GC不用标记而是通过引用计数来识别垃圾。</li>
<li>Generational gc:这是一种相对于传统的“标记-清理”技术来说,比较先进的gc,特点是把对象分成不同的generation,即分成几代人,有年轻的,有年老的。这类gc主要是利用计算机程序的一个特点,即“越年轻的对象越容易死亡”,也就是存活的越久的对象越有机会存活下去。</li>
</ul>
<h3 id="吞吐量与响应时间"><a href="#吞吐量与响应时间" class="headerlink" title="吞吐量与响应时间"></a>吞吐量与响应时间</h3><p>   牵扯到垃圾收集,还需要搞清楚吞吐量与响应时间的含义</p>
<ul>
<li>吞吐量是对单位时间内完成的工作量的量度。如:每分钟的 Web 服务器请求数量。</li>
<li>响应时间是提交请求和返回该请求的响应之间使用的时间。如:访问Web页面花费的时间。</li>
</ul>
<p>   吞吐量与访问时间的关系很复杂,有时可能以响应时间为代价而得到较高的吞吐量,而有时候又要以吞吐量为代价得到较好的响应时间。而在其他情况下,一个单独的更改可能对两者都有提高。通常,平均响应时间越短,系统吞吐量越大;平均响应时间越长,系统吞吐量越小; 但是,系统吞吐量越大,未必平均响应时间越短;因为在某些情况(例如,不增加任何硬件配置)吞吐量的增大,有时会把平均响应时间作为牺牲,来换取一段时间处理更多的请求。</p>
<p>   针对于Java的垃圾回收来说,不同的垃圾回收器会不同程度地影响这两个指标。例如:并行的垃圾收集器,其保证的是吞吐量,会在一定程度上牺牲响应时间。而并发的收集器,则主要保证的是请求的响应时间。</p>
<h3 id="GC的回收流程"><a href="#GC的回收流程" class="headerlink" title="GC的回收流程"></a>GC的回收流程</h3><ol>
<li>找出堆中活着的对象</li>
<li>释放死对象占用的资源</li>
<li>定期调整活对象的位置</li>
</ol>
<h3 id="GC算法"><a href="#GC算法" class="headerlink" title="GC算法"></a>GC算法</h3><ul>
<li>Mark-Sweep 标记-清除</li>
<li>Mark-Sweep-Compact 标记-整理</li>
<li>Copying Collector 复制算法</li>
<li>Mark-标记从”GC roots”开始扫描(这里的roots包括线程栈、静态常量等),给能够沿着roots到达的对象标记为”live”,最终所有能够到达的对象都被标记为”live”,而无法到达的对象则为”dead”。效率和存活对象的数量是线性相关的。</li>
<li>Sweep-清除扫描堆,定位到所有”dead”对象,并清理掉。效率和堆的大小是线性相关的。</li>
<li>Compact-压缩对于对象的清除,会产生一些内存碎片,这时候就需要对这些内存进行压缩、整理。包括:relocate(将存货的对象移动到一起,从而释放出连续的可用内存)、remap(收集所有的对象引用指向新的对象地址)。效率和存活对象的数量是线性相关的。</li>
<li>Copy-复制将内存分为”from”和”to”两个区域,垃圾回收时,将from区域的存活对象整体复制到to区域中。效率和存活对象的数量是线性相关的。</li>
</ul>
<p>   其中,Copy对比Mark-sweep</p>
<ol>
<li>内存消耗:copy需要两倍的最大live set内存;mark-sweep则只需要一倍。</li>
<li>效率上:copy与live set成线性相关,效率高;mark-sweep则与堆大小线性相关,效率较低。</li>
</ol>
<h3 id="分代收集"><a href="#分代收集" class="headerlink" title="分代收集"></a>分代收集</h3><p>   分代收集是目前比较先进的垃圾回收方案。有以下几个相关理论:</p>
<ul>
<li>分代假设:大部分对象的寿命很短,“朝生夕死”,重点放在对年青代对象的收集,而且年青代通常只占整个空间的一小部分。</li>
<li>把年青代里活的很长的对象移动到老年代。</li>
<li>只有当老年代满了才去收集。</li>
<li>收集效率明显比不分代高。</li>
</ul>
<p>   HotSpot虚拟机的分代收集,分为一个Eden区、两个Survivor去以及Old Generation/Tenured区,其中Eden以及Survivor共同组成New Generatiton/Young space。通常将对New Generation进行的回收称为Minor GC;对Old Generation进行的回收称为Major GC,但由于Major GC除并发GC外均需对整个堆以及Permanent Generation进行扫描和回收,因此又称为Full GC。</p>
<p>   分代收集中典型的垃圾收集算法组合描述如下:</p>
<ul>
<li>年青代通常使用Copy算法收集,会stop the world</li>
<li>老年代收集一般采用Mark-sweep-compact, 有可能会stop the world,也可以是concurrent或者部分concurrent。</li>
</ul>
<p>   那么何时进行Minor GC、何时进行Major GC? 一般的过程如下:</p>
<ul>
<li>对象在Eden Space完成内存分配</li>
<li>当Eden Space满了,再创建对象,会因为申请不到空间,触发Minor GC,进行New(Eden + S0 或 Eden S1) Generation进行垃圾回收</li>
<li>Minor GC时,Eden Space不能被回收的对象被放入到空的Survivor(S0或S1,Eden肯定会被清空),另一个Survivor里不能被GC回收的对象也会被放入这个Survivor,始终保证一个Survivor是空的</li>
<li>在Step3时,如果发现Survivor区满了,则这些对象被copy到old区,或者Survivor并没有满,但是有些对象已经足够Old,也被放入Old Space。</li>
<li>当Old Space被放满之后,进行Full GC</li>
</ul>
<p>   但这个具体还要看JVM是采用的哪种GC方案。总而言之,内存回收和垃圾收集是比较复杂的原理,很多时候是影响系统性能、并发能力的主要的因素之一,深入理解其运作,对编写的程序有一点影响力。</p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[逝去的2016,归来的2017]]></title>
<url>http://yoursite.com/2017/01/01/%E6%88%91%E7%9A%842016%E6%80%BB%E7%BB%93/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p><strong>致我已逝去的2016,迎我即将到来的2017</strong></p>
<hr>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="题记"><a href="#题记" class="headerlink" title="题记"></a>题记</h2><p>   <strong>人生中总有一段时光会让人突然成长,突然想明白很多事,好似看懂了全世界。</strong></p>
<h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><h3 id="小谈"><a href="#小谈" class="headerlink" title="小谈"></a>小谈</h3><p>   借着跨年的喜悦气氛,我翻阅了一下自己空间里整个2016年所记录下来的说说踪迹,感觉2016年像梦一样的从我脑海里一闪而过,在这一年里,我仿佛做了很多事情,经历了很多事情,又仿佛经历的没有想象的那么多,感觉这些记忆是那么近,又那么的远,这大概就叫矛盾吧!!</p>
<p>   经常会听到身边有人跟我说,“你是我身边最会写说说的男的,你看你空间里面那么多说说”。哈哈,我承认他说的没错,但是我会去想,为什么我会时不时的发个说说,感觉像是在证明着什么或者是记录着什么。</p>
<p>   我给自己的解释是,一方面,这也许就是害怕孤独的一种表现,可能知道我的人,都知道我是一个喜欢热闹的、喜欢瞎搞的、喜欢交朋友、喜欢….,发说说或者是朋友是为了让大家时刻记着,嗯,我身边有这么一个人,他喜欢发说说,哈哈;另外一方面我可能是想多记录下自己一天中经历的事情的所感所想,这样,也许在未来的某个日子,我去翻这些说说的时候,我能记起当时这天我在经历着生命,可能会让自己有一种回味的感觉,我不知道大家有没有写日记的习惯,反正我很少会去写,因为有的时候记些流水账,对我来说,很无趣,所以可能说说跟朋友圈就是我日记的一个替代品,只是想做为自己的一种习惯在延续着,哈哈。</p>
<h3 id="回顾2016"><a href="#回顾2016" class="headerlink" title="回顾2016"></a>回顾2016</h3><p>   2016的大事件太多,太多,“与队友们完成美国数学建模比赛”,“在重庆遇见人生的一场雪(几十年不遇)”,“给弟弟的一封信”,“美国小哥的礼物”,“以为朋友在台湾被地震牵连”,“在家过年”,“看了一年很棒的NBA全明星”,“协会招新”,“校招提前批笔试”,“小李子圆了奥斯卡梦”,“完成2次课程设计”,“模拟双选会”,“全国计算机等级三级考试考了个59分(这尼玛)”,“库昊全票MVP”,“协会换届”,“第一次面试”,“得罪最不想得罪的人”,“见证LBJ带领的骑士创造历史”,“搭博客”,“找工作”,“面试魅族”,“面试华为”,“感受前一天天堂,后一天地狱的人生”,“找到工作”,“离校”,“实习”,“初入社会”,“坚持的事”等等…..</p>
<h4 id="找工作"><a href="#找工作" class="headerlink" title="找工作"></a>找工作</h4><p>   对于找工作,如果现在有人问我,你后不后悔不继续读书而选择工作,我的答案是肯定的;如果有人问,你后不后悔进入自己选择的这家公司,答案也是肯定的。因为既然是自己选择的路,为什么要去后悔呢,可能最多的是有遗憾吧,我也庆幸自己能够足够幸运找到合适自己的工作,以及能够在这么一个大家庭里工作。</p>
<h4 id="离校"><a href="#离校" class="headerlink" title="离校"></a>离校</h4><p>   时间总是不和任何人开玩笑,悄无声息地就从我们手中悄悄溜走。转眼之间就到大四了,找到了工作,也为自己盘算着离校的时间去实习。虽然以前不觉得,但是真的一个人如果想到自己要离开校园了,离开自己一直生活的环境,离开自己最熟悉的那群人,多少都会有些伤感。依稀记得,那天踏出校门,回头望去,只觉得那就是青春,可能以后都经历不了了,但是还是很高兴你在我的世界里出现。</p>
<h4 id="初入社会"><a href="#初入社会" class="headerlink" title="初入社会"></a>初入社会</h4><p>   一直以来我都是一个比较独立自主的人,所以踏入社会,我可能会相对来说更容易适应。来到魅族实习,有了新的环境,认识了新的人与事。感受到了魅族的热情,感受到工作的热情,感受到了珠海的魅力,还有很多….,我喜欢这样的生活,充实而又满足,初入社会,我要做的还有很多,我相信未来会更好。</p>
<h4 id="见证历史"><a href="#见证历史" class="headerlink" title="见证历史"></a>见证历史</h4><p>   不得不说,2016年是我看NBA以来最热血澎湃的一年。首先,今年的NBA全明星上,见证了可能是历史上少有的,精彩的扣篮大赛,见证了两个扣篮新星的奇迹表演;其次,见证了LBJ带领骑士创造了历史;最后,见证LBJ在新赛季创新的一个个新的历史,感谢有你。</p>
<h4 id="坚持的事"><a href="#坚持的事" class="headerlink" title="坚持的事"></a>坚持的事</h4><ol>
<li>健身,强度不是很大,但是我相信只要一直坚持下去,至少对身体是有好处的。</li>
<li>写博客,今年才开始写博客,记录自己的学习经历。</li>
<li>看书,读万卷书,行万里路。</li>
<li>看电影,看经典的电影,陶冶情操。</li>
<li>周末出去走走,希望不要宅在家里。</li>
<li>学习,巩固技术知识。</li>
<li>看新闻,看资讯,了解前沿技术,知识。</li>
<li>学英语。</li>
<li>思考。</li>
<li>理想。</li>
</ol>
<h4 id="我的成长"><a href="#我的成长" class="headerlink" title="我的成长"></a>我的成长</h4><ul>
<li>社交圈变广,慢慢扩展视野;</li>
<li>慢慢学会管理时间,明白时间的重要性;</li>
<li>初入社会,慢慢适应社会;</li>
<li>明白了这世界上有些事是有规律的,违背了规律可能会遇到麻烦;</li>
<li>制定了一个小目标</li>
<li>…</li>
</ul>
<h3 id="2017年展望"><a href="#2017年展望" class="headerlink" title="2017年展望"></a>2017年展望</h3><p>   保持积极的态度,不骄不躁;</p>
<p>   严肃对待时间,记录生活;</p>
<p>   多出去走走,体验生活;</p>
<p>   坚持看书,看电影;</p>
<p>   坚持健身,锻炼身体;</p>
<p>   技术更上一层楼;</p>
<p>   让家慢慢变好;</p>
<p>   当然也希望自己越活越年轻,哈哈哈哈哈;</p>
<p>   还有很多…</p>
<h3 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h3><p>   人生最好的心态是平静,我知道自己可能无法做到,但是,我会慢慢向它靠拢。</p>
<p>   2017年给自己的第一句话是,“当自己做了正确的事,就会感觉自己在地球的重量又会增加了些”。</p>
<p>   2016年,感谢遇到的所有人,遇到的所有事,2017年,加油!</p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[读深入理解Java虚拟机]]></title>
<url>http://yoursite.com/2016/12/31/%E7%AC%AC%E4%BA%8C%E7%AB%A0/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>看了第二章的内容,大致了解了下Java虚拟机的内存分划,以及内存操作导致的内存溢出异常,对于我以后使用Java编程有很大帮助</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><h2 id="Java-存储区域与内存溢出异常"><a href="#Java-存储区域与内存溢出异常" class="headerlink" title="Java 存储区域与内存溢出异常"></a>Java 存储区域与内存溢出异常</h2><h3 id="前言-1"><a href="#前言-1" class="headerlink" title="前言"></a>前言</h3><p>   对于c/c++的程序开发人员来说,内存管理既是他们的权力也是让他们头疼的问题,而对于Java开发人员来说,在虚拟机的帮助下,我们不需要为每个new操作去配对delete/free代码,因此也不容易出现内存泄漏和内存溢出的问题,但是如果不了解虚拟机的内存管理机制,一旦出现内存问题,很难排查问题,笔者在读完<strong>深入理解Java虚拟机</strong>后做了以下的笔记,希望对于一些初识者有一些帮助。</p>
<h3 id="运行时数据区域"><a href="#运行时数据区域" class="headerlink" title="运行时数据区域"></a>运行时数据区域</h3><p>   Java虚拟机在执行Java程序的过程中把它所管理的内存划分成若干个不同的数据区域,各自在运行时起到不同的用途。其具体分区情况,如下图所示。</p>
<p><img src="/images/2016-12-31.png" alt=""></p>
<p align="center">Java虚拟机运行事数据区</p>
<p>   下面对各个区域进行简单的介绍</p>
<ol>
<li>程序计数器: 一块较小的内存单元,是当前线程所执行的字节码的行号指示器;</li>
<li>Java虚拟机栈:描述Java方法执行的内存模型,每个方法从调用到执行完毕,对应于一个栈帧在虚拟机栈中入栈到出栈的过程;</li>
<li>本地方法栈: 与虚拟机栈发挥的作用比较相似,虚拟机栈为虚拟机执行Java方法服务,而本地方法栈是虚拟机使用到的Native方法服务。</li>
<li>Java堆: Java堆是Java虚拟机所管理的内存中最大的一块,是所有线程共享的一块内存区域,在虚拟机启动时创建,用以存放对象实例。</li>
<li>方法区: 与Java堆一样,是各个线程共享的内存区域,用以存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。</li>
<li>运行时常量池: 方法区的一部分,用以存放编译期生成的各种字面量和符号作用;</li>
<li>直接内存: 这部分不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区,但是在运行是这个部分内存也频繁的使用。</li>
</ol>
<h3 id="虚拟机对象"><a href="#虚拟机对象" class="headerlink" title="虚拟机对象"></a>虚拟机对象</h3><h4 id="对象的创建"><a href="#对象的创建" class="headerlink" title="对象的创建"></a>对象的创建</h4><p>   Java是一门面向对象的编程语言,在Java程序运行过程种无时无刻都有对象被创建出来。而创建对象的命令就是new,当虚拟机遇到一条new指令的时候,首先将去检查这个指令的参数是否能在常量池种定位到一个类的符号作用,并且检查这个符号引用代表的类是否被加载、解析和初始化过。如果没有,那就先执行相应的类加载过程,在类加载检查通过后,虚拟机才会对新生的对象分配内存,并且内存大小可确定,在内存分配完后,虚拟机要将内存分配到的内存空间初始化为零值,为了保证对象实例在Java代码中可以不赋值直接使用,接下来虚拟机将会对对象进行必要的设置。</p>
<p>   在完成以上工作后,一个对象才算真正的被创建起来了。</p>
<h4 id="对象的内存布局"><a href="#对象的内存布局" class="headerlink" title="对象的内存布局"></a>对象的内存布局</h4><p>   在虚拟机中,对象在内存中的存储的布局被分为3块区域:对象头、实例数据和对齐填充。</p>
<ol>
<li>对象头: 对象头一部分用以存储对象自身的运行数据,一部分是它指向的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;</li>
<li>实例数据: 是对象真正存储的有效数据,也是在程序代码中所定义的各种类型的字段内容;</li>
<li>对齐填充: 这部分并不是必然存在的,也没有特殊的含义,只是起占位符的作用。</li>
</ol>
<h4 id="对象的访问定位"><a href="#对象的访问定位" class="headerlink" title="对象的访问定位"></a>对象的访问定位</h4><p>   建立对象是为了使用对象,我们的Java程序需要通过栈上的reference数据来操作堆上的具体对象。</p>
<p>   Java虚拟机规范规定了一个指向对象的引用,但是没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,而是取决于虚拟机的实现而定。目前主流的访问方式有使用句柄和直接指针这两种方式。</p>
<ul>
<li>使用句柄,Java堆中会划出一块内存来做句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息,其原理如下图所示。</li>
</ul>
<p><img src="/images/2016-12-31-1.png" alt=""></p>
<p align="center">使用句柄访问</p>
<ul>
<li>使用直接指针访问,那么Java堆对象的布局需要考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址,其原理如下图所示。</li>
</ul>
<p><img src="/images/2016-12-31-2.png" alt=""></p>
<p align="center">使用直接指针访问</p>
<p>   两种对象访问方式各有优势,使用句柄来访问的最大好处就是reference中存储的是隐定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而reference本身不需要修改;而使用直接指针访问的最大好处就是速度快,节省时间开销。</p>
<h3 id="内存溢出异常"><a href="#内存溢出异常" class="headerlink" title="内存溢出异常"></a>内存溢出异常</h3><p>   在Java虚拟机规范中,定义了两种异常,一种是线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError;另一种是虚拟机在扩展栈的时候无法申请到足够的内存空间,会抛出OutOfMemoryError异常,这两个异常都是我们平常编写程序时,必须要注意的,比如慎用static,数据库处理游标、文件等处理后是否释放资源,图片处理是否进行压缩、回收等。</p>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[读深入理解Java虚拟机]]></title>
<url>http://yoursite.com/2016/12/31/%E7%AC%AC%E4%B8%80%E7%AB%A0/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p><strong>最近从同事借了《深入理解Java虚拟机》,想着没事读读,做做读书笔记</strong></p>
<hr>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="第一章-走进java"><a href="#第一章-走进java" class="headerlink" title="第一章 走进java"></a>第一章 走进java</h2><h3 id="前言-1"><a href="#前言-1" class="headerlink" title="前言"></a>前言</h3><p>   如今,Java不仅仅是一门编程语言,还是一个由一系列计算机软件和规范形成的技术体系,这个技术体系提供了完整的用于软件开发和跨平台不熟的支持环境,并广泛应用于嵌入式系统、移动终端、企业服务器、大型机等各个场合。其具有以下特点:</p>
<ol>
<li>结构严谨、面向对象的编程语言;</li>
<li>摆脱了硬件平台的束缚,实现了“一次编写,到处运行”的特点;</li>
<li>具有相对安全的内存管理和访问机制;</li>
<li>实现了热点代码检测和运行时编译及优化;</li>
<li>拥有一套完善的应用程序接口等…</li>
</ol>
<h3 id="Java的技术体系"><a href="#Java的技术体系" class="headerlink" title="Java的技术体系"></a>Java的技术体系</h3><p>   从传统意义上来看,Sun官方所定义的Java技术体系包括以下几个组成部分:</p>
<ul>
<li>Java程序设计语言</li>
<li>各种硬件平台上的虚拟机</li>
<li>Class文件格式</li>
<li>Java Api类库</li>
<li>来自商业机构和开源社区的第三方Java类库</li>
</ul>
<p>   我们可以把Java程序设计语言、虚拟机、Java Api类库这三部分称之为JDK就是java开发的最小环境。把Java Api类库中的子集Java Se Api和虚拟机这两部分统称为JRE,即Java运行环境。Java技术体系可以分为四个平台,分别为:</p>
<ol>
<li>Java Card:支持一些Java小程序,运行在小内存设备里;</li>
<li>Java Me: 支持Java程序运行在移动终端上;</li>
<li>Java Se: 支持面向桌面级应用的Java平台;</li>
<li>Java EE: 支持使用多层架构的企业级应用的Java平台。</li>
</ol>
<h3 id="Java发展史"><a href="#Java发展史" class="headerlink" title="Java发展史"></a>Java发展史</h3><p>   此处省略一万个字……总而言之现在发展到Java8了。</p>
<h3 id="Java虚拟机发展史"><a href="#Java虚拟机发展史" class="headerlink" title="Java虚拟机发展史"></a>Java虚拟机发展史</h3><p>   同上….</p>
<h3 id="展望Java技术的未来"><a href="#展望Java技术的未来" class="headerlink" title="展望Java技术的未来"></a>展望Java技术的未来</h3><ol>
<li>模块化:模块化是解决应用系统与技术平台越来越复杂、越来越庞大问题的一个重要途径;</li>
<li>混合语言: 如今,单一的Java开发已经无法满足当前软件的复杂需求,为了更好解决问题,混合语言层出不穷,如Clojure,Jruby,Groovy等;</li>
<li>多核并行: Cpu硬件的发展方向已经从高频率转变到多核心,随着多核时代的到来,软件开发越来越多关注并行编程,Java也更加专注;</li>
<li>进一步丰富语言,语法;</li>
<li>64位虚拟机等。</li>
</ol>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[Android源码编译]]></title>
<url>http://yoursite.com/2016/12/26/%E7%B3%BB%E7%BB%9F%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E5%88%86%E6%9E%90/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>Android源码编译学习小结</strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<h2 id="系统源码编译"><a href="#系统源码编译" class="headerlink" title="系统源码编译"></a>系统源码编译</h2><p>   笔者最近在学习安卓系统源码的编译,为了能够印象深刻,粗略的总结了以下内容,希望对我一样的初学者有一些帮助。</p>
<h3 id="系统编译的初始化指令"><a href="#系统编译的初始化指令" class="headerlink" title="系统编译的初始化指令"></a>系统编译的初始化指令</h3><p>   对Android编译环境进行初始化很简单,分为两步。第一步打开终端输入source build/envseup.sh加载所需的文件。</p>
<pre><code>$ source build/envseup.sh
including device/asusource build/envseup.shs/grouper/vendorsetup.sh
including device/asus/tilapia/vendorsetup.sh
including device/generic/armv7-a-neon/vendorsetup.sh
including device/generic/armv7-a/vendorsetup.sh
including device/generic/mips/vendorsetup.sh
including device/generic/x86/vendorsetup.sh
including device/lge/mako/vendorsetup.sh
including device/samsung/maguro/vendorsetup.sh
including device/samsung/manta/vendorsetup.sh
including device/samsung/toroplus/vendorsetup.sh
including device/samsung/toro/vendorsetup.sh
including device/ti/panda/vendorsetup.sh
including sdk/bash_completion/adb.bash
</code></pre><p>   从命令的输出可以知道,文件build/envsetup.sh在加载的过程中,又会在device目录中寻找那些名称为vendorsetup.sh的文件,并且也将它们加载到当前终端来。另外,在sdk/bash_completion目录下的adb.bash文件也会加载到当前终端来,它是用来实现adb命令的bash completion功能的。也就是说,加载了该文件之后,我们在运行adb相关的命令的时候,通过按tab键就可以帮助我们自动完成命令的输入。</p>
<p>   第二步是执行命令lunch,如下所示:</p>
<pre><code>$ lunch
You're building on Linux
Lunch menu... pick a combo:
1. full-eng
2. full_x86-eng
3. vbox_x86-eng
4. full_mips-eng
5. full_grouper-userdebug
6. full_tilapia-userdebug
7. mini_armv7a_neon-userdebug
8. mini_armv7a-userdebug
9. mini_mips-userdebug
10. mini_x86-userdebug
11. full_mako-userdebug userdata.img:将被挂载为 /data,包含了应用程序相关的数据以及和用户相关的数据。
12. full_maguro-userdebug
13. full_manta-userdebug
14. full_toroplus-userdebug
15. full_toro-userdebug
16. full_panda-userdebug
Which would you like? [full-eng]
</code></pre><p>   我们看到lunch命令输出了一个Lunch菜单,该菜单列出了当前Android源码支持的所有设备型号及其编译类型。例如,第一项“full-eng”表示的设备“full”即为模拟器,并且编译类型为“eng”即为工程机。</p>
<p>   当我们选定了一个Lunch菜单项序号(1-16)之后,按回车键,就可以完成Android编译环境的初始化过程。例如,我们选择1,可以看到以下输出:</p>
<pre><code>Which would you like? [full-eng] 1
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.2
TARGET_PRODUCT=full
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
HOST_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.8.0-31-generic-x86_64-with-Ubuntu-13.04-raring
HOST_BUILD_TYPE=release
BUILD_ID=JOP40C
OUT_DIR=out
============================================
</code></pre><p>   我们可以看到,lunch命令帮我们设置好了很多环境变量。通过设置这些环境变量,就配置好了Android编译环境。</p>
<h3 id="源码编译指令"><a href="#源码编译指令" class="headerlink" title="源码编译指令"></a>源码编译指令</h3><p>   在执行编译指令之前,为了确保编译环境的Api匹配所要编译的源码版本,我们会先进行<strong>make update-api</strong>进行Api更新,在此步骤之中可能会遇到各种问题,请读者们自行上网搜索解决,直到更新完成后执行<strong>make</strong>指令进行编译,注:对于整个系统源码编译,必须在系统源码根目录下执行。</p>
<p>   在Android编译系统在编译过程中,会通过根目录下的Makefile脚本加载build/core/main.mk脚本,接着build/core/main.mk脚本又会加载build/core/Makefile脚本,而Android系统镜像文件就是由build/core/Makefile脚本负责打包生成的。</p>
<h3 id="编译打包过程"><a href="#编译打包过程" class="headerlink" title="编译打包过程"></a>编译打包过程</h3><ol>
<li>首先,每个模块对应一个android.mk,对应于各个模块的makefile,该文件中只需定义一些变量,就能触发一个模块的编译,不同模块的编译方式不同,当然每个模块必须遵守编译规则;</li>
<li>其次,每个模块相互独立,但是利用include指令可以将各个模块,添加如main.mk文件中,并有先后顺序,最终各个零散的makefile文件汇聚成最终的makefile文件;</li>
<li>最后,通过以上过程讲所有模块编译打包。</li>
</ol>
<h3 id="打包的产物"><a href="#打包的产物" class="headerlink" title="打包的产物"></a>打包的产物</h3><p>   所有的编译产物都将位于 /out 目录下,该目录下主要有以下几个子目录:</p>
<ul>
<li>/out/host/:该目录下包含了针对主机的 Android 开发工具的产物。即 SDK 中的各种工具,例如:emulator,adb,aapt 等。</li>
<li>/out/target/common/:该目录下包含了针对设备的共通的编译产物,主要是 Java 应用代码和 Java 库。</li>
<li>/out/target/product/<product_name>/:包含了针对特定设备的编译结果以及平台相关的 C/C++ 库和二进制文件。其中,<product_name>是具体目标设备的名称。</product_name></product_name></li>
<li>/out/dist/:包含了为多种分发而准备的包,通过“make disttarget”将文件拷贝到该目录,默认的编译目标不会产生该目录。</li>
</ul>
<h3 id="编译生成的镜像文件"><a href="#编译生成的镜像文件" class="headerlink" title="编译生成的镜像文件"></a>编译生成的镜像文件</h3><p>   Build 的产物中最重要的是三个镜像文件,它们都位于 /out/target/product/<product_name>/ 目录下。</product_name></p>
<ul>
<li>system.img:包含了 Android OS 的系统文件,库,可执行文件以及预置的应用程序,将被挂载为根分区。</li>
<li>ramdisk.img:在启动时将被 Linux 内核挂载为只读分区,它包含了 /init 文件和一些配置文件。它用来挂载其他系统镜像并启动 init 进程。</li>
<li>userdata.img:将被挂载为 /data,包含了应用程序相关的数据以及和用户相关的数据。</li>
</ul>
<hr>
<p><strong>版权声明:本文为博主原创文章,转载请注明出处<a href="https://kidsea.github.io/" target="_blank" rel="external">KidSea</a></strong></p>
]]></content>
</entry>
<entry>
<title><![CDATA[程序员励志名言]]></title>
<url>http://yoursite.com/2016/11/17/%E7%A8%8B%E5%BA%8F%E5%91%98%E5%8A%B1%E5%BF%97%E5%90%8D%E8%A8%80/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><hr>
<p><strong>1、作为一个真正的程序员,首先应该尊重编程,热爱你所写下的程序,他是你的伙伴,而不是工具。 2、程序员可以让步,却不可以退缩,可以羞涩,却不可以软弱,总之,程序员必须是勇敢的。 3、编程是一种单调的生活,因此程序员比普通人需要更多的关怀,更多的友情。 4、程序不是年轻的专利,但是,他属于年轻。 </strong></p>
<a id="more"></a>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><hr>
<p>1、作为一个真正的程序员,首先应该尊重编程,热爱你所写下的程序,他是你的伙伴,而不是工具。</p>
<p>2、程序员可以让步,却不可以退缩,可以羞涩,却不可以软弱,总之,程序员必须是勇敢的。</p>
<p>3、编程是一种单调的生活,因此程序员比普通人需要更多的关怀,更多的友情。</p>
<p>4、程序不是年轻的专利,但是,他属于年轻。</p>