-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
4787 lines (4155 loc) · 658 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[View的绘制]]></title>
<url>/2019/02/27/View%E7%9A%84%E7%BB%98%E5%88%B6/</url>
<content type="html"><![CDATA[<p>View的绘制从<code>ViewRootImpl</code>中的<code>performTraversals</code>开始</p>
<p>ViewRootImpl.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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">performTraversals</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">int</span> childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);</div><div class="line"> <span class="keyword">int</span> childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);</div><div class="line"> performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);</div><div class="line">}</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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">getRootMeasureSpec</span><span class="params">(<span class="keyword">int</span> windowSize, <span class="keyword">int</span> rootDimension)</span> </span>{</div><div class="line"> <span class="keyword">int</span> measureSpec;</div><div class="line"> <span class="keyword">switch</span> (rootDimension) {</div><div class="line"></div><div class="line"> <span class="keyword">case</span> ViewGroup.LayoutParams.MATCH_PARENT:</div><div class="line"> <span class="comment">// Window can't resize. Force root view to be windowSize.</span></div><div class="line"> measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> ViewGroup.LayoutParams.WRAP_CONTENT:</div><div class="line"> <span class="comment">// Window can resize. Set max size for root view.</span></div><div class="line"> measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">default</span>:</div><div class="line"> <span class="comment">// Window wants to be an exact size. Force root view to be that size.</span></div><div class="line"> measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> measureSpec;</div><div class="line">}</div></pre></td></tr></table></figure>
<p><code>performMeasure</code>会调用View的<code>measure</code>的方法</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="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">performMeasure</span><span class="params">(<span class="keyword">int</span> childWidthMeasureSpec, <span class="keyword">int</span> childHeightMeasureSpec)</span> </span>{</div><div class="line"> ...</div><div class="line"> mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);</div><div class="line"> ...</div><div class="line">}</div></pre></td></tr></table></figure>
<p>对于普通的View来说,这里是指我们布局中的View,View的<code>measure</code>过程由<code>ViewGroup</code>传递而来。</p>
<p> <strong>ViewGroup.java</strong></p>
<p><code>ViewGroup</code>提供了一个<code>measureChildren</code>的方法用来循环遍历<code>measure</code>View。这个方法只会测量不为<code>GONE</code>的View。</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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">measureChildren</span><span class="params">(<span class="keyword">int</span> widthMeasureSpec, <span class="keyword">int</span> heightMeasureSpec)</span> </span>{</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> size = mChildrenCount;</div><div class="line"> <span class="keyword">final</span> View[] children = mChildren;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < size; ++i) {</div><div class="line"> <span class="keyword">final</span> View child = children[i];</div><div class="line"> <span class="keyword">if</span> ((child.mViewFlags & VISIBILITY_MASK) != GONE) {</div><div class="line"> measureChild(child, widthMeasureSpec, heightMeasureSpec);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><code>measureChild</code>将父View的<code>MeasureSpec</code>传入,计算出自己的<code>childMeasureSpec</code>,然后再交给<code>View.measure</code>方法。</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"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">measureChild</span><span class="params">(View child, <span class="keyword">int</span> parentWidthMeasureSpec,</span></span></div><div class="line"><span class="function"><span class="params"> <span class="keyword">int</span> parentHeightMeasureSpec)</span> </span>{</div><div class="line"> <span class="keyword">final</span> LayoutParams lp = child.getLayoutParams();</div><div class="line"></div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,</div><div class="line"> mPaddingLeft + mPaddingRight, lp.width);</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,</div><div class="line"> mPaddingTop + mPaddingBottom, lp.height);</div><div class="line"></div><div class="line"> child.measure(childWidthMeasureSpec, childHeightMeasureSpec);</div><div class="line">}</div></pre></td></tr></table></figure>
<p><code>getChildMeasureSpec</code>方法中,<code>spec</code>是父View的<code>MeasureSpec</code>。<code>padding</code>是父View的<code>padding</code>。<code>childDimension</code>是子View自己设置的大小。</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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">getChildMeasureSpec</span><span class="params">(<span class="keyword">int</span> spec, <span class="keyword">int</span> padding, <span class="keyword">int</span> childDimension)</span> </span>{</div><div class="line"> <span class="keyword">int</span> specMode = MeasureSpec.getMode(spec);</div><div class="line"> <span class="keyword">int</span> specSize = MeasureSpec.getSize(spec);</div><div class="line"></div><div class="line"> <span class="comment">//这里的size指的是父View中剩余的大小</span></div><div class="line"> <span class="keyword">int</span> size = Math.max(<span class="number">0</span>, specSize - padding);</div><div class="line"></div><div class="line"> <span class="keyword">int</span> resultSize = <span class="number">0</span>;</div><div class="line"> <span class="keyword">int</span> resultMode = <span class="number">0</span>;</div><div class="line"></div><div class="line"> <span class="keyword">switch</span> (specMode) {</div><div class="line"> <span class="comment">// Parent has imposed an exact size on us</span></div><div class="line"> <span class="keyword">case</span> MeasureSpec.EXACTLY:</div><div class="line"> <span class="keyword">if</span> (childDimension >= <span class="number">0</span>) {</div><div class="line"> resultSize = childDimension;</div><div class="line"> resultMode = MeasureSpec.EXACTLY;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (childDimension == LayoutParams.MATCH_PARENT) {</div><div class="line"> <span class="comment">// Child wants to be our size. So be it.</span></div><div class="line"> resultSize = size;</div><div class="line"> resultMode = MeasureSpec.EXACTLY;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (childDimension == LayoutParams.WRAP_CONTENT) {</div><div class="line"> <span class="comment">// Child wants to determine its own size. It can't be</span></div><div class="line"> <span class="comment">// bigger than us.</span></div><div class="line"> resultSize = size;</div><div class="line"> resultMode = MeasureSpec.AT_MOST;</div><div class="line"> }</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"></div><div class="line"> <span class="comment">// Parent has imposed a maximum size on us</span></div><div class="line"> <span class="keyword">case</span> MeasureSpec.AT_MOST:</div><div class="line"> <span class="keyword">if</span> (childDimension >= <span class="number">0</span>) {</div><div class="line"> <span class="comment">// Child wants a specific size... so be it</span></div><div class="line"> resultSize = childDimension;</div><div class="line"> resultMode = MeasureSpec.EXACTLY;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (childDimension == LayoutParams.MATCH_PARENT) {</div><div class="line"> <span class="comment">// Child wants to be our size, but our size is not fixed.</span></div><div class="line"> <span class="comment">// Constrain child to not be bigger than us.</span></div><div class="line"> resultSize = size;</div><div class="line"> resultMode = MeasureSpec.AT_MOST;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (childDimension == LayoutParams.WRAP_CONTENT) {</div><div class="line"> <span class="comment">// Child wants to determine its own size. It can't be</span></div><div class="line"> <span class="comment">// bigger than us.</span></div><div class="line"> resultSize = size;</div><div class="line"> resultMode = MeasureSpec.AT_MOST;</div><div class="line"> }</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"></div><div class="line"> <span class="comment">// Parent asked to see how big we want to be</span></div><div class="line"> <span class="keyword">case</span> MeasureSpec.UNSPECIFIED:</div><div class="line"> <span class="keyword">if</span> (childDimension >= <span class="number">0</span>) {</div><div class="line"> <span class="comment">// Child wants a specific size... let him have it</span></div><div class="line"> resultSize = childDimension;</div><div class="line"> resultMode = MeasureSpec.EXACTLY;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (childDimension == LayoutParams.MATCH_PARENT) {</div><div class="line"> <span class="comment">// Child wants to be our size... find out how big it should</span></div><div class="line"> <span class="comment">// be</span></div><div class="line"> resultSize = View.sUseZeroUnspecifiedMeasureSpec ? <span class="number">0</span> : size;</div><div class="line"> resultMode = MeasureSpec.UNSPECIFIED;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (childDimension == LayoutParams.WRAP_CONTENT) {</div><div class="line"> <span class="comment">// Child wants to determine its own size.... find out how</span></div><div class="line"> <span class="comment">// big it should be</span></div><div class="line"> resultSize = View.sUseZeroUnspecifiedMeasureSpec ? <span class="number">0</span> : size;</div><div class="line"> resultMode = MeasureSpec.UNSPECIFIED;</div><div class="line"> }</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//noinspection ResourceType</span></div><div class="line"> <span class="keyword">return</span> MeasureSpec.makeMeasureSpec(resultSize, resultMode);</div><div class="line">}</div></pre></td></tr></table></figure>
<table>
<thead>
<tr>
<th style="text-align:center">childLayoutParams//ParentSPecMode</th>
<th style="text-align:center">EXACTLY</th>
<th style="text-align:center">AT_MOST</th>
<th style="text-align:center">UNSPECIFIED</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">dp/px</td>
<td style="text-align:center">EXACTLY childSize</td>
<td style="text-align:center">EXACTLY chileSize</td>
<td style="text-align:center">EXACTLY chileSize</td>
</tr>
<tr>
<td style="text-align:center">match_parent</td>
<td style="text-align:center">EXACTLY parentSize</td>
<td style="text-align:center">AT_MOST parentSize</td>
<td style="text-align:center">UNSPECIFIED 0</td>
</tr>
<tr>
<td style="text-align:center">wrap_content</td>
<td style="text-align:center">AT_MOST parentSize</td>
<td style="text-align:center">AT_MOST parentSize</td>
<td style="text-align:center">UNSPECIFIED 0</td>
</tr>
</tbody>
</table>
<p>此时进入了View的测量</p>
<p>View.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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">measure</span><span class="params">(<span class="keyword">int</span> widthMeasureSpec, <span class="keyword">int</span> heightMeasureSpec)</span> </span>{</div><div class="line"> ...</div><div class="line"> onMeasure(widthMeasureSpec, heightMeasureSpec);</div><div class="line"> ... </div><div class="line">}</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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onMeasure</span><span class="params">(<span class="keyword">int</span> widthMeasureSpec, <span class="keyword">int</span> heightMeasureSpec)</span> </span>{</div><div class="line"> setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),</div><div class="line"> getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));</div><div class="line">}</div></pre></td></tr></table></figure>
<p>如果当前View设置了背景,则取背景的最小大小,否则取View自己的<code>mMinWidth</code>。这个<code>mMinWidth</code>是可以在布局文件中设置的。</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"><span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">getSuggestedMinimumWidth</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">return</span> (mBackground == <span class="keyword">null</span>) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());</div><div class="line">}</div></pre></td></tr></table></figure>
<p>View的测量。这个<code>size</code>是View建议的最小大小。<code>measureSpec</code>是从父View那根据父View的<code>measureSpec</code>计算出的自己的<code>measureSpec</code>。</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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">getDefaultSize</span><span class="params">(<span class="keyword">int</span> size, <span class="keyword">int</span> measureSpec)</span> </span>{</div><div class="line"> <span class="keyword">int</span> result = size;</div><div class="line"> <span class="keyword">int</span> specMode = MeasureSpec.getMode(measureSpec);</div><div class="line"> <span class="keyword">int</span> specSize = MeasureSpec.getSize(measureSpec);</div><div class="line"></div><div class="line"> <span class="keyword">switch</span> (specMode) {</div><div class="line"> <span class="keyword">case</span> MeasureSpec.UNSPECIFIED:</div><div class="line"> result = size;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> MeasureSpec.AT_MOST:</div><div class="line"> <span class="keyword">case</span> MeasureSpec.EXACTLY:</div><div class="line"> result = specSize;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> result;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>例如有如下布局</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">LinearLayout</span></span></div><div class="line"><span class="tag"> <span class="attr">xmlns:android</span>=<span class="string">"http://schemas.android.com/apk/res/android"</span></span></div><div class="line"><span class="tag"> <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></div><div class="line"><span class="tag"> <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></span></div><div class="line"><span class="tag"> <span class="attr">android:orientation</span>=<span class="string">"vertical"</span>></span></div><div class="line"> <span class="tag"><<span class="name">TextView</span></span></div><div class="line"><span class="tag"> <span class="attr">android:layout_width</span>=<span class="string">"wrap_content"</span></span></div><div class="line"><span class="tag"> <span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span></span></div><div class="line"><span class="tag"> <span class="attr">android:text</span>=<span class="string">"123"</span></span></div><div class="line"><span class="tag"> /></span></div><div class="line"><span class="tag"></<span class="name">LinearLayout</span>></span></div></pre></td></tr></table></figure>
<p>在测量的时候。由<code>LinearLayout</code>这个<code>ViewGroup</code>先发起测量。在<code>measureChildren</code>这个方法中它传入了自己的<code>MeasureSpec</code>来测量<code>TextView</code>这个子View的<code>MeasureSpec</code>。此时<code>LinearLayout</code>是<code>EXACTLY</code>模式。由表可知。父View是<code>EXACTLY</code>(match_parent),子View是<code>wrap_content</code>的时候。它的<code>MeasureSpec</code>是<code>AT_MOST</code>加<code>parentSize</code>。在得到子View<code>MeasureSpec</code>的时候,开始子View自己的测量。</p>
<p>这里的子View是<code>TextView</code>,它有它自己的<code>onMeasure</code>实现。如果这里只是单纯的一个View。那么当它宽高都为<code>wrap_content</code>的时候它其实占据了父View的全部剩余空间,效果和<code>match_parent</code>一样。</p>
<p><img src="http://changqin.iaimer.com//20190227183724.png" alt=""></p>
<p>这也提示我们,在自定义View的时候,应该自己处理<code>wrap_content</code>的情况,要不然就跟<code>match_parent</code>一样了。</p>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> View </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android中的ClassLoader]]></title>
<url>/2018/12/20/Android%E4%B8%AD%E7%9A%84ClassLoader/</url>
<content type="html"><![CDATA[<h4 id="Android中的ClassLoader"><a href="#Android中的ClassLoader" class="headerlink" title="Android中的ClassLoader"></a>Android中的ClassLoader</h4><p>Java中的<code>ClassLoader</code>可以加载<code>jar</code>包和<code>class</code>文件,在Android则不同。在Android中,不论DVM还是ART,加载的都是<code>dex</code>文件。Android中的<code>ClassLoader</code>可以分为系统类加载器和自定义加载器。</p>
<p>Android中<code>ClassLoader</code>类继承关系如下</p>
<p><img src="http://changqin.iaimer.com//20181220181115.png" alt=""></p>
<h5 id="BootClassLoader"><a href="#BootClassLoader" class="headerlink" title="BootClassLoader"></a>BootClassLoader</h5><p><a href="http://androidxref.com/8.1.0_r33/xref/libcore/ojluni/src/main/java/java/lang/ClassLoader.java" target="_blank" rel="external">源码</a></p>
<p><code>BootClassLoader</code>是<code>ClassLoader</code>的一个内部类,并继承自<code>ClassLoader</code>。</p>
<p>它是包内可见的,因此我们没法使用它,也不能使用动态加载。</p>
<h5 id="UrlClassLoader"><a href="#UrlClassLoader" class="headerlink" title="UrlClassLoader"></a>UrlClassLoader</h5><p><code>UrlClassLoader</code>继承自<code>SecureClassLoader</code>,它只能用于加载jar文件,但是由于 dalvik 不能直接识别jar,所以在 Android 中无法使用这个加载器。</p>
<h5 id="BaseDexClassLoader"><a href="#BaseDexClassLoader" class="headerlink" title="BaseDexClassLoader"></a>BaseDexClassLoader</h5><p><a href="http://androidxref.com/8.0.0_r4/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java" target="_blank" rel="external">源码</a></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="function"><span class="keyword">public</span> <span class="title">BaseDexClassLoader</span><span class="params">(String dexPath, File optimizedDirectory,</span></span></div><div class="line"><span class="function"><span class="params"> String librarySearchPath, ClassLoader parent)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(parent);</div><div class="line"> <span class="keyword">this</span>.pathList = <span class="keyword">new</span> DexPathList(<span class="keyword">this</span>, dexPath, librarySearchPath, <span class="keyword">null</span>);</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (reporter != <span class="keyword">null</span>) {</div><div class="line"> reportClassLoaderChain();</div><div class="line"> }</div><div class="line">}</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="title">BaseDexClassLoader</span><span class="params">(ByteBuffer[] dexFiles, ClassLoader parent)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(parent);</div><div class="line"> <span class="keyword">this</span>.pathList = <span class="keyword">new</span> DexPathList(<span class="keyword">this</span>, dexFiles);</div><div class="line">}</div></pre></td></tr></table></figure>
<p><code>BaseDexClassLoader</code>继承自<code>ClassLoader</code>,用于加载各种<code>dex</code>中的类。</p>
<p>具体参数的含义</p>
<ul>
<li><code>dexPath</code>. 指目标类所在的APK或jar文件的路径,类装载器将从该路径中寻找指定的目标类,该类必须是APK或jar的全路径.如果要包含多个路径,路径之间必须使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)获得。最终做的是将dexPath路径上的文件ODEX优化到内部位置optimizedDirectory,然后,再进行加载的。</li>
<li><code>optimizedDirectory</code>. 由于dex文件被包含在APK或者Jar文件中,因此在装载目标类之前需要先从APK或Jar文件中解压出dex文件,该参数就是制定解压出的dex 文件存放的路径。这也是对apk中dex根据平台进行ODEX优化的过程。其实APK是一个程序压缩包,里面包含dex文件,ODEX优化就是把包里面的执行程序提取出来,就变成ODEX文件,因为你提取出来了,系统第一次启动的时候就不用去解压程序压缩包的程序,少了一个解压的过程。这样的话系统启动就加快了。为什么说是第一次呢?是因为DEX版本的也只有第一次会解压执行程序到 /data/dalvik-cache(针对PathClassLoader)或者optimizedDirectory(针对DexClassLoader)目录,之后也是直接读取目录下的的dex文件,所以第二次启动就和正常的差不多了。当然这只是简单的理解,实际生成的ODEX还有一定的优化作用。ClassLoader只能加载内部存储路径中的dex文件,所以这个路径必须为内部路径。</li>
<li><code>librarySearchPath</code>.指目标类中所使用的C/C++库存放的路径</li>
<li><code>parent</code>. 是指该装载器的父装载器,一般为当前执行类的装载器,例如在Android中以context.getClassLoader()作为父装载器。</li>
</ul>
<h5 id="PathClassLoader"><a href="#PathClassLoader" class="headerlink" title="PathClassLoader"></a>PathClassLoader</h5><p><a href="http://androidxref.com/8.0.0_r4/xref/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java" target="_blank" rel="external">源码</a></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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">PathClassLoader</span><span class="params">(String dexPath, ClassLoader parent)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(dexPath, <span class="keyword">null</span>, <span class="keyword">null</span>, parent);</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">PathClassLoader</span><span class="params">(String dexPath, String librarySearchPath, ClassLoader parent)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(dexPath, <span class="keyword">null</span>, librarySearchPath, parent);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>在<code>PathClassLoader</code>的构造方法中没有参数<code>optimizedDirectory</code>,这是因为<code>PathClassLoader</code>已经默认了参数<code>optimizedDirectory</code>的值为<code>/data/dalvik-cache</code>目录。所以<code>PathClassLoader</code>无法定义解压的dex文件的存储路径,因此<code>PathClassLoader</code>通常用来加载已经安装的apk的dex文件。</p>
<h5 id="DexClassLoader"><a href="#DexClassLoader" class="headerlink" title="DexClassLoader"></a>DexClassLoader</h5><p><a href="http://androidxref.com/8.0.0_r4/xref/libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java" target="_blank" rel="external">源码</a></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="function"><span class="keyword">public</span> <span class="title">DexClassLoader</span><span class="params">(String dexPath, String optimizedDirectory,</span></span></div><div class="line"><span class="function"><span class="params"> String librarySearchPath, ClassLoader parent)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(dexPath, <span class="keyword">new</span> File(optimizedDirectory), librarySearchPath, parent);</div><div class="line">}</div></pre></td></tr></table></figure>
<p><code>DexClassLoader</code>可以加载dex文件以及包含dex的压缩文件,不管加载哪种文件,最终都是要加载dex文件。</p>
<h5 id="InMemoryDexClassLoader"><a href="#InMemoryDexClassLoader" class="headerlink" title="InMemoryDexClassLoader"></a>InMemoryDexClassLoader</h5><p><a href="http://androidxref.com/8.0.0_r4/xref/libcore/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java" target="_blank" rel="external">源码</a></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></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">InMemoryDexClassLoader</span><span class="params">(ByteBuffer[] dexBuffers, ClassLoader parent)</span> </span>{</div><div class="line"> <span class="keyword">super</span>(dexBuffers, parent);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">InMemoryDexClassLoader</span><span class="params">(ByteBuffer dexBuffer, ClassLoader parent)</span> </span>{</div><div class="line"> <span class="keyword">this</span>(<span class="keyword">new</span> ByteBuffer[] { dexBuffer }, parent);</div><div class="line">}</div></pre></td></tr></table></figure>
<p><code>InMemoryDexClassLoader</code>是API26的时候新增的。ByteBuffer数组构造了一个DexPathList,可用于内存中的dex文件。</p>
<h4 id="ClassLoader-的双亲委托模型"><a href="#ClassLoader-的双亲委托模型" class="headerlink" title="ClassLoader 的双亲委托模型"></a>ClassLoader 的双亲委托模型</h4><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">protected</span> Class<?> loadClass(String name, <span class="keyword">boolean</span> resolve)</div><div class="line"> <span class="keyword">throws</span> ClassNotFoundException</div><div class="line"> {</div><div class="line"> <span class="comment">// First, check if the class has already been loaded</span></div><div class="line"> Class<?> c = findLoadedClass(name);</div><div class="line"> <span class="keyword">if</span> (c == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="keyword">if</span> (parent != <span class="keyword">null</span>) {</div><div class="line"> c = parent.loadClass(name, <span class="keyword">false</span>);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> c = findBootstrapClassOrNull(name);</div><div class="line"> }</div><div class="line"> } <span class="keyword">catch</span> (ClassNotFoundException e) {</div><div class="line"> <span class="comment">// ClassNotFoundException thrown if class not found</span></div><div class="line"> <span class="comment">// from the non-null parent class loader</span></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (c == <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// If still not found, then invoke findClass in order</span></div><div class="line"> <span class="comment">// to find the class.</span></div><div class="line"> c = findClass(name);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> c;</div><div class="line"> }</div><div class="line"> <span class="keyword">private</span> Class<?> findBootstrapClassOrNull(String name){</div><div class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">protected</span> Class<?> findClass(String name) <span class="keyword">throws</span> ClassNotFoundException {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ClassNotFoundException(name);</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>加载类的时候,首先判断有没有加载过,如果已经加载过了直接返回,否则就判断父加载器是否存在。如果存在父加载器,则调用父加载器的<code>loadClass</code>方法,不存在则调用<code>findBootstrapClassOrNull</code>方法。但是<code>findBootstrapClassOrNull</code>会直接返回<code>null</code>。所以最终又会调用到<code>findClass</code>方法。而<code>findClass</code>会直接抛出异常,所以这个需要子类来实现。这就是双亲委托模型。双亲委托模型一方面可以避免重复加载类,另一方面可以避免有人恶意编写一个类加载到JVM中。</p>
<p>Refer:<a href="https://www.jianshu.com/p/a620e368389a" target="_blank" rel="external">https://www.jianshu.com/p/a620e368389a</a></p>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Gradle的生命周期]]></title>
<url>/2018/12/15/Gradle%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</url>
<content type="html"><![CDATA[<h4 id="Gradle生命周期分三个阶段"><a href="#Gradle生命周期分三个阶段" class="headerlink" title="Gradle生命周期分三个阶段"></a>Gradle生命周期分三个阶段</h4><p><img src="http://changqin.iaimer.com//20181213221116.png" alt=""></p>
<blockquote>
<h2 id="Build-phases"><a href="#Build-phases" class="headerlink" title="Build phases"></a><a href="https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:build_phases" target="_blank" rel="external">Build phases</a></h2><p>A Gradle build has three distinct phases.</p>
<ul>
<li><p>Initialization</p>
<p>Gradle supports single and multi-project builds. During the initialization phase, Gradle determines which projects are going to take part in the build, and creates a <a href="https://docs.gradle.org/current/dsl/org.gradle.api.Project.html" target="_blank" rel="external">Project</a> instance for each of these projects.</p>
</li>
<li><p>Configuration</p>
<p>During this phase the project objects are configured. The build scripts of <em>all</em> projects which are part of the build are executed.</p>
</li>
<li><p>Execution</p>
<p>Gradle determines the subset of the tasks, created and configured during the configuration phase, to be executed. The subset is determined by the task name arguments passed to the <code>gradle</code> command and the current directory. Gradle then executes each of the selected tasks.</p>
</li>
</ul>
</blockquote>
<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><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"><span class="keyword">this</span>.beforeEvaluate {</div><div class="line"> println <span class="string">'配置前阶段-->ok'</span></div><div class="line">}</div><div class="line"><span class="comment">//配置阶段以后的监听回调</span></div><div class="line"><span class="keyword">this</span>.afterEvaluate {</div><div class="line"> println <span class="string">'配置后阶段-->ok'</span></div><div class="line">}</div><div class="line"><span class="comment">//gradle执行完成以后的监听回调</span></div><div class="line"><span class="keyword">this</span>.gradle.buildFinished {</div><div class="line"> println <span class="string">'执行阶段-->ok'</span></div><div class="line">}</div></pre></td></tr></table></figure>
<h4 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h4><p><a href="https://docs.gradle.org/current/userguide/build_lifecycle.html" target="_blank" rel="external">Gradle官网</a></p>
]]></content>
<categories>
<category> Gradle </category>
</categories>
<tags>
<tag> Gradle </tag>
<tag> Groovy </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Groovy中的json操作]]></title>
<url>/2018/12/14/Groovy%E4%B8%AD%E7%9A%84json%E6%93%8D%E4%BD%9C/</url>
<content type="html"><![CDATA[<h4 id="json-gt-object"><a href="#json-gt-object" class="headerlink" title="json ->object"></a>json ->object</h4><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><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">final</span> String myJson =<span class="string">'''</span></div><div class="line"><span class="string">{"code":200,"body":{"search_result":[{"id":"1393","name":"东京食尸鬼漫画","cover_url":"http://img.1whour.com/xpic/东京食尸鬼.jpg","other_1":"","other_2":""},{"id":"2402","name":"东京都立咒术学校漫画","cover_url":"http://img.1whour.com/xpic/东京都立咒术学校.jpg","other_1":"","other_2":""},{"id":"1107","name":"大东京玩具箱漫画","cover_url":"http://img.1whour.com/xpic/大东京玩具箱.jpg","other_1":"","other_2":""},{"id":"2026","name":"东京小红帽漫画","cover_url":"http://img.1whour.com/xpic/东京小红帽.jpg","other_1":"","other_2":""},{"id":"879","name":"东京ESP漫画","cover_url":"http://img.1whour.com/xpic/djESP.jpg","other_1":"","other_2":""},{"id":"2064","name":"东京暗鸦SwordOfSong漫画","cover_url":"http://img.1whour.com/xpic/东京暗鸦Sword.jpg","other_1":"","other_2":""},{"id":"943","name":"东京乌鸦漫画","cover_url":"http://img.1whour.com/xpic/东京乌鸦.jpg","other_1":"","other_2":""},{"id":"1954","name":"东京奇迹少年漫画","cover_url":"http://img.1whour.com/xpic/东京奇迹少年.jpg","other_1":"","other_2":""},{"id":"1106","name":"东京玩具箱漫画","cover_url":"http://img.1whour.com/xpic/东京玩具箱.jpg","other_1":"","other_2":""},{"id":"430","name":"东京MewMew漫画","cover_url":"http://img.1whour.com/xpic/0djmm.jpg","other_1":"","other_2":""},{"id":"358","name":"东京80年代漫画","cover_url":"http://img.1whour.com/xpic/363.jpg","other_1":"","other_2":""}]}}</span></div><div class="line"><span class="string">'''</span></div><div class="line"><span class="keyword">def</span> jsonSluper = <span class="keyword">new</span> JsonSlurper()</div><div class="line"><span class="keyword">def</span> object = jsonSluper.parseText(myJson)</div><div class="line">println object.body.search_result[<span class="number">0</span>]</div></pre></td></tr></table></figure>
<blockquote>
<p>[id:1393, name:东京食尸鬼漫画, cover_url:<a href="http://img.1whour.com/xpic/东京食尸鬼.jpg" target="_blank" rel="external">http://img.1whour.com/xpic/东京食尸鬼.jpg</a>, other_1:, other_2:]<br>东京食尸鬼漫画</p>
</blockquote>
<h4 id="object-gt-json"><a href="#object-gt-json" class="headerlink" title="object -> json"></a>object -> json</h4><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><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">def</span> cars = [<span class="keyword">new</span> Car(<span class="string">name:</span> <span class="string">'qihu'</span>,<span class="string">money:</span> <span class="number">2000</span>),</div><div class="line"> <span class="keyword">new</span> Car(<span class="string">name:</span> <span class="string">'qq'</span>,<span class="string">money:</span> <span class="number">1000</span>),</div><div class="line"> <span class="keyword">new</span> Car(<span class="string">name:</span> <span class="string">'haha'</span>,<span class="string">money:</span> <span class="number">3000</span>)]</div><div class="line"><span class="keyword">def</span> json = JsonOutput.toJson(cars)</div><div class="line">println JsonOutput.prettyPrint(json)</div></pre></td></tr></table></figure>
<blockquote>
<p>[{“money”:2000,”name”:”qihu”},{“money”:1000,”name”:”qq”},{“money”:3000,”name”:”haha”}]</p>
<p>[<br> {<br> “money”: 2000,<br> “name”: “qihu”<br> },<br> {<br> “money”: 1000,<br> “name”: “qq”<br> },<br> {<br> “money”: 3000,<br> “name”: “haha”<br> }<br>]</p>
</blockquote>
]]></content>
<categories>
<category> Gradle </category>
</categories>
<tags>
<tag> Gradle </tag>
<tag> Groovy </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Groovy中的xml操作]]></title>
<url>/2018/12/13/Groovy%E4%B8%AD%E7%9A%84xml%E6%93%8D%E4%BD%9C/</url>
<content type="html"><![CDATA[<h4 id="解析xml数据"><a href="#解析xml数据" class="headerlink" title="解析xml数据"></a>解析xml数据</h4><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><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"><span class="keyword">final</span> String xml = <span class="string">'''</span></div><div class="line"><span class="string"> <response version-api="2.0"></span></div><div class="line"><span class="string"> <value></span></div><div class="line"><span class="string"> <books id="1" classification="android"></span></div><div class="line"><span class="string"> <book available="20" id="1"></span></div><div class="line"><span class="string"> <title>疯狂Android讲义</title></span></div><div class="line"><span class="string"> <author id="1">李刚</author></span></div><div class="line"><span class="string"> </book></span></div><div class="line"><span class="string"> <book available="14" id="2"></span></div><div class="line"><span class="string"> <title>第一行代码</title></span></div><div class="line"><span class="string"> <author id="2">郭林</author></span></div><div class="line"><span class="string"> </book></span></div><div class="line"><span class="string"> <book available="13" id="3"></span></div><div class="line"><span class="string"> <title>Android开发艺术探索</title></span></div><div class="line"><span class="string"> <author id="3">任玉刚</author></span></div><div class="line"><span class="string"> </book></span></div><div class="line"><span class="string"> <book available="5" id="4"></span></div><div class="line"><span class="string"> <title>Android源码设计模式</title></span></div><div class="line"><span class="string"> <author id="4">何红辉</author></span></div><div class="line"><span class="string"> </book></span></div><div class="line"><span class="string"> </books></span></div><div class="line"><span class="string"> <books id="2" classification="web"></span></div><div class="line"><span class="string"> <book available="10" id="1"></span></div><div class="line"><span class="string"> <title>Vue从入门到精通</title></span></div><div class="line"><span class="string"> <author id="4">李刚</author></span></div><div class="line"><span class="string"> </book></span></div><div class="line"><span class="string"> </books></span></div><div class="line"><span class="string"> </value></span></div><div class="line"><span class="string"> </response></span></div><div class="line"><span class="string">'''</span></div><div class="line"></div><div class="line"><span class="keyword">def</span> xmlSluper = <span class="keyword">new</span> XmlSlurper()</div><div class="line"><span class="keyword">def</span> resp = xmlSluper.parseText(xml)</div><div class="line">println resp.value.books[<span class="number">1</span>].book[<span class="number">0</span>].title.text()</div></pre></td></tr></table></figure>
<blockquote>
<p>Vue从入门到精通</p>
</blockquote>
<h4 id="xml数据简单查找"><a href="#xml数据简单查找" class="headerlink" title="xml数据简单查找"></a>xml数据简单查找</h4><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><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"><span class="comment">//xml,resp同上 </span></div><div class="line"><span class="keyword">def</span> list = []</div><div class="line">resp.value.books.each {books-></div><div class="line"> books.book.each { book -></div><div class="line"> <span class="keyword">def</span> author = book.author.text()</div><div class="line"> <span class="keyword">if</span> (author == <span class="string">'李刚'</span>){</div><div class="line"> list.add(book)</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div><div class="line">println list.toListString()</div></pre></td></tr></table></figure>
<blockquote>
<p>[疯狂Android讲义李刚, Vue从入门到精通李刚]</p>
</blockquote>
<h4 id="深度遍历"><a href="#深度遍历" class="headerlink" title="深度遍历"></a>深度遍历</h4><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><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"><span class="comment">//深度遍历</span></div><div class="line"><span class="keyword">def</span> titles1 = resp.depthFirst().findAll {book -></div><div class="line"> <span class="keyword">return</span> book.author.text() == <span class="string">'李刚'</span></div><div class="line">}</div><div class="line"><span class="keyword">def</span> titles2 = resp.depthFirst().findAll {node -></div><div class="line"> node.name() == <span class="string">'book'</span> && node.<span class="meta">@id</span> == <span class="string">'2'</span></div><div class="line">}</div><div class="line">println titles1</div><div class="line">println titles2</div></pre></td></tr></table></figure>
<blockquote>
<p>[疯狂Android讲义李刚, Vue从入门到精通李刚]</p>
<p>[第一行代码郭林]</p>
</blockquote>
<h4 id="广度遍历"><a href="#广度遍历" class="headerlink" title="广度遍历"></a>广度遍历</h4><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><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//广度遍历</span></div><div class="line"><span class="keyword">def</span> name = resp.value.books.children().findAll { node-></div><div class="line"> node.name() == <span class="string">'book'</span> && node.<span class="meta">@id</span>==<span class="string">'2'</span></div><div class="line">}</div><div class="line">println name</div></pre></td></tr></table></figure>
<blockquote>
<p>第一行代码郭林</p>
</blockquote>
<h4 id="生成xml"><a href="#生成xml" class="headerlink" title="生成xml"></a>生成xml</h4><p>Groovy中生成xml用的是<code>MarkupBuilder</code></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></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">langs</span> <span class="attr">type</span>=<span class="string">'current'</span> <span class="attr">count</span>=<span class="string">'3'</span> <span class="attr">mainstream</span>=<span class="string">'true'</span>></span></div><div class="line"> <span class="tag"><<span class="name">language</span> <span class="attr">flavor</span>=<span class="string">'static'</span> <span class="attr">version</span>=<span class="string">'1.5'</span>></span>Java<span class="tag"></<span class="name">language</span>></span></div><div class="line"> <span class="tag"><<span class="name">language</span> <span class="attr">flavor</span>=<span class="string">'dynamic'</span> <span class="attr">version</span>=<span class="string">'1.6.0'</span>></span>Groovy<span class="tag"></<span class="name">language</span>></span></div><div class="line"> <span class="tag"><<span class="name">language</span> <span class="attr">flavor</span>=<span class="string">'dynamic'</span> <span class="attr">version</span>=<span class="string">'1.9'</span>></span>JavaScript<span class="tag"></<span class="name">language</span>></span></div><div class="line"> <span class="tag"></<span class="name">langs</span>></span></div></pre></td></tr></table></figure>
<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><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="keyword">def</span> sw = <span class="keyword">new</span> StringWriter()</div><div class="line"><span class="keyword">def</span> xmlBuilder = <span class="keyword">new</span> MarkupBuilder(sw)</div><div class="line">xmlBuilder.langs(<span class="string">type:</span> <span class="string">'current'</span>, <span class="string">count:</span> <span class="string">'3'</span>, <span class="string">mainstream:</span> <span class="string">'true'</span>) {</div><div class="line"> language(<span class="string">flavor:</span> <span class="string">'static'</span>, <span class="string">version:</span> <span class="string">'1.5'</span>, <span class="string">"Java"</span>)</div><div class="line"> language(<span class="string">flavor:</span> <span class="string">'dynamic'</span>, <span class="string">version:</span> <span class="string">'1.6'</span>, <span class="string">"Groovy"</span>)</div><div class="line"> language(<span class="string">flavor:</span> <span class="string">'dynamic'</span>, <span class="string">version:</span> <span class="string">'1.9'</span>, <span class="string">"JavaScript"</span>)</div><div class="line">}</div><div class="line">println sw</div></pre></td></tr></table></figure>
<blockquote>
<langs type="current" count="3" mainstream="true"><br> <language flavor="static" version="1.5">Java</language><br> <language flavor="dynamic" version="1.6">Groovy</language><br> <language flavor="dynamic" version="1.9">JavaScript</language><br></langs>
</blockquote>
<p>一般我们生成xml都是用实体对象动态生成的</p>
<p>定义class如下</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><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"><span class="comment">//对应xml中的Langs结点</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Langs</span> {</span></div><div class="line"> String type = <span class="string">"current"</span></div><div class="line"> <span class="keyword">int</span> count = <span class="number">3</span></div><div class="line"> <span class="keyword">boolean</span> mainstream = <span class="literal">true</span></div><div class="line"> <span class="keyword">def</span> language = [<span class="keyword">new</span> Language(<span class="string">flavor:</span> <span class="string">"static"</span>, <span class="string">version:</span> <span class="number">1.5</span>, <span class="string">value:</span> <span class="string">"java"</span>),</div><div class="line"> <span class="keyword">new</span> Language(<span class="string">flavor:</span> <span class="string">"dynamic"</span>, <span class="string">version:</span> <span class="number">1.6</span>, <span class="string">value:</span> <span class="string">"Groovy"</span>),</div><div class="line"> <span class="keyword">new</span> Language(<span class="string">flavor:</span> <span class="string">"dynamic"</span>, <span class="string">version:</span> <span class="number">1.9</span>, <span class="string">value:</span> <span class="string">"JavaScript"</span>)]</div><div class="line">}</div><div class="line"><span class="comment">//对应xml中的language结点</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Language</span> {</span></div><div class="line"> String flavor</div><div class="line"> String version</div><div class="line"> String value</div><div class="line">}</div></pre></td></tr></table></figure>
<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><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"><span class="keyword">def</span> langs = <span class="keyword">new</span> Langs()</div><div class="line">xmlBuilder.langs(<span class="string">type:</span> langs.type, <span class="string">count:</span> langs.count, <span class="string">mainstream:</span> langs.mainstream) {</div><div class="line"> langs.language.each { lang -></div><div class="line"> language(<span class="string">flavor:</span> lang.flavor,</div><div class="line"><span class="symbol"> version:</span> lang.value,</div><div class="line"> lang.value)</div><div class="line"> }</div><div class="line">}</div><div class="line">println sw</div></pre></td></tr></table></figure>
<p>上面的生成方式也是可以的</p>
]]></content>
<categories>
<category> Gradle </category>
</categories>
<tags>
<tag> Gradle </tag>
<tag> Groovy </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Groovy的列表]]></title>
<url>/2018/12/12/Groovy%E7%9A%84%E5%88%97%E8%A1%A8/</url>
<content type="html"><![CDATA[<h5 id="1-列表"><a href="#1-列表" class="headerlink" title="1.列表"></a>1.列表</h5><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">def</span> list = [<span class="number">1</span>, <span class="number">3</span>, <span class="number">1</span>]</div><div class="line">println list.<span class="keyword">class</span></div><div class="line">println list.size()</div></pre></td></tr></table></figure>
<h5 id="2-数组"><a href="#2-数组" class="headerlink" title="2.数组"></a>2.数组</h5><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"><span class="keyword">def</span> array = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">1</span>] <span class="keyword">as</span> <span class="keyword">int</span>[]</div><div class="line">println array.<span class="keyword">class</span></div><div class="line">println array.size()</div><div class="line"><span class="keyword">int</span>[] array2 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">4</span>]</div></pre></td></tr></table></figure>
<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><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//排序</span></div><div class="line"><span class="keyword">def</span> sortList = [<span class="number">2</span>, <span class="number">5</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">-3</span>, <span class="number">4</span>, <span class="number">7</span>, <span class="number">0</span>]</div><div class="line"><span class="comment">//Comparator mc = { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 }</span></div><div class="line"><span class="comment">//Collections.sort(sortList,mc)</span></div><div class="line">sortList.sort{a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : <span class="number">1</span> }</div><div class="line"><span class="comment">//println sortList</span></div></pre></td></tr></table></figure>
<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"><span class="comment">//查找</span></div><div class="line"><span class="keyword">def</span> findList = [<span class="number">2</span>, <span class="number">5</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">-3</span>, <span class="number">4</span>, <span class="number">7</span>, <span class="number">0</span>]</div><div class="line"><span class="keyword">int</span> res1 = findList.find {it % <span class="number">2</span> !=<span class="number">0</span>}</div><div class="line"><span class="keyword">def</span> res2 = findList.findAll {it % <span class="number">2</span> == <span class="number">0</span>}</div></pre></td></tr></table></figure>
]]></content>
<categories>
<category> Gradle </category>
</categories>
<tags>
<tag> Gradle </tag>
<tag> Groovy </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Groovy 闭包进阶]]></title>
<url>/2018/12/11/Groovy-%E9%97%AD%E5%8C%85%E8%BF%9B%E9%98%B6/</url>
<content type="html"><![CDATA[<h5 id="1-闭包关键变量"><a href="#1-闭包关键变量" class="headerlink" title="1.闭包关键变量"></a>1.闭包关键变量</h5><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><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="comment">//闭包中定义一个闭包</span></div><div class="line"><span class="keyword">def</span> nestClouser = {</div><div class="line"> <span class="keyword">def</span> innerClouser = {</div><div class="line"> <span class="comment">//this 代表闭包定义处的类</span></div><div class="line"> println <span class="string">"innerClouser this:"</span> + <span class="keyword">this</span></div><div class="line"> <span class="comment">//owner 代表闭包定义处的类或对象</span></div><div class="line"> println <span class="string">"innerClouser owner:"</span> + owner</div><div class="line"> <span class="comment">//delegate 代表任意第三方对象 默认值=owner</span></div><div class="line"> println <span class="string">"innerClouser delegate:"</span> + delegate</div><div class="line"> }</div><div class="line"> <span class="comment">//innerClouser.delegate = p //修改默认的delegate,this和owner不能修改</span></div><div class="line"> innerClouser.call()</div><div class="line">}</div><div class="line">nestClouser.call()</div><div class="line"></div><div class="line"><span class="string">out:</span></div><div class="line">innerClouser <span class="string">this:</span>Demo49@<span class="number">3</span>ecedf21 </div><div class="line">innerClouser <span class="string">owner:</span>Demo49$_run_closure2@<span class="number">6</span>df20ade <span class="comment">//指向了它最近的一个类或对象</span></div><div class="line">innerClouser <span class="string">delegate:</span>Demo49$_run_closure2@<span class="number">6</span>df20ade</div><div class="line"><span class="comment">//innerClouser delegate:Person@9a7a808</span></div></pre></td></tr></table></figure>
<h5 id="2-闭包的委托策略"><a href="#2-闭包的委托策略" class="headerlink" title="2.闭包的委托策略"></a>2.闭包的委托策略</h5><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><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"><span class="class"><span class="keyword">class</span> <span class="title">Student</span>{</span></div><div class="line"> String name</div><div class="line"> <span class="keyword">def</span> pretty = {<span class="string">"my name is ${name}"</span>}</div><div class="line"> String toString(){</div><div class="line"> pretty.call()</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Teacher</span>{</span></div><div class="line"> String name</div><div class="line">}</div><div class="line"><span class="keyword">def</span> stu = <span class="keyword">new</span> Student(<span class="string">name:</span> <span class="string">'wcq'</span>)</div><div class="line"><span class="keyword">def</span> tea = <span class="keyword">new</span> Teacher(<span class="string">name:</span> <span class="string">'qqq'</span>)</div><div class="line"></div><div class="line">stu.pretty.delegate = tea</div><div class="line">stu.pretty.resolveStrategy = Closure.DELEGATE_FIRST</div><div class="line"></div><div class="line">println stu.toString()</div></pre></td></tr></table></figure>]]></content>
<categories>
<category> Gradle </category>
</categories>
<tags>
<tag> Gradle </tag>
<tag> Groovy </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Groovy 闭包]]></title>
<url>/2018/12/10/Groovy-%E9%97%AD%E5%8C%85/</url>
<content type="html"><![CDATA[<h3 id="Groovy-闭包"><a href="#Groovy-闭包" class="headerlink" title="Groovy 闭包"></a>Groovy 闭包</h3><h5 id="1、闭包参数"><a href="#1、闭包参数" class="headerlink" title="1、闭包参数"></a>1、闭包参数</h5><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">def</span> clouser = { String name -></div><div class="line"> println <span class="string">"Hello groovy by ${name}"</span></div><div class="line">}</div></pre></td></tr></table></figure>
<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></pre></td><td class="code"><pre><div class="line"><span class="keyword">def</span> clouser = {</div><div class="line"> println <span class="string">"Hello groovy by ${it}"</span></div><div class="line">}</div></pre></td></tr></table></figure>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">clouser(<span class="string">'wcq'</span>)</div></pre></td></tr></table></figure>
<p>闭包和kotlin一样,有默认的参数名it</p>
<h5 id="2、闭包返回值"><a href="#2、闭包返回值" class="headerlink" title="2、闭包返回值"></a>2、闭包返回值</h5><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">def</span> clouser = {</div><div class="line"> println <span class="string">"Hello groovy by ${it}"</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>上面代码的默认返回值是<code>null</code></p>
<h5 id="3-闭包的用法"><a href="#3-闭包的用法" class="headerlink" title="3.闭包的用法"></a>3.闭包的用法</h5><ul>
<li><p>与基本类型的结合使用</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><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="keyword">int</span> x = fab(<span class="number">5</span>)</div><div class="line"><span class="keyword">int</span> fab(<span class="keyword">int</span> number) {</div><div class="line"> <span class="keyword">int</span> result = <span class="number">1</span></div><div class="line"> <span class="number">1.</span>upto(number, { num -> result *= num })</div><div class="line"> <span class="keyword">return</span> result</div><div class="line">}</div><div class="line">println x</div></pre></td></tr></table></figure>
<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><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></pre></td><td class="code"><pre><div class="line"><span class="keyword">int</span> y = cal(<span class="number">5</span>)</div><div class="line"><span class="keyword">int</span> cal(<span class="keyword">int</span> number) {</div><div class="line"> <span class="keyword">int</span> result = <span class="number">0</span></div><div class="line"> number.times {</div><div class="line"> <span class="comment">//note: time方法开始的值是0</span></div><div class="line"> num -> result += num</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> result</div><div class="line">}</div><div class="line">println y</div></pre></td></tr></table></figure>
</li>
<li><p>与String结合使用</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><div class="line">5</div></pre></td><td class="code"><pre><div class="line">String str = <span class="string">'ChangQin251129'</span></div><div class="line"><span class="comment">//each的遍历</span></div><div class="line">str.each {s -></div><div class="line"> print s.toLowerCase()</div><div class="line">}</div></pre></td></tr></table></figure>
<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"><span class="comment">//find 找到符合条件的第一个</span></div><div class="line">println str.find { s -></div><div class="line"> <span class="keyword">return</span> s.isNumber()</div><div class="line">}</div></pre></td></tr></table></figure>
<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><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//找到符合条件的所有值</span></div><div class="line"><span class="keyword">def</span> list = str.findAll { s -></div><div class="line"> <span class="keyword">return</span> s.isNumber()</div><div class="line">}</div><div class="line">println list.toListString()</div></pre></td></tr></table></figure>
<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"><span class="comment">//遍历输入项,查看是否有一项符合条件</span></div><div class="line"><span class="keyword">def</span> isContainNumber = str.any {s-> s.isNumber() }</div><div class="line"><span class="comment">//遍历输入项,查看是否所有项都符合条件</span></div><div class="line"><span class="keyword">def</span> totalIsNumber = str.every { s->s.isNumber() }</div></pre></td></tr></table></figure>
<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"><span class="keyword">def</span> list2 = [<span class="number">1</span>, <span class="string">'a'</span>, <span class="number">1.23</span>, <span class="literal">true</span> ] </div><div class="line"><span class="keyword">def</span> types = list2.collect { it.<span class="keyword">class</span> } </div><div class="line">println types </div><div class="line"><span class="comment">//each返回的是自身 collect返回的是一个集合</span></div></pre></td></tr></table></figure>
<p> </p>
</li>
<li><p>与数据结构结合使用</p>
</li>
<li><p>与文件结合使用</p>
</li>
</ul>
]]></content>
<categories>
<category> Gradle </category>
</categories>
<tags>
<tag> Gradle </tag>
<tag> Groovy </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android面试总结(二)]]></title>
<url>/2018/12/09/Android%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93-%E4%BA%8C/</url>
<content type="html"><![CDATA[<h4 id="Java-基础"><a href="#Java-基础" class="headerlink" title="Java 基础"></a>Java 基础</h4><h5 id="Q-Java-中有哪几种引用-它们的含义和区别是什么"><a href="#Q-Java-中有哪几种引用-它们的含义和区别是什么" class="headerlink" title="Q:Java 中有哪几种引用?它们的含义和区别是什么?"></a>Q:Java 中有哪几种引用?它们的含义和区别是什么?</h5><ul>
<li>强引用(Strong Reference)就是指在程序代码中普遍存在的,类似”Object obj = new Object()”这类的引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。</li>
<li>软引用(Sofr Reference)是用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用</li>
<li>弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后,提供了WeakReference类来实现弱引用。</li>
<li>虚引用(Phantom Reference)也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到个系统通知。在JDK1.2之后,提供了 PhantomReference类来实现虚引用</li>
</ul>
]]></content>
<categories>
<category> Android </category>
<category> 面试 </category>
</categories>
<tags>
<tag> Android </tag>
<tag> 面试 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[理解Synchronized]]></title>
<url>/2018/12/06/%E7%90%86%E8%A7%A3Synchronized/</url>
<content type="html"><![CDATA[<p><img src="http://changqin.iaimer.com//20181206173330.png" alt=""></p>
<p> </p>
<h4 id="1、在类的实例方法上加synchronized,或者在类的实例对象中加入synchronized-this-,此时锁住的是该类的实例对象"><a href="#1、在类的实例方法上加synchronized,或者在类的实例对象中加入synchronized-this-,此时锁住的是该类的实例对象" class="headerlink" title="1、在类的实例方法上加synchronized,或者在类的实例对象中加入synchronized (this) {},此时锁住的是该类的实例对象"></a>1、在类的实例方法上加<code>synchronized</code>,或者在类的实例对象中加入<code>synchronized (this) {}</code>,此时锁住的是该类的实例对象</h4><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></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">TestSynchronized</span> </span>{</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">minus</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">int</span> count = <span class="number">5</span>;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</div><div class="line"> count--;</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" -> "</span> + count);</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> Thread.sleep(<span class="number">500</span>);</div><div class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</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="comment"> * 这个同步方法等价于上面的方法</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">minus2</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">synchronized</span> (<span class="keyword">this</span>) {</div><div class="line"> <span class="keyword">int</span> count = <span class="number">5</span>;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</div><div class="line"> count--;</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" -> "</span> + count);</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> Thread.sleep(<span class="number">500</span>);</div><div class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</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="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">blockMethod</span><span class="params">()</span> </span>{</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" "</span> + <span class="string">"coming"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">staticBlockMethod</span><span class="params">()</span> </span>{</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" "</span> + <span class="string">"coming"</span>);</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">unblockMethod</span><span class="params">()</span> </span>{</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" "</span> + <span class="string">"coming"</span>);</div><div class="line"> }</div><div class="line">}</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></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestMain</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>{</div><div class="line"> TestSynchronized tt = <span class="keyword">new</span> TestSynchronized();</div><div class="line"> Thread t1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</div><div class="line"> tt.minus();</div><div class="line"> }</div><div class="line"> },<span class="string">"t1"</span>);</div><div class="line"> Thread t2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</div><div class="line"> tt.minus();</div><div class="line"> }</div><div class="line"> },<span class="string">"t2"</span>);</div><div class="line"> t1.start();</div><div class="line"> t2.start();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<blockquote>
<p>//执行结果<br>t1 -> 4<br>t1 -> 3<br>t1 -> 2<br>t1 -> 1<br>t1 -> 0<br>t2 -> 4<br>t2 -> 3<br>t2 -> 2<br>t2 -> 1<br>t2 -> 0</p>
</blockquote>
<p>可以看出,因为Thread的Runnable对象是同一个,<code>synchronized</code>很好的锁住了类的实例对象,两个线程同时启动的时候,当一个线程持有锁的时候,另一个对象是不能访问该实例的。</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></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestMain</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>{</div><div class="line"> TestSynchronized tt = <span class="keyword">new</span> TestSynchronized();</div><div class="line"> Thread t1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</div><div class="line"> tt.minus();</div><div class="line"> }</div><div class="line"> },<span class="string">"t1"</span>);</div><div class="line"> Thread t2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</div><div class="line"> <span class="comment">//tt.minus();</span></div><div class="line"> tt.blockMethod();</div><div class="line"> }</div><div class="line"> },<span class="string">"t2"</span>);</div><div class="line"> t1.start();</div><div class="line"> t2.start();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<blockquote>
<p>t1 -> 4<br>t1 -> 3<br>t1 -> 2<br>t1 -> 1<br>t1 -> 0<br>t2 coming</p>
</blockquote>
<p>当t1线程访问类对象的时候,因为blockMethod方法有<code>synchronized</code>关键字,所以t2在t1持有类对象的时候不能访问blockMethod。</p>
<p>将上述<code>tt.blockMethod();</code>换成<code>tt.unblockMethod();</code> 执行结果如下</p>
<blockquote>
<p>t2 coming<br>t1 -> 4<br>t1 -> 3<br>t1 -> 2<br>t1 -> 1<br>t1 -> 0</p>
</blockquote>
<p>可以看出,有线程持有实例对象,其他线程访问有synchronized的实例方法会阻塞,而访问普通的实例方法不会被阻塞。</p>
<h4 id="2、在类的静态方法上加synchronized,或者加上synchronized-TestSynchronized-class-,此时锁住的是该类的类对象"><a href="#2、在类的静态方法上加synchronized,或者加上synchronized-TestSynchronized-class-,此时锁住的是该类的类对象" class="headerlink" title="2、在类的静态方法上加synchronized,或者加上synchronized (TestSynchronized.class) {},此时锁住的是该类的类对象"></a>2、在类的静态方法上加<code>synchronized</code>,或者加上<code>synchronized (TestSynchronized.class) {}</code>,此时锁住的是该类的类对象</h4><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></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">TestSynchronized</span> </span>{</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">minus</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">int</span> count = <span class="number">5</span>;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</div><div class="line"> count--;</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" -> "</span> + count);</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> Thread.sleep(<span class="number">500</span>);</div><div class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</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="comment"> * 这个同步方法等价于上面的方法</span></div><div class="line"><span class="comment"> */</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">minus2</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">synchronized</span> (TestSynchronized.class) {</div><div class="line"> <span class="keyword">int</span> count = <span class="number">5</span>;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</div><div class="line"> count--;</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" -> "</span> + count);</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> Thread.sleep(<span class="number">500</span>);</div><div class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</div><div class="line"> }</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">synchronized</span> <span class="keyword">void</span> <span class="title">blockMethod</span><span class="params">()</span> </span>{</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" "</span> + <span class="string">"coming"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">staticBlockMethod</span><span class="params">()</span> </span>{</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" "</span> + <span class="string">"coming"</span>);</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">unblockMethod</span><span class="params">()</span> </span>{</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" "</span> + <span class="string">"coming"</span>);</div><div class="line"> }</div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">staticUnblockMethod</span><span class="params">()</span> </span>{</div><div class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" "</span> + <span class="string">"coming"</span>);</div><div class="line"> }</div><div class="line">}</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></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">TestMain</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>{</div><div class="line"> Thread t1 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</div><div class="line"> TestSynchronized.minus();</div><div class="line"> }</div><div class="line"> },<span class="string">"t1"</span>);</div><div class="line"> Thread t2 = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</div><div class="line"> TestSynchronized.minus();</div><div class="line"> }</div><div class="line"> },<span class="string">"t2"</span>);</div><div class="line"> t1.start();</div><div class="line"> t2.start();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<blockquote>
<p>t1 -> 4<br>t1 -> 3<br>t1 -> 2<br>t1 -> 1<br>t1 -> 0<br>t2 -> 4<br>t2 -> 3<br>t2 -> 2<br>t2 -> 1<br>t2 -> 0</p>
</blockquote>
<p>静态方法锁住的是类对象。修改测试方法,如下</p>
<ul>
<li>t1调用synchronized的static方法,t2也调用<strong>有</strong>synchronized的static方法<strong>会</strong>阻塞。</li>
<li>t1调用synchronized的static方法,t2调用<strong>非</strong>synchronized的static方法<strong>不会</strong>阻塞。</li>
<li>t1调用synchronized的static方法,t2调用实例的<strong>有</strong>synchronized的static方法<strong>不会</strong>阻塞。</li>
<li>t1调用synchronized的static方法,t2调用实例的<strong>非</strong>synchronized的static方法<strong>不会</strong>阻塞。</li>
</ul>
<h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>A. 无论<code>synchronized</code>关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果<code>synchronized</code>作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。 </p>
<p>B. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。 </p>
]]></content>
<categories>
<category> Android </category>
<category> Java </category>
</categories>
<tags>
<tag> Android </tag>
<tag> Java </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android面试总结(一)]]></title>
<url>/2018/09/20/Android%E9%9D%A2%E8%AF%95%E6%80%BB%E7%BB%93-%E4%B8%80/</url>
<content type="html"><![CDATA[<h4 id="数据存储"><a href="#数据存储" class="headerlink" title="数据存储"></a>数据存储</h4><h5 id="Q-Android中提供哪些数据持久存储的方法?"><a href="#Q-Android中提供哪些数据持久存储的方法?" class="headerlink" title="Q:Android中提供哪些数据持久存储的方法?"></a>Q:Android中提供哪些数据持久存储的方法?</h5><ul>
<li>SharePreference</li>
<li>SQLite</li>
<li>File</li>
<li>Content provider</li>
<li>网络<h5 id="Q-Java中的I-O流读写怎么做?"><a href="#Q-Java中的I-O流读写怎么做?" class="headerlink" title="Q:Java中的I/O流读写怎么做?"></a>Q:Java中的I/O流读写怎么做?</h5></li>
</ul>
<h5 id="Q-SharePreferences适用情形?使用中需要注意什么?"><a href="#Q-SharePreferences适用情形?使用中需要注意什么?" class="headerlink" title="Q:SharePreferences适用情形?使用中需要注意什么?"></a>Q:SharePreferences适用情形?使用中需要注意什么?</h5><p>少量的配置类标记数据,避免复杂的前置操作</p>
<h5 id="Q-了解SQLite中的事务处理吗?是如何做的?"><a href="#Q-了解SQLite中的事务处理吗?是如何做的?" class="headerlink" title="Q:了解SQLite中的事务处理吗?是如何做的?"></a>Q:了解SQLite中的事务处理吗?是如何做的?</h5><p>使用SQLiteDatabase的<code>beginTransaction()</code>方法可以以独占模式开启一个事务,程序执行到<code>endTransaction()</code>方法时会检查事务的标志是否为成功,如果之前调用了<code>setTransactionSuccessful()</code>方法设置事务的标志为成功则提交事务,否则回滚事务。多用于大量数据操作时,能明显减少耗时。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">SQLiteDatabase db = helper.getWritableDatabase(); db.beginTransaction();//开启事务 try {</div><div class="line"> db.execSQL();</div><div class="line"> db.setTransactionSuccessful();//事务正确结束,如果此方法不执行,则所有的数据增删改操作都会回滚 } catch (Exception e) {</div><div class="line"> //处理异常 } finally {</div><div class="line"> db.endTransaction();//关闭事务 }</div></pre></td></tr></table></figure></p>
<h5 id="Q-使用SQLite做批量操作有什么好的方法吗?"><a href="#Q-使用SQLite做批量操作有什么好的方法吗?" class="headerlink" title="Q:使用SQLite做批量操作有什么好的方法吗?"></a>Q:使用SQLite做批量操作有什么好的方法吗?</h5><p>用事务处理进行优化。在数据库操作时,如果当前没有显式事务,SQLite会默认启动一个隐式事务。隐式事务只持续在数据库操作的持续时间内,然后结束。如果数据库操作成功,则提交其更改。在批量操作的时候不开启事务会创建许多隐式事务,非常耗时。</p>
<h5 id="Q-如果现在要删除SQLite中表的一个字段如何做?"><a href="#Q-如果现在要删除SQLite中表的一个字段如何做?" class="headerlink" title="Q:如果现在要删除SQLite中表的一个字段如何做?"></a>Q:如果现在要删除SQLite中表的一个字段如何做?</h5><p>SQLite不支持<code>drop column</code>。<br>步骤</p>
<ol>
<li>创建删除了某个字段的临时表</li>
<li>迁移数据</li>
<li>删除旧表</li>
</ol>
<h5 id="Q-使用SQLite时会有哪些优化操作"><a href="#Q-使用SQLite时会有哪些优化操作" class="headerlink" title="Q:使用SQLite时会有哪些优化操作?"></a>Q:使用SQLite时会有哪些优化操作?</h5><ul>
<li>批量操作时使用事务</li>
</ul>
<h4 id="IPC"><a href="#IPC" class="headerlink" title="IPC"></a>IPC</h4><h5 id="Q-Android中进程和线程的关系?区别?"><a href="#Q-Android中进程和线程的关系?区别?" class="headerlink" title="Q:Android中进程和线程的关系?区别?"></a>Q:Android中进程和线程的关系?区别?</h5><p>线程是CPU调度的最小单元,同时也是一种有限的系统资源。进程一般指一个执行单元,在Android中指一个应用。一个进程可以包含多个线程,因此进程和线程是包含和被包含的关系。</p>
<h5 id="Q-为何需要进行IPC?多进程通信可能会出现什么问题?"><a href="#Q-为何需要进行IPC?多进程通信可能会出现什么问题?" class="headerlink" title="Q:为何需要进行IPC?多进程通信可能会出现什么问题?"></a>Q:为何需要进行IPC?多进程通信可能会出现什么问题?</h5><ul>
<li>一个进程Android分配的内存有限,早些Android版本一个进程只分配16M,如果一个应用太大,那么一个进程就无法满足。</li>
<li>守护进程:防止进程被kill</li>
<li>当前应用需要向其他应用获取数据。由于是两个应用,即两个进程。</li>
</ul>
<p>可能出现的问题</p>
<ol>
<li>静态成员和单例模式完全失效</li>
<li>线程同步机制完全失效</li>
<li>SharedPreference的可靠性下降</li>
<li>Application会多次创建</li>
</ol>
<h5 id="Q-什么是序列化?Serializable接口和Parcelable接口的区别?为何推荐使用后者?"><a href="#Q-什么是序列化?Serializable接口和Parcelable接口的区别?为何推荐使用后者?" class="headerlink" title="Q:什么是序列化?Serializable接口和Parcelable接口的区别?为何推荐使用后者?"></a>Q:什么是序列化?Serializable接口和Parcelable接口的区别?为何推荐使用后者?</h5><p>序列化是将对象持久化到存储设备上或者通过网络传输给其它客户端。</p>
<blockquote>
<p>静态成员属于类不属于对象,不会参与序列化的过程。</p>
<p>用<code>transient</code>关键字标记的成员变量不会参与序列化过程。</p>
</blockquote>
<p>Serializable & Parcelable</p>
<ul>
<li>相同点:<ul>
<li>两者都可以进行序列化与反序列化;</li>
</ul>
</li>
<li>不同点:<ul>
<li>Serializable 的数据最后是存放在硬盘上的,那么读的时候也是 I/O 操作,使用简单但是开销很大。而 Parcelabe 是存放在内存中的。这就导致了下面的一点</li>
<li>Parcelable 的读写速度比 Serializable 在数据量大的时候,快很多</li>
<li>Serializable 的实现十分简单,而 Parcelable 的代码量却比较多</li>
</ul>
</li>
</ul>
<p>Parcelable接口是Android特有功能,效率比实现Serializable接口高效,可用于Intent数据传递,也可以用于进程间通信(IPC)</p>
<h5 id="Q-Android中为何新增Binder来作为主要的IPC方式?"><a href="#Q-Android中为何新增Binder来作为主要的IPC方式?" class="headerlink" title="Q:Android中为何新增Binder来作为主要的IPC方式?"></a>Q:Android中为何新增Binder来作为主要的IPC方式?</h5><h5 id="Q-使用Binder进行数据传输的具体过程?"><a href="#Q-使用Binder进行数据传输的具体过程?" class="headerlink" title="Q:使用Binder进行数据传输的具体过程?"></a>Q:使用Binder进行数据传输的具体过程?</h5><h5 id="Q-Binder框架中ServiceManager的作用?"><a href="#Q-Binder框架中ServiceManager的作用?" class="headerlink" title="Q:Binder框架中ServiceManager的作用?"></a>Q:Binder框架中ServiceManager的作用?</h5><h5 id="Q-是否了解AIDL?原理是什么?如何优化多模块都使用AIDL的情况?"><a href="#Q-是否了解AIDL?原理是什么?如何优化多模块都使用AIDL的情况?" class="headerlink" title="Q:是否了解AIDL?原理是什么?如何优化多模块都使用AIDL的情况?"></a>Q:是否了解AIDL?原理是什么?如何优化多模块都使用AIDL的情况?</h5><h5 id="Q-IPC方式的优缺点和适用场景"><a href="#Q-IPC方式的优缺点和适用场景" class="headerlink" title="Q:IPC方式的优缺点和适用场景"></a>Q:IPC方式的优缺点和适用场景</h5><table>
<thead>
<tr>
<th style="text-align:center">名称</th>
<th style="text-align:center">优点</th>
<th style="text-align:center">缺点</th>
<th style="text-align:center">适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">Bundle</td>
<td style="text-align:center">简单易用</td>
<td style="text-align:center">只能传输Bundle支持的数据类型</td>
<td style="text-align:center">四大组件间的进程通信</td>
</tr>
<tr>
<td style="text-align:center">文件共享</td>
<td style="text-align:center">简单易用</td>
<td style="text-align:center">不适合高并发场景,并且无法做到进程间的通信</td>
<td style="text-align:center">无并访问情形,交换简单的数据实时性不高的场景</td>
</tr>
<tr>
<td style="text-align:center">AIDL</td>
<td style="text-align:center">功能强大,支持一对多并发通信,支持实时通信</td>
<td style="text-align:center">使用稍复杂,需要处理好线程同步</td>
<td style="text-align:center">一对多通信且有RPC需求</td>
</tr>
<tr>
<td style="text-align:center">Messenger</td>
<td style="text-align:center">功能一般,支持一对多串行通信,支持实时通信</td>
<td style="text-align:center">不能很好的处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型</td>
<td style="text-align:center">低并发的一对多即时通信,无RPC需求,或者无须返回结果的RPC需求</td>
</tr>
<tr>
<td style="text-align:center">ContentProvider</td>
<td style="text-align:center">在数据源访问方面功能强大,支持一对多并发数据共享</td>
<td style="text-align:center">可以理解闭为受约束的AIDL,主要提供数据源的CRUD操作</td>
<td style="text-align:center">一对多的进程间的数据共享</td>
</tr>
<tr>
<td style="text-align:center">Socket</td>
<td style="text-align:center">功能强大,可以通过网络传输字节流,支持一对多并发实时通信</td>
<td style="text-align:center">实现细节稍微有点烦琐,不支持直接的RPC</td>
<td style="text-align:center">网络数据交换</td>
</tr>
</tbody>
</table>
]]></content>
<categories>
<category> Android </category>
<category> 面试 </category>
</categories>
<tags>
<tag> Android </tag>
<tag> 面试 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Broadcast Receiver知识梳理]]></title>
<url>/2018/09/20/Broadcast-Receiver%E7%9F%A5%E8%AF%86%E6%A2%B3%E7%90%86/</url>
<content type="html"><![CDATA[<h4 id="Q-广播种类"><a href="#Q-广播种类" class="headerlink" title="Q:广播种类"></a>Q:广播种类</h4><p>分类</p>
<ul>
<li>普通广播(Normal Broadcast)</li>
<li>系统广播(System Broadcast)</li>
<li>有序广播(Ordered Broadcast)</li>
<li>粘性广播(Sticky Broadcast)(在Android5.0 & API 21中已经失效,不建议使用)</li>
<li>App应用内广播(Local Broadcast)</li>
</ul>
<h4 id="Q-广播的两种注册形式?区别在哪?"><a href="#Q-广播的两种注册形式?区别在哪?" class="headerlink" title="Q:广播的两种注册形式?区别在哪?"></a>Q:广播的两种注册形式?区别在哪?</h4><h5 id="静态注册"><a href="#静态注册" class="headerlink" title="静态注册"></a>静态注册</h5><ul>
<li>在AndroidMainfest中通过<receiver>标签声明</receiver></li>
<li>不受任何组件生命周期的影响</li>
<li>耗电、占内存</li>
<li>需要时刻监听广播</li>
</ul>
<h5 id="动态注册"><a href="#动态注册" class="headerlink" title="动态注册"></a>动态注册</h5><ul>
<li>在代码中调用Context.registerReveiver方法</li>
<li>非常驻,灵活,跟随组件的生命周期变化</li>
<li>需要特定时刻监听广播</li>
<li>动态注册的广播永远要快于静态注册的广播,不管静态注册的优先级设置的多高,不管动态注册的优先级有多低</li>
</ul>
<p><a href="https://www.jianshu.com/p/ca3d87a4cdf3" target="_blank" rel="external">参考</a></p>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> Broadcast Receiver </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Service知识梳理]]></title>
<url>/2018/09/17/Service%E7%9F%A5%E8%AF%86%E6%A2%B3%E7%90%86/</url>
<content type="html"><![CDATA[<h4 id="startService"><a href="#startService" class="headerlink" title="startService"></a>startService</h4><p>startService第一次启动会调用<code>onCreate</code>,<code>onCreate</code>只会在创建的时候调用一次,之后多次启动会多次调用<code>onStartCommand</code>。<code>stopService</code>会停止Service,多次调用<code>stopService</code>不会报错。</p>
<h4 id="bindService"><a href="#bindService" class="headerlink" title="bindService"></a>bindService</h4><p>bindService第一次启动会依次调用<code>onCreate</code>-><code>onBind</code>-><code>onServiceConnected</code>。多次调用<code>bindService</code>, <code>onBind</code>和<code>onServiceConnected</code>都不会多次回调。多次调用<code>unBindService</code>会报错。</p>
<h4 id="startCommand"><a href="#startCommand" class="headerlink" title="startCommand"></a>startCommand</h4><ul>
<li><strong>START_STICKY</strong>:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。</li>
<li><strong>START_NOT_STICKY</strong>:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。</li>
<li><strong>START_REDELIVER_INTENT</strong>:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。</li>
<li><strong>START_STICKY_COMPATIBILITY</strong>:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。</li>
</ul>
<p>服务在其托管进程的主线程中运行的</p>
<h4 id="Q-谈一谈Service的生命周期?"><a href="#Q-谈一谈Service的生命周期?" class="headerlink" title="Q:谈一谈Service的生命周期?"></a>Q:谈一谈Service的生命周期?</h4><p><img src="http://changqin.iaimer.com//20180917123329.png" alt=""></p>
<h4 id="Q-Service的两种启动方式?区别在哪?"><a href="#Q-Service的两种启动方式?区别在哪?" class="headerlink" title="Q:Service的两种启动方式?区别在哪?"></a>Q:Service的两种启动方式?区别在哪?</h4><h5 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h5><ul>
<li>开启服务的组件退出之后,服务还是可以在后台长期运行的。其他组件可以调用stopService(Intent)或者自身调用stopSelf停止</li>
<li>组件不能调用服务里面的方法</li>
</ul>
<h5 id="绑定"><a href="#绑定" class="headerlink" title="绑定"></a>绑定</h5><ul>
<li>组件销毁后服务自动被销毁,如果一个Service被多个组件绑定,只有所有的组件被销毁这个服务才会销毁</li>
<li>组件可以调用服务里面的方法</li>
</ul>
<h4 id="Q-一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory-方法?"><a href="#Q-一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory-方法?" class="headerlink" title="Q:一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory()方法?"></a>Q:一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory()方法?</h4><p>同时调用<code>stopService</code>和<code>unbindService</code>才可以回调<code>onDestory</code></p>
<h4 id="Q-Service-的生命周期方法-onCreate、onStart、onBind-等运行在哪个线程"><a href="#Q-Service-的生命周期方法-onCreate、onStart、onBind-等运行在哪个线程" class="headerlink" title="Q:Service 的生命周期方法 onCreate、onStart、onBind 等运行在哪个线程?"></a>Q:Service 的生命周期方法 onCreate、onStart、onBind 等运行在哪个线程?</h4><p>都运行在主线程</p>
<h4 id="Q-Service如何和Activity进行通信?"><a href="#Q-Service如何和Activity进行通信?" class="headerlink" title="Q:Service如何和Activity进行通信?"></a>Q:Service如何和Activity进行通信?</h4><ul>
<li>使用<code>Intent</code>,<code>onStartCommand</code>时候传入的<code>Intent</code></li>
<li><code>BroadcastReceiver</code>,Service发送,Activity接收</li>
<li>接口回调</li>
<li>共享硬盘存储,共享内存</li>
<li><code>ServiceConnection</code></li>
</ul>
<h4 id="Q-用过哪些系统Service?"><a href="#Q-用过哪些系统Service?" class="headerlink" title="Q:用过哪些系统Service?"></a>Q:用过哪些系统Service?</h4><p>获取系统Service一般用<code>getSystemService</code>方法。常见的Service有</p>
<ul>
<li>LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);</li>
<li>ActivityManagerService</li>
<li>PackageManagerService</li>
<li>WindowManagerService<br>参考<a href="https://blog.csdn.net/dongxianfei/article/details/53290643" target="_blank" rel="external">这里</a></li>
</ul>
<h4 id="Q-是否能在Service进行耗时操作?如果非要可以怎么做?"><a href="#Q-是否能在Service进行耗时操作?如果非要可以怎么做?" class="headerlink" title="Q:是否能在Service进行耗时操作?如果非要可以怎么做?"></a>Q:是否能在Service进行耗时操作?如果非要可以怎么做?</h4><p>不能。因为服务在其托管进程的主线程中运行,它既<strong>不</strong>创建自己的线程,也<strong>不</strong>在单独的进程中运行(除非另行指定)。它不可以做密集耗时的操作。如果非要做的话,可以启动一个新的线程来工作。</p>
<h4 id="Q-前台服务是什么?和普通服务的不同?如何去开启一个前台服务?"><a href="#Q-前台服务是什么?和普通服务的不同?如何去开启一个前台服务?" class="headerlink" title="Q:前台服务是什么?和普通服务的不同?如何去开启一个前台服务?"></a>Q:前台服务是什么?和普通服务的不同?如何去开启一个前台服务?</h4><ul>
<li>前台服务被认为是用户主动意识到的一种服务,因此在内存不足时,系统也不会考虑将其终止。 前台服务必须为状态栏提供通知,放在“正在进行”标题下方,这意味着除非服务停止或从前台移除,否则不能清除通知。</li>
<li>要请求让服务运行于前台,请调用 <code>startForeground()</code>。此方法采用两个参数:唯一标识通知的整型数和状态栏的 Notification。</li>
</ul>
<h4 id="Q-AlarmManager能实现定时的原理?"><a href="#Q-AlarmManager能实现定时的原理?" class="headerlink" title="Q:AlarmManager能实现定时的原理?"></a>Q:AlarmManager能实现定时的原理?</h4><h4 id="Q-是否了解ActivityManagerService,谈谈它发挥什么作用?"><a href="#Q-是否了解ActivityManagerService,谈谈它发挥什么作用?" class="headerlink" title="Q:是否了解ActivityManagerService,谈谈它发挥什么作用?"></a>Q:是否了解ActivityManagerService,谈谈它发挥什么作用?</h4><h4 id="Q-如何保证Service不被杀死?"><a href="#Q-如何保证Service不被杀死?" class="headerlink" title="Q:如何保证Service不被杀死?"></a>Q:如何保证Service不被杀死?</h4><ul>
<li>相互唤起,需要借助其他APP</li>
<li>service 相互使用广播唤起 (鸡肋)</li>
<li>和手机商合作 (最高效)</li>
<li>设置 service 等级,priority (鸡肋)</li>
<li>onStartCommand方法,返回 START_STICKY,内存充足的时候会重启 (鸡肋)</li>
</ul>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> Service </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Activity知识梳理]]></title>
<url>/2018/09/16/Activity%E7%9F%A5%E8%AF%86%E6%A2%B3%E7%90%86/</url>
<content type="html"><![CDATA[<h1 id="Activity知识梳理"><a href="#Activity知识梳理" class="headerlink" title="Activity知识梳理"></a>Activity知识梳理</h1><h2 id="1-Activity生命周期"><a href="#1-Activity生命周期" class="headerlink" title="1. Activity生命周期"></a>1. Activity生命周期</h2><p>大部分Copy总结自<a href="https://www.cnblogs.com/lwbqqyumidi/p/3769113.html" target="_blank" rel="external">这个博客</a>和<a href="https://developer.android.com/reference/android/app/Activity" target="_blank" rel="external">官方</a></p>
<p>Activity是由Activity栈进管理,当启动一个新的Activity后,此Activity将被加入到Activity栈顶并处于运行状态,之前的Activity在栈中位于此Activity底部并且不会出现在前台除非新Activity退出。Acitivity一般意义上有四种状态:</p>
<ol>
<li>当Activity位于栈顶时,此时正好处于屏幕最前方,此时处于<code>运行状态</code>;</li>
<li>当Activity失去了焦点但仍然对用于可见<code>(如栈顶的Activity是透明的或者栈顶Activity并不是铺满整个手机屏幕)</code>,此时处于<code>暂停状态</code>。这个状态的Activity仍然存活,当系统的内存极低的时候它会被杀死。</li>
<li>当Activity被其他Activity<code>完全遮挡</code>,此时此Activity对用户不可见,此时处于<code>停止状态</code>。这个时候它仍然保留着所有的状态和成员信息,然而,它对用户来说<code>不再可见</code>,所以它的窗口被隐藏,当需要在其他地方使用内存时,它常常被系统杀死。</li>
<li>当Activity由于人为或系统原因(如低内存等)被销毁,此时处于<code>销毁状态</code>;</li>
</ol>
<h4 id="官方图"><a href="#官方图" class="headerlink" title="官方图"></a>官方图</h4><p><img src="http://changqin.iaimer.com/2018091315368294235616.png" alt="2018091315368294235616.png"></p>
<p>图中需要注意一下几点:</p>
<p>1.Activity实例是由系统自动创建,并在不同的状态期间回调相应的方法。一个最简单的完整的Activity生命周期会按照如下顺序回调:onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy。称之为<code>entire lifetime</code>。</p>
<p>2.当执行onStart回调方法时,Activity开始被用户所见(也就是说,onCreate时用户是看不到此Activity的,那用户看到的是哪个?当然是此Activity之前的那个Activity),一直到onStop之前,此阶段Activity都是被用户可见,称之为<code>visible lifetime</code>。</p>
<p>3.当执行到onResume回调方法时,Activity可以响应用户交互,一直到onPause方法之前,此阶段Activity称之为<code>foreground lifetime</code>。</p>
<h3 id="示例与QA"><a href="#示例与QA" class="headerlink" title="示例与QA"></a>示例与QA</h3><p>假设有两个Activity,A和B。</p>
<h4 id="情况一-AB都不是透明的"><a href="#情况一-AB都不是透明的" class="headerlink" title="情况一 AB都不是透明的"></a>情况一 AB都不是透明的</h4><p>启动A,开始时,A被实例化,执行的回调有A:onCreate -> A:onStart -> A:onResume。</p>
<p>当用户点击A中按钮来到B时,假设B全部遮挡住了A,将依次执行A:onPause -> B:onCreate -> B:onStart -> B:onResume -> A:onStop。<br>此时如果点击Back键,将依次执行B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy。</p>
<h4 id="情况二-B不是透明的"><a href="#情况二-B不是透明的" class="headerlink" title="情况二 B不是透明的"></a>情况二 B不是透明的</h4><p>启动A,开始时,A被实例化,执行的回调有A:onCreate -> A:onStart -> A:onResume。<br>当用户点击A中按钮来到B时,,将依次执行A:onPause -> B:onCreate -> B:onStart -> B:onResume 。<br>此时如果点击Back键,将依次执行B:onPause -> A:onResume -> B:onStop -> B:onDestroy。</p>
<h4 id="情况三-在A已经位于栈顶的时候弹出Dialog"><a href="#情况三-在A已经位于栈顶的时候弹出Dialog" class="headerlink" title="情况三 在A已经位于栈顶的时候弹出Dialog"></a>情况三 在A已经位于栈顶的时候弹出Dialog</h4><ol>
<li>启动Dialog的主题是默认的。<br>启动A,A被实例化,执行的回调有A:onCreate -> A:onStart -> A:onResume。当在A是中弹出Dialog时,A的生命周期不会有任何变化。</li>
<li>启动Dialog的主题是Activity的。 待测</li>
</ol>
<h4 id="情况四-在A已经位于栈顶的时候弹出PopWindow"><a href="#情况四-在A已经位于栈顶的时候弹出PopWindow" class="headerlink" title="情况四 在A已经位于栈顶的时候弹出PopWindow"></a>情况四 在A已经位于栈顶的时候弹出PopWindow</h4><p>没任何影响</p>
<h4 id="情况五-横竖屏切换时候的生命周期"><a href="#情况五-横竖屏切换时候的生命周期" class="headerlink" title="情况五 横竖屏切换时候的生命周期"></a>情况五 横竖屏切换时候的生命周期</h4><p><img src="http://changqin.iaimer.com//20180915205621.png" alt=""><br>此处必须设置<code>screenSize</code>的原文在<a href="https://developer.android.com/guide/topics/resources/runtime-changes?hl=zh-cn" target="_blank" rel="external">这里</a></p>
<h4 id="Q-onSaveInstanceState何时会调用?"><a href="#Q-onSaveInstanceState何时会调用?" class="headerlink" title="Q:onSaveInstanceState何时会调用?"></a>Q:onSaveInstanceState何时会调用?</h4><p>只有在Activity异常终止的时候才会调用,也可以说是Activity即将被销毁并且有机会重新显示的情况下才会调用。</p>
<h5 id="会触发的情况"><a href="#会触发的情况" class="headerlink" title="会触发的情况"></a>会触发的情况</h5><ul>
<li>Activity启动一个新的Activity的时候</li>
<li>Home键</li>
<li>Menu键</li>
<li>锁屏</li>
<li>用户旋转屏幕(<code>API>13且没有设置orientation|screenSize</code>)。</li>
</ul>
<h5 id="不会触发的情况"><a href="#不会触发的情况" class="headerlink" title="不会触发的情况"></a>不会触发的情况</h5><ul>
<li>用户按Back键不会触发,</li>
</ul>
<p><code>onRestoreInstanceState</code>不一定会和<code>onSaveInstanceState</code>成对出现。</p>
<h4 id="Q-如何避免配置改变时Activity重建?"><a href="#Q-如何避免配置改变时Activity重建?" class="headerlink" title="Q:如何避免配置改变时Activity重建?"></a>Q:如何避免配置改变时Activity重建?</h4><ul>
<li>API<13设置configChanges=”orientation”或configChanges=”orientation|keyboardHidden”</li>
<li>API>13设置configChanges=”orientation|screenSize”</li>
</ul>
<h4 id="Q-优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?"><a href="#Q-优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?" class="headerlink" title="Q:优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?"></a>Q:优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?</h4><p>A: Activity被回收后可以在onCreate中的Bundle中判断是否有值来恢复数据。也可以在onRestoreInstanceState中恢复。</p>
<h4 id="Q-说下Activity的四种启动模式?"><a href="#Q-说下Activity的四种启动模式?" class="headerlink" title="Q:说下Activity的四种启动模式?"></a>Q:说下Activity的四种启动模式?</h4><p>(adb shell dumpsys activity 可以查看栈中的Activity)</p>
<ol>
<li><p><strong>standard</strong></p>
<p>标准模式。一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。谁启动了这个Activity,这个Activity就运行在它的那个任务栈中。</p>
</li>
<li><p><strong>singleTop</strong></p>
<p>栈顶复用模式。如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时会回调它的onNewIntent方法。</p>
</li>
<li><p><strong>singleTask</strong></p>
<p>栈内复用模式。只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,也会回调onNewIntent方法。比如Activity A,系统会首先寻找是否存在A想要的任务栈。如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放入栈中。如果存在,看是否有A的实例在栈中存在。如果存在,系统会把A调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建A的实例并把A压入栈中。</p>
<p>singleTask具有clearTop的效果。</p>
</li>
<li><p><strong>singleInstance</strong></p>
<p>单实例模式。具有singleTask的所有特性。具有此种模式的Activity只能单独地位于一个任务栈中。</p>
</li>
</ol>
<h4 id="Q-谈谈singleTop和singleTask的区别以及应用场景"><a href="#Q-谈谈singleTop和singleTask的区别以及应用场景" class="headerlink" title="Q:谈谈singleTop和singleTask的区别以及应用场景"></a>Q:谈谈singleTop和singleTask的区别以及应用场景</h4><h5 id="singleTop"><a href="#singleTop" class="headerlink" title="singleTop"></a>singleTop</h5><ul>
<li>处理通知</li>
</ul>
<h5 id="singleTask"><a href="#singleTask" class="headerlink" title="singleTask"></a>singleTask</h5><ul>
<li>浏览器</li>
<li>微信小程序</li>
</ul>
<h4 id="Q-onNewIntent-调用时机?"><a href="#Q-onNewIntent-调用时机?" class="headerlink" title="Q:onNewIntent()调用时机?"></a>Q:onNewIntent()调用时机?</h4><ul>
<li>启动一个SingleTop且位于栈顶的Activity的时候</li>
<li>启动一个SingleTask且位于栈内的Activity的时候</li>
</ul>
<h4 id="Q-了解哪些Activity启动模式的标记位?"><a href="#Q-了解哪些Activity启动模式的标记位?" class="headerlink" title="Q:了解哪些Activity启动模式的标记位?"></a>Q:了解哪些Activity启动模式的标记位?</h4><h5 id="设定Activity启动模式的标记位"><a href="#设定Activity启动模式的标记位" class="headerlink" title="设定Activity启动模式的标记位"></a>设定Activity启动模式的标记位</h5><ul>
<li><a href="https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_SINGLE_TOP" target="_blank" rel="external">FLAG_ACTIVITY_SINGLE_TOP</a></li>
<li><a href="https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK" target="_blank" rel="external">FLAG_ACTIVITY_NEW_TASK</a></li>
</ul>
<h5 id="设定Activity运行状态的标记位"><a href="#设定Activity运行状态的标记位" class="headerlink" title="设定Activity运行状态的标记位"></a>设定Activity运行状态的标记位</h5><ul>
<li><a href="https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP" target="_blank" rel="external">FLAG_ACTIVITY_CLEAR_TOP</a></li>
</ul>
<h4 id="Q-如何启动其他应用的Activity?"><a href="#Q-如何启动其他应用的Activity?" class="headerlink" title="Q:如何启动其他应用的Activity?"></a>Q:如何启动其他应用的Activity?</h4><p>用隐式意图启动Activity</p>
<h4 id="Q-Activity的启动过程?"><a href="#Q-Activity的启动过程?" class="headerlink" title="Q:Activity的启动过程?"></a>Q:Activity的启动过程?</h4><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul>
<li><a href="https://developer.android.com/guide/components/tasks-and-back-stack" target="_blank" rel="external">https://developer.android.com/guide/components/tasks-and-back-stack</a></li>
<li><a href="https://developer.android.com/guide/topics/manifest/activity-element" target="_blank" rel="external">https://developer.android.com/guide/topics/manifest/activity-element</a></li>
</ul>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> Activity </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android中图片大小知识总结]]></title>
<url>/2018/09/06/Android%E4%B8%AD%E5%9B%BE%E7%89%87%E5%A4%A7%E5%B0%8F%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/</url>
<content type="html"><![CDATA[<h3 id="Android中屏幕密度的相关概念"><a href="#Android中屏幕密度的相关概念" class="headerlink" title="Android中屏幕密度的相关概念"></a>Android中屏幕密度的相关概念</h3><ul>
<li><p><strong>density</strong>:The logical density of the display. This is a scaling factor for the Density Independent Pixel unit, where one DIP is one pixel on an approximately 160 dpi screen (for example a 240x320, 1.5”x2” screen), providing the baseline of the system’s display. Thus on a 160dpi screen this density value will be 1; on a 120 dpi screen it would be .75; etc.<br>This value does not exactly follow the real screen size (as given by xdpi and ydpi, but rather is used to scale the size of the overall UI in steps based on gross changes in the display dpi. For example, a 240x320 screen will have a density of 1 even if its width is 1.8”, 1.3”, etc. However, if the screen resolution is increased to 320x480 but the screen size remained 1.5”x2” then the density would be increased (probably to 1.5).</p>
</li>
<li><p><strong>densityDpi</strong>:The screen density expressed as dots-per-inch.</p>
</li>
</ul>
<p>简单来说,可以理解为 density 的数值是 1dp=density px;densityDpi 是屏幕每英寸对应多少个点(不是像素点),在 DisplayMetrics 当中,这两个的关系是线性的:</p>
<table>
<thead>
<tr>
<th><strong>density</strong></th>
<th style="text-align:center">1</th>
<th style="text-align:center">1.5</th>
<th style="text-align:center">2</th>
<th style="text-align:center">3</th>
<th style="text-align:center">3.5</th>
<th style="text-align:center">4</th>
</tr>
</thead>
<tbody>
<tr>
<td>densityDpi</td>
<td style="text-align:center">160</td>
<td style="text-align:center">240</td>
<td style="text-align:center">320</td>
<td style="text-align:center">480</td>
<td style="text-align:center">560</td>
<td style="text-align:center">640</td>
</tr>
</tbody>
</table>
<h3 id="分析源码"><a href="#分析源码" class="headerlink" title="分析源码"></a>分析源码</h3><ol>
<li>加载一张640 * 427 310KB的png图片,图片放drawable-hdpi目录下。<br>模拟器参数<br>density: 2.625<br>densityDpi: 420<br>byteCount: 3346560<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">Bitmap qingye = BitmapFactory.decodeResource(getResources(), R.drawable.friend_small);</div><div class="line">Log.e(TAG, "getByteCount= " + qingye.getByteCount());</div></pre></td></tr></table></figure>
</li>
</ol>
<p>打印日志,<code>getByteCount= 3346560</code>约等于3M</p>
<ol>
<li>查看<code>getByteCount</code>方法<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></pre></td><td class="code"><pre><div class="line">public final int getByteCount() {</div><div class="line"> if (mRecycled) {</div><div class="line"> Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! "</div><div class="line"> + "This is undefined behavior!");</div><div class="line"> return 0;</div><div class="line"> }</div><div class="line"> // int result permits bitmaps up to 46,340 x 46,340</div><div class="line"> return getRowBytes() * getHeight(); }</div></pre></td></tr></table></figure>
</li>
</ol>
<p>可以看出总大小和<code>getRowBytes()</code>以及图片的高度有关<br>进而查看<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">public final int getRowBytes() {</div><div class="line"> if (mRecycled) {</div><div class="line"> Log.w(TAG, "Called getRowBytes() on a recycle()'d bitmap! This is undefined behavior!");</div><div class="line"> }</div><div class="line"> return nativeRowBytes(mNativePtr); }</div></pre></td></tr></table></figure></p>
<p>发现这是一个naive方法<br><code>private static native int nativeRowBytes(long nativeBitmap);</code></p>
<p>在<code>SkBitmap.h</code>中<br><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">/** Return the number of bytes between subsequent rows of the bitmap. */</div><div class="line">size_t rowBytes() const { return fRowBytes; }</div></pre></td></tr></table></figure></p>
<p>在<code>SkBitmap.cpp</code>中<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">size_t SkBitmap::ComputeRowBytes(Config c, int width) { return SkColorTypeMinRowBytes(SkBitmapConfigToColorType(c), width); }</div></pre></td></tr></table></figure></p>
<p>在<code>SkImageInfo.h</code>中<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">static int SkColorTypeBytesPerPixel(SkColorType ct) {</div><div class="line"> static const uint8_t gSize[] = {</div><div class="line"> 0, // Unknown</div><div class="line"> 1, // Alpha_8</div><div class="line"> 2, // RGB_565</div><div class="line"> 2, // ARGB_4444</div><div class="line"> 4, // RGBA_8888</div><div class="line"> 4, // BGRA_8888</div><div class="line"> 1, // kIndex_8</div><div class="line"> };</div><div class="line"> SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gSize) == (size_t)(kLastEnum_SkColorType + 1),</div><div class="line"> size_mismatch_with_SkColorType_enum);</div><div class="line"></div><div class="line"> SkASSERT((size_t)ct < SK_ARRAY_COUNT(gSize));</div><div class="line"> return gSize[ct];</div><div class="line">}</div><div class="line"></div><div class="line">static inline size_t SkColorTypeMinRowBytes(SkColorType ct, int width) {</div><div class="line"> return width * SkColorTypeBytesPerPixel(ct);</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>可以看到argb_8888格式的一个像素占用4个字节</p>
<ol>
<li>求得公式<br>公式= 图片长<em>宽</em>4,对吗?<br>640 * 427 * 4 = 1093120 不等于 3346560</li>
</ol>
<p>在<strong>BitmapFactory.java</strong>中<br><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="function"><span class="keyword">public</span> <span class="keyword">static</span> Bitmap <span class="title">decodeResourceStream</span><span class="params">(Resources res, TypedValue value,</span></span></div><div class="line"><span class="function"><span class="params"> InputStream is, Rect pad, Options opts)</span> </span>{</div><div class="line"> validate(opts);</div><div class="line"> <span class="keyword">if</span> (opts == <span class="keyword">null</span>) {</div><div class="line"> opts = <span class="keyword">new</span> Options();</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (opts.inDensity == <span class="number">0</span> && value != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">final</span> <span class="keyword">int</span> density = value.density;</div><div class="line"> <span class="keyword">if</span> (density == TypedValue.DENSITY_DEFAULT) {</div><div class="line"> opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (density != TypedValue.DENSITY_NONE) {</div><div class="line"> opts.inDensity = density;<span class="comment">//这里density的值如果对应资源目录为hdpi的话,就是240</span></div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (opts.inTargetDensity == <span class="number">0</span> && res != <span class="keyword">null</span>) {</div><div class="line"> opts.inTargetDensity = res.getDisplayMetrics().densityDpi;</div><div class="line"><span class="comment">//这个inTargetDensity是当前屏幕的densityDpi,我的模拟器是420</span></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> decodeStream(is, pad, opts); }</div></pre></td></tr></table></figure></p>
<p>我们最应该关心的是什么呢?是 inDensity 和 inTargetDensity,这两个值与下面 cpp 文件里面的 density 和 targetDensity 相对应。重复一下,inDensity 就是原始资源的 density,inTargetDensity 就是屏幕的 density。</p>
<p>在<code>BitmapFactory.cpp</code>的<code>doDecode</code>方法中<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><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></pre></td><td class="code"><pre><div class="line">if (env - > GetBooleanField(options, gOptions_scaledFieldID)) {</div><div class="line"> const int density = env - > GetIntField(options, gOptions_densityFieldID);</div><div class="line"> const int targetDensity = env - > GetIntField(options, gOptions_targetDensityFieldID);</div><div class="line"> const int screenDensity = env - > GetIntField(options, gOptions_screenDensityFieldID);</div><div class="line"> if (density != 0 && targetDensity != 0 && density != screenDensity) {</div><div class="line"> scale = (float) targetDensity / density;</div><div class="line"> }</div><div class="line">}</div><div class="line">...</div><div class="line">//这里这个deodingBitmap就是解码出来的bitmap,大小是图片原始的大小</div><div class="line"> int scaledWidth = decodingBitmap.width();</div><div class="line"> int scaledHeight = decodingBitmap.height();</div><div class="line"></div><div class="line"> if (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) {</div><div class="line"> scaledWidth = int(scaledWidth * scale + 0.5 f);</div><div class="line"> scaledHeight = int(scaledHeight * scale + 0.5 f);</div><div class="line"> }</div><div class="line">...</div><div class="line">if (willScale) {</div><div class="line"> // This is weird so let me explain: we could use the scale parameter</div><div class="line"> // directly, but for historical reasons this is how the corresponding</div><div class="line"> // Dalvik code has always behaved. We simply recreate the behavior here.</div><div class="line"> // The result is slightly different from simply using scale because of</div><div class="line"> // the 0.5f rounding bias applied when computing the target image size</div><div class="line"> const float sx = scaledWidth / float(decodingBitmap.width());</div><div class="line"> const float sy = scaledHeight / float(decodingBitmap.height());</div><div class="line"></div><div class="line"> // TODO: avoid copying when scaled size equals decodingBitmap size</div><div class="line"> SkColorType colorType = colorTypeForScaledOutput(decodingBitmap.colorType());</div><div class="line"> // FIXME: If the alphaType is kUnpremul and the image has alpha, the</div><div class="line"> // colors may not be correct, since Skia does not yet support drawing</div><div class="line"> // to/from unpremultiplied bitmaps.</div><div class="line"> outputBitmap - > setInfo(SkImageInfo::Make(scaledWidth, scaledHeight,</div><div class="line"> colorType, decodingBitmap.alphaType()));</div><div class="line"> if (!outputBitmap - > allocPixels(outputAllocator, NULL)) {</div><div class="line"> return nullObjectReturn("allocation failed for scaled bitmap");</div><div class="line"> }</div><div class="line"></div><div class="line"> // If outputBitmap's pixels are newly allocated by Java, there is no need</div><div class="line"> // to erase to 0, since the pixels were initialized to 0.</div><div class="line"> if (outputAllocator != & javaAllocator) {</div><div class="line"> outputBitmap - > eraseColor(0);</div><div class="line"> }</div><div class="line"></div><div class="line"> SkPaint paint;</div><div class="line"> paint.setFilterLevel(SkPaint::kLow_FilterLevel);</div><div class="line"></div><div class="line"> SkCanvas canvas( * outputBitmap);</div><div class="line"> canvas.scale(sx, sy);</div><div class="line"> canvas.drawBitmap(decodingBitmap, 0.0 f, 0.0 f, & paint);</div><div class="line">} else {</div><div class="line"> outputBitmap - > swap(decodingBitmap);</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>scale = (float) targetDensity / density;<br>在这个例子中,scale = 420 / 240 = 1.75<br>所以byteCount = 640 * 427 * 1.75 * 1.75 * 4 = 3347680 约等于3346560<br>因为scaledWidth还有0.5f的精度,所以加上精度<br>640 * 1.75 + 0.5 = 1120<br>427 * 1.75 + 0.5 = 747<br>1120 * 747 * 4 = <strong>3346560</strong></p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>Android加载一张图片的大小与下列情况有关</p>
<ul>
<li>色彩格式,如果是 ARGB8888 那么就是一个像素4个字节,如果是 RGB565 那就是2个字节</li>
<li>原始文件存放的资源目录hdpi还是其他</li>
<li>目标屏幕的密度</li>
</ul>
<p>总结转载自<a href="https://juejin.im/entry/56f23e001532bc00507e1c64" target="_blank" rel="external">这里</a></p>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Kotlin学习之类的继承]]></title>
<url>/2018/06/23/Kotlin%E5%AD%A6%E4%B9%A0%E4%B9%8B%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF/</url>
<content type="html"><![CDATA[<h3 id="1-Kotlin使用了-来代替Jave中的extend和implements。Kotlin和java一样,单继承多接口。"><a href="#1-Kotlin使用了-来代替Jave中的extend和implements。Kotlin和java一样,单继承多接口。" class="headerlink" title="1. Kotlin使用了:来代替Jave中的extend和implements。Kotlin和java一样,单继承多接口。"></a>1. Kotlin使用了<code>:</code>来代替Jave中的<code>extend</code>和<code>implements</code>。Kotlin和java一样,单继承多接口。</h3><h3 id="2-Kotlin可以在接口中添加带默认实现的方法"><a href="#2-Kotlin可以在接口中添加带默认实现的方法" class="headerlink" title="2. Kotlin可以在接口中添加带默认实现的方法"></a>2. Kotlin可以在接口中添加带默认实现的方法</h3><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></pre></td><td class="code"><pre><div class="line">interface Clickable {</div><div class="line"> fun click()</div><div class="line"> fun showOff() = println("I'm clickable!")</div><div class="line">}</div></pre></td></tr></table></figure>
<p>实现这个接口后可以重写出可以直接省略</p>
<h3 id="3-调用继承自接口方法的实现"><a href="#3-调用继承自接口方法的实现" class="headerlink" title="3. 调用继承自接口方法的实现"></a>3. 调用继承自接口方法的实现</h3><p>如果有两个接口有一个共同的方法,有一个类同时实现了这两个接口。那么这个方法默认不会调用任何接口的方法。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">interface Focusable {</div><div class="line"> fun setFocus(b: Boolean) = println("I ${if (b) "got" else "lose"} focus.")</div><div class="line"> fun showOff() = println("I'm foucusable!")</div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<categories>
<category> Kotlin </category>
</categories>
<tags>
<tag> Kotlin </tag>
</tags>
</entry>
<entry>
<title><![CDATA[JetPack之lifecycles]]></title>
<url>/2018/06/19/JetPack%E4%B9%8Blifecycles/</url>
<content type="html"><![CDATA[<p> 一般写组件的时候,例如一个获取位置的小组件,我们会这么写。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><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">class MyActivity extends AppCompatActivity {</div><div class="line"> private MyLocationListener myLocationListener; public void onCreate(...) {</div><div class="line"> myLocationListener = new MyLocationListener(this, location -> {</div><div class="line"> // update UI</div><div class="line"> });</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onStart() {</div><div class="line"> super.onStart();</div><div class="line"> Util.checkUserStatus(result -> {</div><div class="line"> // what if this callback is invoked AFTER activity is stopped?</div><div class="line"> if (result) {</div><div class="line"> myLocationListener.start();</div><div class="line"> }</div><div class="line"> });</div><div class="line"> }</div><div class="line"></div><div class="line"> @Override</div><div class="line"> public void onStop() {</div><div class="line"> super.onStop();</div><div class="line"> myLocationListener.stop();</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>我们会在<code>onStart</code>或<code>onResume</code>的时候注入监听,在<code>onPause</code>或<code>onDestory</code>的时候移除监听。如果我们有很多这样的小组件,维护起来很是麻烦。而且如果要在<br><code>onStart</code>的时候做配置回调,那么有可能<code>onStop</code>比<code>onStart</code>会提前结束。这样就更麻烦了。</p>
<h3 id="Lifecycle"><a href="#Lifecycle" class="headerlink" title="Lifecycle"></a>Lifecycle</h3><p>Lifecycle是一个持有其他组件(例如<code>activity</code>和<code>fragment</code>)的生命周期信息状态的一个类,它允许其他对象观察这个状态。</p>
<p>它有两个主要的成员和生命周期状态有联系。</p>
<ul>
<li><p><code>Event</code>。这个生命周期事件从<code>framework</code>和<code>Lifecycle</code>进行派发。这些事件对应<code>activity</code>和<code>fragment</code>中的生命周期回调。</p>
</li>
<li><p><code>State</code>。生命周期对象组件的当前状态。</p>
</li>
</ul>
<p><img src="http://changqin.iaimer.com//20180619154207.png" alt=""></p>
<p>一个类可以通过向其方法添加注解来监视组件的生命周期状态。然后,通过调用<code>Lifecycle</code>类的<code>addObserver()</code>方法来添加一个观察者。下面是示例代码。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">public class MyObserver implements LifecycleObserver {</div><div class="line"> @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)</div><div class="line"> public void connectListener() {</div><div class="line"> ...</div><div class="line"> }</div><div class="line"></div><div class="line"> @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)</div><div class="line"> public void disconnectListener() {</div><div class="line"> ...</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">myLifecycleOwner.getLifecycle().addObserver(new MyObserver());</div></pre></td></tr></table></figure>
<p>在上面的示例中,<code>myLifecycleOwner</code>对象实现了<code>LifecycleOwner</code>接口。</p>
<h3 id="LifecycleOwner"><a href="#LifecycleOwner" class="headerlink" title="LifecycleOwner"></a>LifecycleOwner</h3><p>`Lifecycle``可以查看当前对象的生命周期。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">if (lifecycle.getCurrentState().isAtLeast(STARTED)) { </div><div class="line"> // do something</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p><code>Fragment</code>和<code>Activitie</code>在<code>Support Library</code><strong>26.1.0</strong>之后就已经实现了<code>LifecycleOwner</code>接口。</p>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> Arch </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android中的长按快捷方式实现]]></title>
<url>/2018/06/15/Android%E4%B8%AD%E7%9A%84%E9%95%BF%E6%8C%89%E5%BF%AB%E6%8D%B7%E6%96%B9%E5%BC%8F%E5%AE%9E%E7%8E%B0/</url>
<content type="html"><![CDATA[<h4 id="快捷方式"><a href="#快捷方式" class="headerlink" title="快捷方式"></a>快捷方式</h4><blockquote>
<p> Android 7.1 (API level 25)以上才支持</p>
</blockquote>
<h3 id="1-三种类型"><a href="#1-三种类型" class="headerlink" title="1. 三种类型"></a>1. 三种类型</h3><ul>
<li>静态类型。这样实现的话当需要更新快捷方式的时候必须更新整个APP</li>
<li>动态类型。这样可以在APP运行的时候利用<code>ShortcutManager</code>进行添加、更新或移除</li>
<li>桌面类型。这种也是能在运行时添加,也是利用<code>ShortcutManager</code>进行操作。但是需要用户同意才行</li>
</ul>
<h3 id="2-静态快捷方式的使用"><a href="#2-静态快捷方式的使用" class="headerlink" title="2. 静态快捷方式的使用"></a>2. 静态快捷方式的使用</h3><h4 id="1-在AndroidManifest-xml中找到主Activity。即包含android-intent-action-MAIN和android-intent-category-LAUNCHER的。"><a href="#1-在AndroidManifest-xml中找到主Activity。即包含android-intent-action-MAIN和android-intent-category-LAUNCHER的。" class="headerlink" title="1. 在AndroidManifest.xml中找到主Activity。即包含android.intent.action.MAIN和android.intent.category.LAUNCHER的。"></a>1. 在<code>AndroidManifest.xml</code>中找到主<code>Activity</code>。即包含<code>android.intent.action.MAIN</code>和<code>android.intent.category.LAUNCHER</code>的。</h4><h4 id="2-添加-lt-meta-data-gt-节点"><a href="#2-添加-lt-meta-data-gt-节点" class="headerlink" title="2. 添加<meta-data>节点"></a>2. 添加<code><meta-data></code>节点</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"</div><div class="line"> package="com.changqin.androidfuturejava"> <application android:name=".App"</div><div class="line"> android:allowBackup="true"</div><div class="line"> android:icon="@mipmap/ic_launcher"</div><div class="line"> android:label="@string/app_name"</div><div class="line"> android:roundIcon="@mipmap/ic_launcher_round"</div><div class="line"> android:supportsRtl="true"</div><div class="line"> android:theme="@style/AppTheme"></div><div class="line"> <activity android:name=".MainActivity"></div><div class="line"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/></div><div class="line"> </intent-filter> <meta-data android:name="android.app.shortcuts"</div><div class="line"> android:resource="@xml/shortcuts" /></div><div class="line"> </activity> </div><div class="line"></manifest></div></pre></td></tr></table></figure>
<h4 id="3-创建res-xml-shortcuts-xml"><a href="#3-创建res-xml-shortcuts-xml" class="headerlink" title="3. 创建res/xml/shortcuts.xml"></a>3. 创建<code>res/xml/shortcuts.xml</code></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><shortcuts xmlns:android="http://schemas.android.com/apk/res/android"></div><div class="line"> <shortcut android:shortcutId="compose"</div><div class="line"> android:enabled="true"</div><div class="line"> android:icon="@drawable/shortcuts_add"</div><div class="line"> android:shortcutShortLabel="@string/test1"</div><div class="line"> android:shortcutLongLabel="@string/test2"</div><div class="line"> android:shortcutDisabledMessage="@string/test3"></div><div class="line"> <intent android:action="android.intent.action.VIEW"</div><div class="line"> android:targetPackage="com.changqin.androidfuturejava"</div><div class="line"> android:targetClass="com.changqin.androidfuturejava.shortcut.ShortTestActivity" /></div><div class="line"> <!-- If your shortcut is associated with multiple intents, include them</div><div class="line"> here. The last intent in the list determines what the user sees when they launch this shortcut. --> <categories android:name="android.shortcut.conversation" /></div><div class="line"> </shortcut> </div><div class="line"><!-- Specify more shortcuts here. --> </shortcuts></div></pre></td></tr></table></figure>
<ul>
<li><code>shortcutShortLabel</code>指的是快捷方式的<code>简明短语</code>。</li>
<li><code>shortcutLongLabel</code>指的是<code>扩展短语</code>,如果有足够的空间,APP将显示这个值而不是<code>shortcutShortLabel</code>。</li>
<li><code>shortcutDisabledMessage</code>指的是当用户试图启动禁用的快捷方式时,APP中出现的消息。这个消息应该向用户解释为什么现在禁用了快捷方式。如果<code>android:enabled</code>是<code>true</code>,则该属性的值没有影响。</li>
<li><code>android:shortcutShortLabel</code>、<code>android:shortcutLongLabel</code>和<code>android:shortcutDisabledMessage</code>必须使用<code>@string/shortcut_short_label</code>格式</li>
</ul>
<p>正常显示的快捷方式<br><img src="http://changqin.iaimer.com//20180615144615.png" alt=""></p>
<h3 id="3-使用动态快捷方式"><a href="#3-使用动态快捷方式" class="headerlink" title="3. 使用动态快捷方式"></a>3. 使用动态快捷方式</h3><p>动态快捷方式应该为应用程序中特定的、上下文敏感的操作提供<code>actions</code>。这些<code>actions</code>可以在应用程序的使用之间进行更改,甚至在应用程序运行时也可以进行更改。<br><code>ShortcutManager</code>允许我们在动态快捷方式中做以下操作</p>
<ul>
<li><strong>添加</strong>: 使用<code>setDynamicShortcuts()</code>来重新添加整个快捷方列表</li>
<li><strong>更新</strong> 使用<code>updateShortcuts()</code>来更新</li>
<li><strong>移除</strong> 使用<code>removeDynamicShortcuts()</code>来移除一组,或者使用<code>removeAllDynamicShortcuts()</code>来移除所有的快捷方式</li>
</ul>
<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></pre></td><td class="code"><pre><div class="line">@TargetApi(Build.VERSION_CODES.N_MR1)</div><div class="line">public void addShort(View view) {</div><div class="line"> ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);</div><div class="line"> ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")</div><div class="line"> .setShortLabel("Web site")</div><div class="line"> .setLongLabel("Open the web site")</div><div class="line"> .setIcon(Icon.createWithResource(this, R.drawable.ic_add_white_24dp))</div><div class="line"> .setIntent(new Intent(Intent.ACTION_VIEW,</div><div class="line"> Uri.parse("https://changqin.win")))</div><div class="line"> .build(); shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut)); Toast.makeText(this,"add success",Toast.LENGTH_SHORT).show(); }</div></pre></td></tr></table></figure>
<h3 id="4-使用桌面快捷方式"><a href="#4-使用桌面快捷方式" class="headerlink" title="4. 使用桌面快捷方式"></a>4. 使用桌面快捷方式</h3><p>在Android 8.0 (API level 26)或以上,我们可以创建桌面快捷方式。不同于前两者,桌面快捷方式允许有自己独立的icon。</p>
<p>创建步骤</p>
<ol>
<li>使用<code>isRequestPinShortcutSupported()</code>来验证设备是否支持在APP上创建快捷方式。</li>
<li>创建<code>ShortcutInfo</code>对象。<br> a. 如果对象已存在,只需创建包含<code>ID</code>的对象即可。系统自动查找与快捷方式相关的所有信息。<br> b. 如果是一个新的对象,那么创建的时候必须包含<code>ID</code>、<code>intent</code>和<code>short label</code></li>
<li>调用<code>requestPinShortcut()</code>请求添加桌面快捷方式。在此期间,可以通过<code>PendingIntent</code>对象来监听快捷方式是否添加成功。ps: 如果用户不允许添加,是不会收到回调的。当快捷方式添加成功后,可以用<code>updateShortcuts()</code>来更新。</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">@RequiresApi(api = Build.VERSION_CODES.O)</div><div class="line">public void addDesktopShort(View view) {</div><div class="line"> if (mShortcutManager.isRequestPinShortcutSupported()) {</div><div class="line"> // Assumes there's already a shortcut with the ID "my-shortcut".</div><div class="line"> // The shortcut must be enabled. ShortcutInfo pinShortcutInfo =</div><div class="line"> new ShortcutInfo.Builder(this, "my-shortcut")</div><div class="line"> .build(); // Create the PendingIntent object only if your app needs to be notified</div><div class="line"> // that the user allowed the shortcut to be pinned. Note that, if the // pinning operation fails, your app isn't notified. We assume here that the // app has implemented a method called createShortcutResultIntent() that // returns a broadcast intent. Intent pinnedShortcutCallbackIntent =</div><div class="line"> mShortcutManager.createShortcutResultIntent(pinShortcutInfo); // Configure the intent so that your app's broadcast receiver gets</div><div class="line"> // the callback successfully. PendingIntent successCallback = PendingIntent.getBroadcast(this, 0,</div><div class="line"> pinnedShortcutCallbackIntent, 0); mShortcutManager.requestPinShortcut(pinShortcutInfo,</div><div class="line"> successCallback.getIntentSender());</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><img src="http://changqin.iaimer.com//20180615153135.png" alt=""></p>
]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android 快捷方式 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android中的MultiDex]]></title>
<url>/2018/06/12/Android%E4%B8%AD%E7%9A%84MultiDex/</url>
<content type="html"><![CDATA[<h3 id="1-简介"><a href="#1-简介" class="headerlink" title="1. 简介"></a>1. 简介</h3><p>在安卓开发中,当开发到一定的版本,apk有可能会遇到64K方法问题。指的是Android中的可执行文件.dex中的Java方法引用超过65536。</p>
<h3 id="2-使用MultiDex解决64K限制问题"><a href="#2-使用MultiDex解决64K限制问题" class="headerlink" title="2. 使用MultiDex解决64K限制问题"></a>2. 使用MultiDex解决64K限制问题</h3><ul>
<li><p>Android5.0之前,系统使用的是Dalvik虚拟机来执行应用。默认情况下,Dalvik为每个apk只生成一个classes.dex文件,为了规避单个.dex文件方法个数超过64K的问题,我们需要拆分这个单一的dex文件,拆分后可能出现classes.dex,classes2.dex等多个.dex文件。应用启动的时候会先加载classes.dex文件,我们称之为主dex文件。</p>
</li>
<li><p>Android5.0之后,Android开始使用ART虚拟机来代替Dalvik虚拟机,ART天然支持从apk文件中加载多个.dex文件,在应用安装期间,它会执行一个预编译操作。将所有的dex编译成一个单一的.oat文件,在应用运行是去加载这个.oat文件,而不是一个一个的加载.dex文件。</p>
</li>
</ul>
<h3 id="3-规避方法"><a href="#3-规避方法" class="headerlink" title="3. 规避方法"></a>3. 规避方法</h3><ul>
<li>检查引用的依赖</li>
<li>使用Proguard,移除没有使用的类、字段、方法和属性</li>
</ul>
<h3 id="4-配置"><a href="#4-配置" class="headerlink" title="4. 配置"></a>4. 配置</h3><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></pre></td><td class="code"><pre><div class="line">android {</div><div class="line"> defaultConfig {</div><div class="line"> multiDexEnabled true</div><div class="line"> }</div><div class="line">}</div><div class="line">dependencies {</div><div class="line"> implementation 'com.android.support:multidex:1.0.3' </div><div class="line">}</div></pre></td></tr></table></figure>
<p>引入MultiDexApplication</p>
<p>三种方法</p>
<ul>
<li>配置当前项目的清单文件</li>
</ul>
<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></pre></td><td class="code"><pre><div class="line"><application</div><div class="line"> android:name="android.support.multidex.MultiDexApplication"</div><div class="line"></application></div></pre></td></tr></table></figure>
<ul>
<li><p>当前的Application继承MultiDexApplication</p>
</li>
<li><p>在attachBaseContext方法中初始化MultiDex</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></pre></td><td class="code"><pre><div class="line">@Override protected void attachBaseContext(Context base) {</div><div class="line"> super.attachBaseContext(base);</div><div class="line"> MultiDex.install(this); </div><div class="line">}</div></pre></td></tr></table></figure>
</li>
</ul>
<h3 id="5-局限性"><a href="#5-局限性" class="headerlink" title="5. 局限性"></a>5. 局限性</h3><p>前面我们说过, MultiDex Support Library只是一个不得已而为之的方案,它本身并不是完美的,因此将它集成到项目中,需要经过完整的测试才能上线,可能会出现应用性能下降等问题, MultiDex Support Library的局限性如下。</p>
<ul>
<li><p>应用首次启动时 Dalvik虚拟机会对所有的.dex文件执行 dexopt操作,生成ODEX文件,这个过程很复杂且非常耗时,如果应用的从dex文件太大,可能会导致出现ANR。</p>
</li>
<li><p>在 Android4.0( API level14)之前的系统上,由于 Dalvik linearalloc的bug(见Isse225861),使用 Multidex的应用可能启动失败。如果你的应用还支持低于 API level14的系统版本时,那么在上线之前需要针在这些低版本系统经过严格充分的测试,否则用户可能会在启动你的APP时出现错误。理论上,使用 Proguard的压缩功能可以减少或者消除这些潜在的问题。当然,目前低于 Android4.0的系统使用量已经很少了,建议直接将应用的 minSdkversion设置为14,这样问题也就不存在了。</p>
</li>