-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
2017 lines (1991 loc) · 203 KB
/
Copy pathsearch.xml
File metadata and controls
2017 lines (1991 loc) · 203 KB
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>ADB 指令</title>
<url>/Blog/ADB%20%E6%8C%87%E4%BB%A4/</url>
<content><![CDATA[<h1 id="ADB-指令"><a href="#ADB-指令" class="headerlink" title="ADB 指令"></a>ADB 指令</h1><h4 id="安裝-APP"><a href="#安裝-APP" class="headerlink" title="安裝 APP"></a>安裝 APP</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">adb install "APK 檔案路徑"</span><br></pre></td></tr></table></figure>
<h4 id="移除-APP"><a href="#移除-APP" class="headerlink" title="移除 APP"></a>移除 APP</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">adb shell pm uninstall -k "應用包名"</span><br></pre></td></tr></table></figure>
<h4 id="查詢-APP-列出全部"><a href="#查詢-APP-列出全部" class="headerlink" title="查詢 APP 列出全部"></a>查詢 APP 列出全部</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">adb shell pm list packages</span><br></pre></td></tr></table></figure>
<h4 id="獲取-Mac-地址"><a href="#獲取-Mac-地址" class="headerlink" title="獲取 Mac 地址"></a>獲取 Mac 地址</h4><p>第一種:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">adb shell </span><br><span class="line"></span><br><span class="line">cd \sys\class\net\eth0 或者cd \sys\class\net\wlan0</span><br><span class="line"></span><br><span class="line">cat address</span><br></pre></td></tr></table></figure>
<p>第二種:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">adb shell ifconfig wlan0</span><br></pre></td></tr></table></figure>
<h4 id="清理-APP-數據與緩存"><a href="#清理-APP-數據與緩存" class="headerlink" title="清理 APP 數據與緩存"></a>清理 APP 數據與緩存</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">adb shell pm clear com.larzio.poc</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>ADB</category>
</categories>
<tags>
<tag>Android, ADB</tag>
</tags>
</entry>
<entry>
<title>Activity</title>
<url>/Blog/Activity/</url>
<content><![CDATA[<h1 id="Activity"><a href="#Activity" class="headerlink" title="Activity"></a>Activity</h1><h2 id="生命週期"><a href="#生命週期" class="headerlink" title="生命週期"></a>生命週期</h2><p><img src="https://i.imgur.com/WLneg5X.png" alt="image alt"></p>
<table>
<thead>
<tr>
<th>生命週期方法</th>
<th>調用時機</th>
</tr>
</thead>
<tbody><tr>
<td>OnCreate</td>
<td>在 Activity 物件被第一次創建時調用,及通常用來做程式的初始化動作。</td>
</tr>
<tr>
<td>OnStart</td>
<td>當 Activity 變得可見時調用該方法。</td>
</tr>
<tr>
<td>OnResume</td>
<td>當 Activity開始準備使用戶交互時調用該方法。</td>
</tr>
<tr>
<td>OnPause</td>
<td>系統即將啟動另外一個 Activity 時調用該方法。</td>
</tr>
<tr>
<td>OnStop</td>
<td>當前 Activity 變得不可見時調用該方法。</td>
</tr>
<tr>
<td>OnDestory</td>
<td>當前 Activity 被銷毀之前調用該方法。</td>
</tr>
<tr>
<td>OnRestart</td>
<td>當一個 Activity 再次啟動之前就會調用該方法。</td>
</tr>
</tbody></table>
<ol>
<li>Activity 的生命週期方法微系統自行調用,而非開發人用去控制,開發人員可於方法內填入所要執行的程序。</li>
<li>Android Application 遵循的動作流程:<ol>
<li>一般啟動<br><strong><code>onCreate</code>-><code>onStart</code>-><code>onResume</code></strong><br>啟動一個 Activity 的基本流程:分配資源給這個 Activity <code>OnCreate</code>,然後將 Activity 內容顯示到螢幕上<code> OnStart</code>,在一切就緒後,取得螢幕的控制權<code>OnResume</code>,使用者開始使用程式。</li>
<li>呼叫另一個 Activity<br> <strong><code>OnPause(1)</code>-><code>OnCreate(2)</code>-><code>OnStart(2)</code>-><code>OnResume(2)</code>-><code>OnStop(1)</code></strong><br> 先暫停原本 Activity 1,直到 Activity 2 完成一般啟動流程後,Activity 1 才會被停止。</li>
<li>回復原 Activity<br> <strong><code>OnPause(2)</code>-><code>OnRestart(1)</code>-><code>OnStart(1)</code>-><code>OnResume(1)</code>-><code>OnStop(2)</code>-><code>OnDestory(2)</code></strong><br> 按返回鍵可以回到原本 Activity。</li>
<li>退出 / 結束<br><strong><code>OnPause</code>-><code>OnStop</code>-><code>OnDestory</code></strong><br>如果程式中直接呼叫 <code>finish()</code> 方法來關閉 Activity 的話,系統會暫停 <code>onPause</code>後,停止<code>OnStop</code>,然後才銷毀<code>OnDestory</code></li>
<li>回收後再啟動<br> 被回收掉的 Activity 一旦又重新被呼叫時,會像一般啟動一樣再次呼叫 Activity 的<code>OnCreate</code>方法</li>
</ol>
</li>
</ol>
<h2 id="啟動模式"><a href="#啟動模式" class="headerlink" title="啟動模式"></a>啟動模式</h2><table>
<thead>
<tr>
<th align="center">LaunchMode</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody><tr>
<td align="center">standard</td>
<td align="center">Android 預設的啟動模式 ; Activity stack 一直堆疊上去。</td>
</tr>
<tr>
<td align="center">singleTop</td>
<td align="center">如果 Activity 的實例已存在於當前任務的頂部,則系統通過調用其 onNewsIntent()方法</td>
</tr>
<tr>
<td align="center">singleTask</td>
<td align="center">若已存在於任務棧中,則會將其以上的 Activity 銷毀並且掉傭其 onNewIntent() 方法</td>
</tr>
<tr>
<td align="center">singleInstance</td>
<td align="center">脫離當前的任務棧,另開一個任務棧</td>
</tr>
</tbody></table>
<p><br><br><br></p>
<table>
<thead>
<tr>
<th align="center">使用Intent标志</th>
<th align="center">说明</th>
</tr>
</thead>
<tbody><tr>
<td align="center">FLAG_ACTIVITY_NEW_TASK</td>
<td align="center">同singleTask</td>
</tr>
<tr>
<td align="center">FLAG_ACTIVITY_SINGLE_TOP</td>
<td align="center">同singleTop</td>
</tr>
<tr>
<td align="center">FLAG_ACTIVITY_CLEAR_TOP</td>
<td align="center">如果正在啟動的 Activity 已在當前task中運行,則不會啟動該 Activity 的新實例,而是銷毀其上的 Activity,並調用其 onNewIntent()方法</td>
</tr>
</tbody></table>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>Android 內存洩漏注意</title>
<url>/Blog/Android%20%E5%85%A7%E5%AD%98%E6%B4%A9%E6%BC%8F%E6%B3%A8%E6%84%8F/</url>
<content><![CDATA[<h1 id="Android-內存洩漏注意"><a href="#Android-內存洩漏注意" class="headerlink" title="Android 內存洩漏注意"></a>Android 內存洩漏注意</h1><p>Activity 使用的匿名內部類 OnClickListener 並不會造成內存洩漏,因為當前的介面被銷毀,View也被銷毀。</p>
<p>Dialog clickEvent 也是使用 OnClickListener 但是內部卻是通過 Message 傳遞事件。</p>
<p>如果當前頁面退出,而 Messagequeue 正在阻塞則會造成內存洩漏</p>
<p>內部類隱性持有外部類的引用,請勿使內部類持有比外部類生命週期還要長的對象。</p>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>Android P 以上網路傳輸時出現:Cleartext HTTP traffic to xxx not permitted</title>
<url>/Blog/Android%20P%20%E4%BB%A5%E4%B8%8A%E7%B6%B2%E8%B7%AF%E5%82%B3%E8%BC%B8%E6%99%82%E5%87%BA%E7%8F%BE%EF%BC%9ACleartext%20HTTP%20traffic%20to%20xxx%20not%20permitted/</url>
<content><![CDATA[<p>Google 針對 Android P 的應用程序,將要求默認使用加密連接。</p>
<p>因此若 Android P 使用 HttpUrlConnection 進行 Http 請求將會出現以下異常:<br><code> W/System.err: java.io.IOException: Cleartext HTTP traffic to **** not permitted</code></p>
<p>針對此問題,有三種解決方式:</p>
<ol>
<li>App 改用 Https 請求</li>
<li>targetSdkVersion 降到27以下</li>
<li>更改網路安全配置</li>
</ol>
<p>這裡主要講解第三種解決方式,更改網路安全配置。</p>
<h3 id="第一步:"><a href="#第一步:" class="headerlink" title="第一步:"></a>第一步:</h3><p>在 res/xml 底下創建一個 nextwork_security_config.xml 檔案。內容如下:</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">base-config</span> <span class="attr">cleartextTrafficPermitted</span>=<span class="string">"true"</span> /></span></span><br></pre></td></tr></table></figure>
<h3 id="第二步:"><a href="#第二步:" class="headerlink" title="第二步:"></a>第二步:</h3><p>於 AndroidManifest.xml 檔案中更改為如下內容:</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">mainfest</span>></span></span><br><span class="line"><span class="comment"><!--略--></span></span><br><span class="line"><application</span><br><span class="line"></span><br><span class="line">android:networkSecurityConfig="@xml/network_security_config">></span><br><span class="line"></span><br><span class="line"><span class="comment"><!--略--></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">application</span>></span></span><br><span class="line"><span class="tag"></<span class="name">mainfest</span>></span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>Android 內存管理機制</title>
<url>/Blog/Android%20%E5%85%A7%E5%AD%98%E7%AE%A1%E7%90%86%E6%A9%9F%E5%88%B6/</url>
<content><![CDATA[<h2 id="一、Java對象生命週期"><a href="#一、Java對象生命週期" class="headerlink" title="一、Java對象生命週期"></a>一、Java對象生命週期</h2><p>Java代碼編譯後生成的字節碼.class文件從文件系統中加載到虛擬機之後,便有了JVM上的Java對象,Java對象在JVM上運行有7個階段,如下:</p>
<ul>
<li>Created(創建)</li>
<li>InUse(應用)</li>
<li>Invisible(不可見)</li>
<li>Unreachable(不可達)</li>
<li>Collected(收集)</li>
<li>Finalized(終結)</li>
<li>Deallocated(對象空間重新分配)</li>
</ul>
<h3 id="1、Created(創建)"><a href="#1、Created(創建)" class="headerlink" title="1、Created(創建)"></a>1、Created(創建)</h3><ol>
<li>Class 對象首次加載的時候進行一次,有關靜態初始化的所有動作從超類到子類會依序執行。</li>
<li>在堆上為對象分配足夠的存儲空間。</li>
<li>存儲空間會被清空,也就是說對象中的所有基本類型數據都為空</li>
<li>從超類到子類依序初始化成員變量。</li>
<li>從超類到子類依序執行構造方法。</li>
</ol>
<h3 id="2、InUse(應用)"><a href="#2、InUse(應用)" class="headerlink" title="2、InUse(應用)"></a>2、InUse(應用)</h3><p>該對象至少被一個強引用持有。</p>
<h3 id="3、Invisible(不可見)"><a href="#3、Invisible(不可見)" class="headerlink" title="3、Invisible(不可見)"></a>3、Invisible(不可見)</h3><p>程序的執行已經超過該對象的作用域。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">boolean</span> bool = <span class="keyword">false</span>;</span><br><span class="line"><span class="keyword">if</span> (bool == <span class="keyword">true</span>){</span><br><span class="line"> <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"> count ++;</span><br><span class="line">}</span><br><span class="line">System.out.println(count);<span class="comment">// 報錯,count 不可見</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="4、Unreachable(不可達)"><a href="#4、Unreachable(不可達)" class="headerlink" title="4、Unreachable(不可達)"></a>4、Unreachable(不可達)</h3><p>該對象不被任何強引用持有。</p>
<h3 id="5、Collected(收集)"><a href="#5、Collected(收集)" class="headerlink" title="5、Collected(收集)"></a>5、Collected(收集)</h3><p>當 GC 已經對該對象的內存空間重新分配做好準備時,對象進入收集階段,如果該對象重寫了<code>finalize()</code>方法,則執行它。</p>
<p><strong>千萬不要重寫<code>finalize()</code>方法</strong></p>
<ul>
<li>影響JVM的對象分配與回收速度<br> 至少垃圾回收器對該對象運行兩次GC</li>
<li>可能造成該對象的再次復活<br> 在<code>finalize()</code>方法中,假設有其他強引用再次持有該對象,則導致對象的狀態變化。破壞了Java對象的生命週期進程。</li>
</ul>
<h3 id="6、Finalized(終結)"><a href="#6、Finalized(終結)" class="headerlink" title="6、Finalized(終結)"></a>6、Finalized(終結)</h3><p>等待垃圾回收器回收該對象空間。</p>
<h3 id="7、Deallocated(對象空間重新分配)"><a href="#7、Deallocated(對象空間重新分配)" class="headerlink" title="7、Deallocated(對象空間重新分配)"></a>7、Deallocated(對象空間重新分配)</h3><p>GC對該對象所佔用的內存空間進行回收或者在分配,該對象徹底消失。</p>
<h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h3><ul>
<li>不需要使用該對象時,將之設為空。</li>
</ul>
<h2 id="二、內存分配"><a href="#二、內存分配" class="headerlink" title="二、內存分配"></a>二、內存分配</h2><p>在Android系統中,<strong>堆</strong>實際上就是一塊<strong>匿名共享內存</strong>。</p>
<p>Android虛擬機把它封裝成一個mSpace,由底層C庫來管理,並且仍然使用libc提供的函數malloc和free來分配和釋放內存。</p>
<blockquote>
<p>應用程序的內存分配及垃圾回收都是由<code>Android虛擬機</code>完成的。</p>
</blockquote>
<table>
<thead>
<tr>
<th align="center">Android 版本</th>
<th align="center">虛擬機</th>
</tr>
</thead>
<tbody><tr>
<td align="center">Android 5.0 下</td>
<td align="center">Dalvik 虛擬機</td>
</tr>
<tr>
<td align="center">Android 5.0及以上</td>
<td align="center">ART 虛擬機</td>
</tr>
</tbody></table>
<h3 id="Dalivik"><a href="#Dalivik" class="headerlink" title="Dalivik"></a>Dalivik</h3><ul>
<li>Linear Alloc</li>
<li>Zygote Space</li>
<li>Alloc Space</li>
</ul>
<h3 id="ART"><a href="#ART" class="headerlink" title="ART"></a>ART</h3><ul>
<li>Non Moving Space</li>
<li>Zygote Space</li>
<li>Alloc Space</li>
<li>Image Space</li>
<li>Large Obj Space</li>
</ul>
<p>Dalivik的 Linear Alloc 與 ART的 Non Moving Space相似。皆是一個只讀區域,主要存儲虛擬機中的纇,因為纇加載後只需要只讀的屬性,並且不會改變它。</p>
<p>Zygote Space:在Zygote進程和應用程序進程之間共享。</p>
<p>Allocaton Space:每個進程獨佔。</p>
<p>Image Space:存放一些預加載類。與Zygote Space一樣,在Zygote進程和應用程序進程之間共享。</p>
<p>Large Object Space:離散地址的集合,分配一些大對象。</p>
<h2 id="三、內存回收機制"><a href="#三、內存回收機制" class="headerlink" title="三、內存回收機制"></a>三、內存回收機制</h2><p>內存分為三個區域:</p>
<ul>
<li>Young Generation(年輕代)</li>
<li>Old Generation(年老代)</li>
<li>Permanent Generation(持久代)</li>
</ul>
<p><img src="https://i.imgur.com/77oha2V.png"></p>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android, Java</tag>
</tags>
</entry>
<entry>
<title>Android 定位</title>
<url>/Blog/Android%20%E5%AE%9A%E4%BD%8D/</url>
<content><![CDATA[<h1 id="Android-定位"><a href="#Android-定位" class="headerlink" title="Android 定位"></a>Android 定位</h1><h4 id="檢測系統定位服務是否開啟"><a href="#檢測系統定位服務是否開啟" class="headerlink" title="檢測系統定位服務是否開啟"></a>檢測系統定位服務是否開啟</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">isSystemLocationEnable</span><span class="params">()</span> </span>{</span><br><span class="line"> LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);</span><br><span class="line"> <span class="keyword">boolean</span> gpsLocationEnable = manager.isProviderEnabled(LocationManager.GPS_PROVIDER);</span><br><span class="line"> <span class="keyword">boolean</span> networkLocationEnable = manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);</span><br><span class="line"> <span class="keyword">return</span> gpsLocationEnable && networkLocationEnable;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h4 id="跳轉至系統設置中定位介面"><a href="#跳轉至系統設置中定位介面" class="headerlink" title="跳轉至系統設置中定位介面"></a>跳轉至系統設置中定位介面</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Intent intent = <span class="keyword">new</span> Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);</span><br><span class="line">startActivity(intent);</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android, Java, Location</tag>
</tags>
</entry>
<entry>
<title>Android 緩存淺談 (LruCache)</title>
<url>/Blog/Android%20%E7%B7%A9%E5%AD%98%E6%B7%BA%E8%AB%87%20(LruCache)/</url>
<content><![CDATA[<h4 id="Android-可以通過緩存減少頻繁的網路操作,減少流量、提升性能。"><a href="#Android-可以通過緩存減少頻繁的網路操作,減少流量、提升性能。" class="headerlink" title="Android 可以通過緩存減少頻繁的網路操作,減少流量、提升性能。"></a><strong>Android 可以通過緩存減少頻繁的網路操作,減少流量、提升性能。</strong></h4><p>三級緩存流程如下:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">flowchat</span><br><span class="line"></span><br><span class="line">st=>start: 加載圖片</span><br><span class="line">e=>end: 加載完成</span><br><span class="line">op_1=>operation: 判斷手機內存是否有該圖片?</span><br><span class="line">cond_1=>condition: 有或無?</span><br><span class="line">op_2=>operation: 從內存中取出圖片</span><br><span class="line">op_3=>operation: 判斷手機 SD 卡或外部儲存是否有該圖片?</span><br><span class="line">cond_2=>condition: 有或無?</span><br><span class="line">op_4=>operation: 從手機 SD 卡或外部儲存中取出</span><br><span class="line"></span><br><span class="line">op_5=>operation: 網路下載該圖片</span><br><span class="line"></span><br><span class="line">st->op_1->cond_1</span><br><span class="line">cond_1(yes,right)->op_2->e</span><br><span class="line">cond_1(no)->op_3->cond_2</span><br><span class="line">cond_2(yes,right)->op_4->e</span><br><span class="line">cond_2(no)->op_5->e</span><br></pre></td></tr></table></figure>
<p>三級緩存流程,首先從內存中加載該圖片,因為從內存獲取圖片速度最快,但是內存空間有限,所以從內存緩存使用<code>LruCache</code>,外部緩存即為硬碟緩存,相比內存緩存的速度慢很多,但可儲存空間大,硬碟緩存使用<code>DiskLruCache</code>。</p>
<blockquote>
<p><code>Android</code> 緩存機制主要是基於 <code>JAVA</code> 的緩存機制,<code>JAVA</code> 緩存機制有四種,強引用、軟引用、弱引用、虛引用,<br>著重看軟引用和弱引用。<br>可參考:<a href="https://blog.csdn.net/weixin_43821974/article/details/84893833">強引用、軟引用、弱引用、虛引用</a></p>
</blockquote>
<h4 id="Andorid-2-3版本後,Google-不建議使用軟引用與弱引用!,而是使用強引用"><a href="#Andorid-2-3版本後,Google-不建議使用軟引用與弱引用!,而是使用強引用" class="headerlink" title="Andorid 2.3版本後,Google 不建議使用軟引用與弱引用!,而是使用強引用"></a><strong>Andorid 2.3版本後,Google 不建議使用軟引用與弱引用!,而是使用強引用</strong></h4><p>Google 官網描述如下:</p>
<pre><code> Note: 在過去,一種比較流行的內存緩存實現方法是使用軟引用(SoftReference)或弱引用(WeakReference)對Bitmap進行緩存,
然而我們並不推薦這樣的做法。從Android 2.3 (API Level 9)開始,垃圾回收機制變得更加頻繁,這使得釋放軟(弱)引用的頻率也隨之增高,
導致使用引用的效率降低很多。而且在Android 3.0 (API Level 11)之前,備份的Bitmap會存放在Native Memory中,
它不是以可預知的方式被釋放的,這樣可能導致程序超出它的內存限製而崩潰。
內存緩存以花費寶貴的程序內存為前提來快速訪問位圖。 LruCache類(在API Level 4的Support Library中也可以找到)特別適合用來緩存Bitmaps,
它使用一個強引用(strong referenced)的LinkedHashMap保存最近引用的對象,
並且在緩存超出設置大小的時候剔除(evict)最近最少使用到的對象。
</code></pre>
<h4 id="一、LurCache介紹"><a href="#一、LurCache介紹" class="headerlink" title="一、LurCache介紹"></a>一、LurCache介紹</h4><ol>
<li>LRU (全稱:Least Recently Used)<br>即最少使用算法, 將最近沒有使用的數據從緩存中移除。(全稱:Least Recently Used),即最少使用算法, 將最近沒有使用的數據從緩存中移除。</li>
<li>LurCache<br>算法原理把最近使用的對象用強引用存儲在 <code>LinkedHashMap</code>,並且把最近最少使用的對象在緩存大小達到閥值將它從內存中移除。<h4 id="二、使用"><a href="#二、使用" class="headerlink" title="二、使用"></a>二、使用</h4></li>
</ol>
<p>實現 LurCache 緩存的步驟:</p>
<ol>
<li>先設置緩存的內存大小,預設為手機內存的 1/8 。<br> 手機內存獲取方式: <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">int</span> maxMemonry = (<span class="keyword">int</span>) (Runtime.getRuntime() .maxMemory() / <span class="number">1024</span>);</span><br></pre></td></tr></table></figure></li>
<li>重寫 <code>sizeOf</code>的方法,返回對象數量。</li>
</ol>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>AndroidManifest.xml 簡介</title>
<url>/Blog/AndroidManifest.xml%20%E7%B0%A1%E4%BB%8B/</url>
<content><![CDATA[<h1 id="AndroidManifest-xml-簡介"><a href="#AndroidManifest-xml-簡介" class="headerlink" title="AndroidManifest.xml 簡介"></a>AndroidManifest.xml 簡介</h1><p>Android 應用程序中最重要的文件之一。</p>
<ul>
<li><p>為應用程序定義包名。包名被視為唯一辨識碼。</p>
</li>
<li><p>描述應用程序的元件。如 Activity、Service、BroadcastReceiver、ContentProvider。</p>
</li>
<li><p>宣示此應用需要哪些權限。</p>
<h2 id="檔案結構"><a href="#檔案結構" class="headerlink" title="檔案結構"></a>檔案結構</h2><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"> <span class="meta"><?xml version="1.0" encoding="utf-8"?></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">manifest</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">uses-permission</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">permission</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">permission-tree</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">permission-group</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">instrumentation</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">uses-sdk</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">uses-configuration</span> /></span> </span><br><span class="line"> <span class="tag"><<span class="name">uses-feature</span> /></span> </span><br><span class="line"> <span class="tag"><<span class="name">supports-screens</span> /></span> </span><br><span class="line"> <span class="tag"><<span class="name">compatible-screens</span> /></span> </span><br><span class="line"> <span class="tag"><<span class="name">supports-gl-texture</span> /></span> </span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">application</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">activity</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">action</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">category</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">data</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta-data</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">activity</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">activity-alias</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">intent-filter</span>></span> . . . <span class="tag"></<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta-data</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">activity-alias</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">service</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">intent-filter</span>></span> . . . <span class="tag"></<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta-data</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">service</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">receiver</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">intent-filter</span>></span> . . . <span class="tag"></<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta-data</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">receiver</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">provider</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">grant-uri-permission</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">meta-data</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">path-permission</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">provider</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">uses-library</span> /></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"></<span class="name">application</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">manifest</span>></span></span><br><span class="line"> </span><br></pre></td></tr></table></figure>
<p>下方按字母順序列出可出現在宣示說明檔案中的所有元素。 只有這些才是符合資格的元素,您無法新增自己的元素或屬性。</p>
<p><img src="https://i.imgur.com/hzjfAnM.png"></p>
</li>
</ul>
<p><strong>元素</strong></p>
<ol>
<li><code><manifest></code>和<code>application</code>是必要的元素,務必顯示這兩者且只出現一次,其他大多的元素都是可選的且可任意排序。</li>
<li><code><actiivty-alias></code>需排在<code><activity></code>後方。</li>
</ol>
<p><strong>屬性</strong></p>
<ol>
<li>必須為元素指定某些屬性,才能達到其目的。</li>
<li>大多的屬性均為選用性質,若未被指定則使用其預設值或狀態。</li>
</ol>
<p><strong>宣告類別名稱</strong></p>
<p>許多元素會對應到 Java 物件,包括應用程序本身的元素(<code><appliceation></code>)與其主要元件:Activity(<code><activity></code>)、Service(<code><service></code>)、BroadcastReceiver(<code><receiver></code>)以及(<code><provider></code>)。</p>
<p>如果您一如往常定義元件類別 (<code>Activity</code>、<code>Service</code>、 <code>BroadcastReceiver</code> 及 <code>ContentProvider</code>),通過<code>name</code>屬性宣告子類別。如下</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">manifest</span> <span class="attr">.</span> <span class="attr">.</span> <span class="attr">.</span> ></span></span><br><span class="line"> <span class="tag"><<span class="name">application</span> <span class="attr">.</span> <span class="attr">.</span> <span class="attr">.</span> ></span></span><br><span class="line"> <span class="tag"><<span class="name">service</span> <span class="attr">android:name</span>=<span class="string">"com.example.project.SecretService"</span> <span class="attr">.</span> <span class="attr">.</span> <span class="attr">.</span> ></span></span><br><span class="line"> . . .</span><br><span class="line"> <span class="tag"></<span class="name">service</span>></span></span><br><span class="line"> . . .</span><br><span class="line"> <span class="tag"></<span class="name">application</span>></span></span><br><span class="line"><span class="tag"></<span class="name">manifest</span>></span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>or</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">manifest</span> <span class="attr">package</span>=<span class="string">"com.example.project"</span> <span class="attr">.</span> <span class="attr">.</span> <span class="attr">.</span> ></span></span><br><span class="line"> <span class="tag"><<span class="name">application</span> <span class="attr">.</span> <span class="attr">.</span> <span class="attr">.</span> ></span></span><br><span class="line"> <span class="tag"><<span class="name">service</span> <span class="attr">android:name</span>=<span class="string">".SecretService"</span> <span class="attr">.</span> <span class="attr">.</span> <span class="attr">.</span> ></span></span><br><span class="line"> . . .</span><br><span class="line"> <span class="tag"></<span class="name">service</span>></span></span><br><span class="line"> . . .</span><br><span class="line"> <span class="tag"></<span class="name">application</span>></span></span><br><span class="line"><span class="tag"></<span class="name">manifest</span>></span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p><strong>多個值</strong></p>
<p>如果可以指定多個值,該元素幾乎會一直重複,而不是在單一元素內列出多個值。 例如,<code>Intent-filter</code>能列出數種動作:</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">intent-filter</span> <span class="attr">.</span> <span class="attr">.</span> <span class="attr">.</span> ></span></span><br><span class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">"android.intent.action.EDIT"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">"android.intent.action.INSERT"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">"android.intent.action.DELETE"</span> /></span></span><br><span class="line"> . . .</span><br><span class="line"><span class="tag"></<span class="name">intent-filter</span>></span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="檔案功能"><a href="#檔案功能" class="headerlink" title="檔案功能"></a>檔案功能</h2><p><strong>Intent-filter</strong></p>
<p>應用程式的核心元件(即應用程式的 Activity、Service、BroadcastReceiver)是由<code>Intent</code>啟動。</p>
<p><code>Intent</code>用於說明要採取的動作 - 包括執行依據的資料、應執行動作的元件類別,以及其他相關的指示。</p>
<p>例如,包含 “android.intent.action.MAIN” 與 “android.intent.category.LAUNCHER” 設定的篩選器會將某 Activity 宣告為啟動應用程式的 Activity,也就是應顯示在應用程式啟動器中的 Activity。</p>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>Android 需要了解的知識點</title>
<url>/Blog/Android%20%E9%9C%80%E8%A6%81%E4%BA%86%E8%A7%A3%E7%9A%84%E7%9F%A5%E8%AD%98%E9%BB%9E/</url>
<content><![CDATA[<h2 id="JVM"><a href="#JVM" class="headerlink" title="JVM"></a>JVM</h2><ol>
<li>Java 內存區域</li>
<li>堆棧區別</li>
<li>哪些區域線程私有?那些共享?</li>
<li>垃圾回收算法</li>
<li>Android 與 Java 虛擬機的差異?</li>
</ol>
<h2 id="Java"><a href="#Java" class="headerlink" title="Java"></a>Java</h2><ol>
<li>volatile (只保證了可見性和有序性,不能保證原子性)</li>
<li>synchronized:修飾代碼塊/方法/對象的區別?</li>
<li>lock,有哪幾種鎖?</li>
<li>線程同步方式?</li>
<li>死鎖是什麼?</li>
<li>泛型中類型擦除?</li>
<li>淺拷貝、深拷貝差異?如何實現?</li>
</ol>
<h2 id="源碼"><a href="#源碼" class="headerlink" title="源碼"></a>源碼</h2><ol>
<li>Handler 消息機制</li>
<li>HashMap</li>
<li>ArrayMap</li>
<li>ArrayList、LinkedList 用法有什麼要注意的?</li>
<li>OkHttp 了解?使用注意事項?</li>
<li>RxJava 介紹?</li>
<li>Retrofit?</li>
<li>EventBus</li>
<li>Glide</li>
<li>Gson</li>
</ol>
<h2 id="Android"><a href="#Android" class="headerlink" title="Android"></a>Android</h2><ol>
<li>Activity 生命週期</li>
<li>ANR </li>
<li>事件分發機制</li>
<li>View 繪製流程?View的顯示過程?</li>
<li>四大組件(Activity、Service、ContentProvide、Broadcast)</li>
<li>Fragment是什麼? 與Activity 的差別是什麼?</li>
<li>SurfaceView原理? 與 View 的差別是什麼?</li>
<li>前台服務與後台服務區別?</li>
<li>AIDL是什麼?</li>
<li>IPC方式?誰最快?</li>
<li>Activity 四種啟動模式?</li>
<li>怎麼退出所有 Activity?</li>
<li>Protocol Buffer 了解嗎?</li>
<li>APP中多進程有什麼用?</li>
<li>方法數65536怎麼解決</li>
<li>Android 存儲(文件、SP、數據庫</li>
<li>Service 兩種啟動方式?區別?</li>
<li>ThreadLocal 是什麼?</li>
<li></li>
</ol>
<h2 id="HTTP-協議"><a href="#HTTP-協議" class="headerlink" title="HTTP 協議"></a>HTTP 協議</h2><ol>
<li>HTTP 緩存</li>
<li>什麼是 HTTP?</li>
<li>HTTP/HTTPS的區別?</li>
<li>TCP/IP 三次握手 四次揮手?</li>
<li>TCP/UDP 的區別?</li>
<li>HTTP 狀態碼?</li>
<li>對稱/非對稱加密?</li>
</ol>
<h2 id="Project"><a href="#Project" class="headerlink" title="Project"></a>Project</h2><ol>
<li>IM模組如何實現?</li>
<li>登入模組如何實現?</li>
<li>如何避免內存洩漏?如何優化?</li>
</ol>
<h2 id="Design-Pattern"><a href="#Design-Pattern" class="headerlink" title="Design Pattern"></a>Design Pattern</h2><ol>
<li>生產者、消費者是什麼?</li>
<li>命令模式是什麼?</li>
<li>單例模式</li>
<li>觀察者</li>
<li>建造者</li>
</ol>
<h2 id="數據結構"><a href="#數據結構" class="headerlink" title="數據結構"></a>數據結構</h2><ol>
<li>七大排序分別是什麼?</li>
<li>二叉樹原理?</li>
<li>紅黑樹是什麼?</li>
</ol>
<h2 id="計算機網路"><a href="#計算機網路" class="headerlink" title="計算機網路"></a>計算機網路</h2><ol>
<li>網路有哪幾層?分別對應什麼協議?</li>
<li>IP TCP 傳輸的都是什麼數據?</li>
<li>DNS?</li>
</ol>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>FIFO/LRU/LFUS三種緩存算法</title>
<url>/Blog/FIFO_LRU_LFUS%E4%B8%89%E7%A8%AE%E7%B7%A9%E5%AD%98%E7%AE%97%E6%B3%95/</url>
<content><![CDATA[<h1 id="FIFO-LRU-LFUS三種緩存算法"><a href="#FIFO-LRU-LFUS三種緩存算法" class="headerlink" title="FIFO/LRU/LFUS三種緩存算法"></a>FIFO/LRU/LFUS三種緩存算法</h1><h3 id="FIFO"><a href="#FIFO" class="headerlink" title="FIFO"></a>FIFO</h3><blockquote>
<p>First in First out,先進先出,如果緩存容量滿,則優先移出最早加入緩存的數據;內部可使用隊列實現。</p>
</blockquote>
<h3 id="LRU"><a href="#LRU" class="headerlink" title="LRU"></a>LRU</h3><blockquote>
<p>Least recently used,最近最少使用,目前最常用的緩存算法和設計方案之一,如果緩存容量滿,優先移除最近最久未使用的數據,適用場景廣泛。</p>
</blockquote>
<h3 id="LFU"><a href="#LFU" class="headerlink" title="LFU"></a>LFU</h3><blockquote>
<p>Least Frequently used,最近最不常用,如果緩存容量滿,移除訪問次數最少的數據,若訪問次數相同數據有多個,則移除最久訪問的數據。</p>
</blockquote>
]]></content>
<categories>
<category>Algorithm</category>
</categories>
<tags>
<tag>Algorithm</tag>
</tags>
</entry>
<entry>
<title>Android開發,分析 finish() 和 onBackPressed() 的區別</title>
<url>/Blog/Android%E9%96%8B%E7%99%BC%EF%BC%8C%E5%88%86%E6%9E%90%20finish()%20%E5%92%8C%20onBackPressed()%20%E7%9A%84%E5%8D%80%E5%88%A5/</url>
<content><![CDATA[<ol>
<li><code>finish()</code>,最常用來關閉 Actiivty 的方法。</li>
<li><code>onBackPressed()</code>,Android 點擊返回按鍵的方法。</li>
</ol>
<ul>
<li>一般來說這兩個方法作用是一致的。</li>
<li>但使用 <code>finish()</code>,將無法實現返回上一層的共享變換,必須使用<code>onBackPressed()</code>才能實現。</li>
</ul>
<h3 id="finish"><a href="#finish" class="headerlink" title="finish()"></a>finish()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">finish</span><span class="params">()</span> </span>{</span><br><span class="line"> finish(DONT_FINISH_TASK_WITH_ACTIVITY);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/** <span class="doctag">@hide</span> Task isn't finished when activity is finished */</span></span><br><span class="line"> <span class="comment">// 關閉 Activity 但不關閉棧</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> DONT_FINISH_TASK_WITH_ACTIVITY = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@hide</span> Task is finished if the finishing activity is the root of the task. To preserve the</span></span><br><span class="line"><span class="comment"> * past behavior the task is also removed from recents.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="comment">// 如果當前 Activity 處於棧底,則關閉 Activity 同時關閉棧</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> FINISH_TASK_WITH_ROOT_ACTIVITY = <span class="number">1</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@hide</span> Task is finished along with the finishing activity, but it is not removed from</span></span><br><span class="line"><span class="comment"> * recents.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="comment">// 關閉 Activity 同時關閉棧</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> FINISH_TASK_WITH_ACTIVITY = <span class="number">2</span>;</span><br></pre></td></tr></table></figure>
<p>方法一共有三種。</p>
<h3 id="onBackPressed"><a href="#onBackPressed" class="headerlink" title="onBackPressed()"></a>onBackPressed()</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onBackPressed</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (mActionBar != <span class="keyword">null</span> && mActionBar.collapseActionView()) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (!mFragments.getFragmentManager().popBackStackImmediate()) {</span><br><span class="line"> finishAfterTransition();</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p><code>onBackPressed()</code>方法,先判斷是否有彈出的窗口,<code>PopWindow</code> or <code>Dialog</code> or <code>NavigationView</code>…等,如果有先關閉這些,如果沒有再來進行關閉的操作。</p>
<p><code>finishAfterTransition()</code>執行變換動畫後再進行 <code>finish()</code></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">finishAfterTransition</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!mActivityTransitionState.startExitBackTransition(<span class="keyword">this</span>)) {</span><br><span class="line"> finish();</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<hr>
<h3 id="總結"><a href="#總結" class="headerlink" title="總結"></a>總結</h3><p>一共存在以下三種情況:</p>
<ol>
<li>沒有<code>PopWindow</code> or <code>Dialog</code> or <code>NavigationView</code>or 共享變換,<code>finish()</code>與<code>onBackPressed()</code>是完全一樣的。</li>
<li>存在<code>PopWindow</code> or <code>Dialog</code> or <code>NavigationView</code>,<code>onBackPressed()</code>會先關閉它。</li>
<li>存在共享變換,<code>finish()</code>將不執行動畫直接關閉 Activity,<code>onBackPressed()</code>執行動畫完才關閉 Activity。 </li>
</ol>
<hr>
<h3 id="參考文獻"><a href="#參考文獻" class="headerlink" title="參考文獻"></a>參考文獻</h3><p><a href="https://blog.csdn.net/Stanny_Bing/article/details/78563029">Android开发,源码分析finish()和onBackPressed()的区别 - Stanny_Bing的博客 - CSDN博客</a></p>
<!--stackedit_data:
eyJoaXN0b3J5IjpbLTEyMDg1ODAxMjldfQ==
-->]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>Command Line 基本指令與操作</title>
<url>/Blog/Command%20Line%20%E5%9F%BA%E6%9C%AC%E6%8C%87%E4%BB%A4%E8%88%87%E6%93%8D%E4%BD%9C/</url>
<content><![CDATA[<h1 id="Command-Line-基本指令與操作"><a href="#Command-Line-基本指令與操作" class="headerlink" title="Command Line 基本指令與操作"></a>Command Line 基本指令與操作</h1><p><strong>基本理解</strong></p>
<p>命令行(command line)是一個純文字的應用程式,被稱為命令列介面(Command Line Interface,CLI)。一般都是使用圖形化介面(Graphical User Interface,GUI)操作電腦。</p>
<h2 id="指令-Command"><a href="#指令-Command" class="headerlink" title="指令(Command)"></a>指令(Command)</h2><p><strong>1.基本指令</strong></p>
<p><code>whoami</code>(Who am I)</p>
<p>作業系統中用於檢視目前有效用戶名稱的命令。</p>
<p><code>ls</code>(list)</p>
<p>列出所有檔案和路徑</p>
<p>可用參數:</p>
<ul>
<li>列出隱藏的目錄:<code>ls -a</code></li>
<li>列出詳細資料:<code>ls -l</code></li>
<li>包上述兩個:<code>ls -la</code></li>
<li>列出 .js 的檔案:<code>ls *.js</code></li>
</ul>
<p><code>cd</code>(change directory)</p>
<p>切換目錄</p>
<p>可用參數:</p>
<ul>
<li>回到 home 目錄:<code>cd ~</code># 屬於使用者底下的資料夾</li>
<li>回到根目錄:<code>cd /</code># 電腦最底層</li>
<li>回到上一層資料夾:<code>cd ..</code></li>
</ul>
<blockquote>
<p>小訣竅:當輸入 cd 空格 時,按<code>tab</code>會幫你列出底下的資料夾列表。</p>
</blockquote>
<p><code>pwd</code></p>
<p>取得目前所在的位置。</p>
<p><code>clear</code></p>
<p>清空 Terminal 面板。</p>
<p><code>exit</code></p>
<p>關閉 Termina。</p>
<p><strong>2.檔案操作指令</strong></p>
<p><code>mkdir</code>(make directory)</p>
<p>新建資料夾。</p>
<p><code>rm</code>(remove)</p>
<p>刪除檔案,並不會進到垃圾桶中,因此使用時要小心。</p>
<p>可用參數:</p>
<ul>
<li><code>rmdir (remove directory)</code>:刪除空資料夾,若資料夾內有檔案就無法刪除。</li>
<li><code>rm -rf</code>:刪除整個檔案或資料夾。</li>
</ul>
<blockquote>
<p>小訣竅:當刪除的檔名帶有空格或特殊字元時,可使用單引號將檔名括起來,例:<code>rm '要 刪 除 的 檔 名'</code></p>
</blockquote>
<p><code>mv</code>(move)</p>
<p>移動檔案:<code>mv file folder</code><br>更改檔名:<code>mv originalFile newFile</code></p>
<p><code>touch</code></p>
<p>碰一下檔案</p>
<p>情況一:假設檔案不存在,就會建立一個新的檔案。<br>情況二:假設檔案存在,更改檔案的修改時間。</p>
<p><code>cp</code>(copy)</p>
<p>複製檔案</p>
<p>可用參數:</p>
<ul>
<li><code>cp -r folder folder_copy</code></li>
</ul>
<p><code>echo</code></p>
<p>作用一:印出字串在 Termainal 面板。<br>作用二:印出字串在檔案中。</p>
<p><code>cat</code>(catenate)</p>
<p>將檔案內容顯示在 Terminal 面板。</p>
<p><code>less</code></p>
<p>將檔案內容以分頁顯示在 Terminal 面板。</p>
<p><code>curl</code></p>
<p>送出 request</p>
<p>可用參數:</p>
<ul>
<li><code>curl -I target-url</code>:擷取 request header</li>
</ul>
<p><strong>3.其他指令</strong></p>
<p><code>man</code>(manual)</p>
<p>查看指令用法說明書。#windows 沒有</p>
<p><code>date</code></p>
<p>印出現在時間</p>
<p><code>top</code>(table of processes)</p>
<p>印出所有 processes。可以顯示即時的系統負載狀態。</p>
<p><code>vim</code></p>
<p>進入 vim 編輯器,分為普通模式跟編輯模式。</p>
<p>對應的 key:</p>
<ul>
<li><code>i</code>:進入編輯模式</li>
<li><code>esc</code>:進入普通模式</li>
<li><code>:q</code>:退出</li>
<li><code>:wq</code>:存檔退出</li>
<li><code>:q!</code>:不存檔直接退出</li>
</ul>
]]></content>
<categories>
<category>Command</category>
</categories>
<tags>
<tag>Command</tag>
</tags>
</entry>
<entry>
<title>Git 進階應用 Submodule</title>
<url>/Blog/Git%20%E9%80%B2%E9%9A%8E%E6%87%89%E7%94%A8%20Submodule/</url>
<content><![CDATA[<h1 id="Git-進階應用-Submodule"><a href="#Git-進階應用-Submodule" class="headerlink" title="Git 進階應用 Submodule"></a>Git 進階應用 Submodule</h1><p>以下將以<code>SubRepo</code>代表要被匯入的 Repository,而<code>SuperRepo</code>則是把 SubRepo 匯入的 Repository。</p>
<p>尚未撰寫</p>
<h2 id="參考文獻"><a href="#參考文獻" class="headerlink" title="參考文獻"></a>參考文獻</h2><p><a href="https://blog.puckwang.com/post/2020/git-submodule-vs-subtree/">Git 進階應用 Submodule 與 Subtree,使用它們來拆分專案
</a></p>
<p><a href="https://chouandy.pixnet.net/blog/post/240597416-git-submodule-%E7%9A%84%E6%96%B0%E5%A2%9E%E8%88%87%E6%9B%B4%E6%96%B0">Git Submodule 的新增與更新</a></p>
]]></content>
<categories>
<category>Git</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title>Git</title>
<url>/Blog/Git/</url>
<content><![CDATA[<h1 id="Git"><a href="#Git" class="headerlink" title="Git"></a>Git</h1><blockquote>
<p>簡介:Git 是一個開源的分布式版本控制系統。</p>
</blockquote>
<h1 id="集中式與分布式版本控制系統差異?"><a href="#集中式與分布式版本控制系統差異?" class="headerlink" title="集中式與分布式版本控制系統差異?"></a>集中式與分布式版本控制系統差異?</h1><p>集中式版本控制系統</p>
<p><img src="https://i.imgur.com/4KXYkQs.jpg"></p>
<ul>
<li>集中式版本控制系統:版本庫集中存放在中央服務器中,當需要修改版本時,需先從服務器取出並修改版本,再存入服務器中,過程中是需要聯網的。</li>
</ul>
<p>–</p>
<p>分布式版本控制系統</p>
<p><img src="https://i.imgur.com/MfkZ8un.jpg"></p>
<ul>
<li>分布式版本控制系統:每台電腦都有完整的版本庫,當修改完後將版本推送至其他電腦的版本庫修改即可。</li>
</ul>
<p>實際使用分布式版本控制系統時,很少會兩人之間的電腦推送版本庫的修改,因為可能並不在一個區域網內,兩台電腦互相訪問不了,因此通常會有一台充當”中央服務器”的電腦,但這個服務器的作用僅僅是方便交換大家的修改。</p>
<h1 id="1-基本概念"><a href="#1-基本概念" class="headerlink" title="1.基本概念"></a>1.基本概念</h1><h2 id="1-1-文件狀態"><a href="#1-1-文件狀態" class="headerlink" title="1.1 文件狀態"></a>1.1 文件狀態</h2><p>Git 中文件分為三種狀態:<code>已修改(modified)</code>、<code>暫存(staged)</code>、<code>已提交(committed)</code></p>
<ul>
<li>修改:Git 可以感知到工作目錄中哪些文件被修改,然後把修改的文件加入到 modifiied 區域。</li>
<li>暫存:通過 add 命令將工作目錄中被修改的文件提交到暫存區,等候被 commit。</li>
<li>提交:將暫存區文件 commit 至 Git 目錄中永久保存。</li>
</ul>
<h2 id="1-2-commit-節點"><a href="#1-2-commit-節點" class="headerlink" title="1.2 commit(節點)"></a>1.2 commit(節點)</h2><p>在 Git 中每次提交都會生成一個<code>節點</code>,而每個節點都會有一個<code>hash</code>作為唯一標示。</p>
<h2 id="1-3-HEAD-指針"><a href="#1-3-HEAD-指針" class="headerlink" title="1.3 HEAD(指針)"></a>1.3 HEAD(指針)</h2><p><code>HEAD</code>可以稱他為<code>指針</code>或<code>引用</code>,可指向任意一個<code>節點</code>,並且指向的<code>節點</code>為當前工作目錄。也可以指向一個<code>分支</code>,間接指向<code>分支</code>所指向的<code>節點</code>。</p>
<h2 id="1-4-遠程倉庫"><a href="#1-4-遠程倉庫" class="headerlink" title="1.4 遠程倉庫"></a>1.4 遠程倉庫</h2><p>雖然 Git 會把代碼以及歷史保存在本地,但最終還是要提交到服務器上的遠程倉庫,通過<code>clone</code>可以把遠程倉庫的代碼下載到本地。</p>
<p>遠程倉庫作為中介,開發完新功能可以申請提交至遠程倉庫,同時也可以從遠程倉庫拉取你同事的代碼。</p>
<h1 id="2-Branch-分支"><a href="#2-Branch-分支" class="headerlink" title="2. Branch(分支)"></a>2. Branch(分支)</h1><p><code>分支</code>可以存在多個,但<code>HEAD</code>只有一個。通常會根據<code>功能</code>或<code>版本</code>建立不同分支。</p>
<h1 id="3-命令詳解"><a href="#3-命令詳解" class="headerlink" title="3. 命令詳解"></a>3. 命令詳解</h1><p>基礎設定</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git config --global user.name 'Ed'</span><br><span class="line">git config --global user.email salahayo3192@gmail.com</span><br></pre></td></tr></table></figure>
<h2 id="3-0-創建本地倉庫"><a href="#3-0-創建本地倉庫" class="headerlink" title="3.0 創建本地倉庫"></a>3.0 創建本地倉庫</h2><p>使當前目錄作為 Git 本地倉庫。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git init</span><br></pre></td></tr></table></figure>
<h2 id="3-1-提交相關"><a href="#3-1-提交相關" class="headerlink" title="3.1 提交相關"></a>3.1 提交相關</h2><h3 id="添加某個文件到暫存區:"><a href="#添加某個文件到暫存區:" class="headerlink" title="添加某個文件到暫存區:"></a>添加某個文件到暫存區:</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add 文件路徑</span><br></pre></td></tr></table></figure>
<h3 id="添加所有文件到暫存區:"><a href="#添加所有文件到暫存區:" class="headerlink" title="添加所有文件到暫存區:"></a>添加所有文件到暫存區:</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add .</span><br></pre></td></tr></table></figure>
<h3 id="撤銷工作區改動:"><a href="#撤銷工作區改動:" class="headerlink" title="撤銷工作區改動:"></a>撤銷工作區改動:</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git checkout -- 文件名</span><br></pre></td></tr></table></figure>
<h3 id="清空暫存區:"><a href="#清空暫存區:" class="headerlink" title="清空暫存區:"></a>清空暫存區:</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git reset HEAD 文件名</span><br></pre></td></tr></table></figure>
<h3 id="提交:"><a href="#提交:" class="headerlink" title="提交:"></a>提交:</h3><p>將改動的文件加入到暫存區後就可以進行提交了,提交後會生成一個新的提交節點。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git commit -m "該節點的描述信息"</span><br></pre></td></tr></table></figure>
<h2 id="3-2-分支相關"><a href="#3-2-分支相關" class="headerlink" title="3.2 分支相關"></a>3.2 分支相關</h2><h3 id="創建分支"><a href="#創建分支" class="headerlink" title="創建分支"></a>創建分支</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git branch 分支名</span><br></pre></td></tr></table></figure>
<h3 id="切換分支"><a href="#切換分支" class="headerlink" title="切換分支"></a>切換分支</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git checkout 分支名</span><br></pre></td></tr></table></figure>
<h3 id="刪除分支"><a href="#刪除分支" class="headerlink" title="刪除分支"></a>刪除分支</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git branch -d 分支名</span><br></pre></td></tr></table></figure>
<h2 id="3-3-合併相關"><a href="#3-3-合併相關" class="headerlink" title="3.3 合併相關"></a>3.3 合併相關</h2><p>常用的合併命令大概有三個<code>merge</code>、<code>rebase</code>、<code>cherry-pick</code></p>
<h3 id="merge"><a href="#merge" class="headerlink" title="merge"></a>merge</h3><p><code>merge</code>是最常用的合併命令,可以將某個分支或某個節點的代碼合併至當前分支。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git merge 分支名/節點哈希值</span><br></pre></td></tr></table></figure>
<h3 id="rebase"><a href="#rebase" class="headerlink" title="rebase"></a>rebase</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git rebase 分支名/節點哈希值</span><br></pre></td></tr></table></figure>
<h3 id="cherry-pick"><a href="#cherry-pick" class="headerlink" title="cherry-pick"></a>cherry-pick</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git cherry-pick 節點哈希值</span><br></pre></td></tr></table></figure>
<h2 id="3-4-回退相關"><a href="#3-4-回退相關" class="headerlink" title="3.4 回退相關"></a>3.4 回退相關</h2><h3 id="分離HEAD"><a href="#分離HEAD" class="headerlink" title="分離HEAD"></a>分離<code>HEAD</code></h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git checkout 節點哈希值</span><br><span class="line"></span><br><span class="line">// HEAD 分離並指向前一個節點</span><br><span class="line">git checkout 分支名/HEAD^</span><br><span class="line"></span><br><span class="line">// HEAD 分離並指向前 N 個節點</span><br><span class="line">git checkout 分支名~N</span><br></pre></td></tr></table></figure>
<h3 id="回退"><a href="#回退" class="headerlink" title="回退"></a>回退</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git reset HEAD~N</span><br></pre></td></tr></table></figure>
<h2 id="基本操作"><a href="#基本操作" class="headerlink" title="基本操作"></a>基本操作</h2><h3 id="新增、提交"><a href="#新增、提交" class="headerlink" title="新增、提交"></a>新增、提交</h3><p>添加指定檔案到版本追蹤</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add readme.txt</span><br></pre></td></tr></table></figure>
<p>添加當前目錄所有檔案到版本追蹤</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add .</span><br></pre></td></tr></table></figure>
<p>添加指定檔案到版本追蹤</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add test.txt</span><br></pre></td></tr></table></figure>
<p>提交此次修改</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git commit -m "版本變更內容"</span><br></pre></td></tr></table></figure>
<p>查看專案的當前狀態,添加 -s 參數,可獲得簡短的結果輸出</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git status</span><br></pre></td></tr></table></figure>
<p>比較修改內容與最近提交的紀錄有哪些不同</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git diff</span><br></pre></td></tr></table></figure>
<hr>
<p>複製遠端倉庫至當前目錄</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git clone <repo></span><br></pre></td></tr></table></figure>
<p>複製遠端倉庫至指定目錄</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git clone <repo> <directory></span><br></pre></td></tr></table></figure>
<h3 id="git-reset-HEAD"><a href="#git-reset-HEAD" class="headerlink" title="git reset HEAD"></a>git reset HEAD</h3><table>
<thead>
<tr>
<th>名詞</th>
<th>解釋</th>
</tr>
</thead>
<tbody><tr>
<td>head</td>
<td>所在位置</td>
</tr>
<tr>
<td>index</td>
<td>變更狀態紀錄</td>
</tr>
<tr>
<td>working tree</td>
<td>工作目錄</td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>mode</th>
<th>head</th>
<th>index</th>
<th>working tree</th>
<th>說明</th>
</tr>
</thead>
<tbody><tr>
<td>soft</td>
<td>changed</td>
<td>unchanged</td>
<td>unchanged</td>
<td>僅移除commit變成新版未 commit,內容仍是新版的</td>
</tr>
<tr>
<td>mixed</td>
<td>changed</td>
<td>changed</td>
<td>unchanged</td>
<td>index 移除staged標記,變成Modifiedor Untracked,內容是新版的</td>
</tr>
<tr>
<td>hard</td>
<td>changed</td>
<td>changed</td>
<td>changed</td>
<td>回到上一版版本,其間變更完全移除(接近 svn revert),內容及狀態皆是上一版</td>
</tr>
</tbody></table>
<p>回退至當前版本,預設模式為 mixed</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git reset HEAD</span><br><span class="line"></span><br><span class="line">git reset --soft HEAD~1</span><br></pre></td></tr></table></figure>
<h3 id="git-rm"><a href="#git-rm" class="headerlink" title="git rm"></a>git rm</h3><p>移除某個文件,就必須要從已跟蹤文件清單中移除</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git rm <file></span><br></pre></td></tr></table></figure>
<p>如果刪除之前修改過並且已經放到站存區域的話,則必須要用強制選項<code>-f</code></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git rm -f <file></span><br></pre></td></tr></table></figure>
<p>不做工作區中刪除文件</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git rm --cached <file></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>Git</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title>Android四大組件-Activity</title>
<url>/Blog/Android%E5%9B%9B%E5%A4%A7%E7%B5%84%E4%BB%B6-Activity/</url>
<content><![CDATA[<h2 id="LaunchMode"><a href="#LaunchMode" class="headerlink" title="LaunchMode"></a>LaunchMode</h2><p>分為四種:<code>standard</code>、<code>singleTop</code>、<code>singleTask</code>、<code>singleInstance</code>。默認<strong>standard</strong></p>
<h3 id="standard"><a href="#standard" class="headerlink" title="standard"></a>standard</h3><ul>
<li>Activity 可以多次實例化,而每個實例均可屬於不同的任務,並且一個任務可以擁有多個實例。</li>
</ul>
<h3 id="singleTop"><a href="#singleTop" class="headerlink" title="singleTop"></a>singleTop</h3><ul>
<li>如果當前任務的頂部已存在 Activity 的一個實例,則系統會通過調用該實例的 onNewIntent() 方法象棋傳送 Intent,而不是創建 Activity 的新實例。</li>
<li></li>
</ul>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>Collection 架構</title>
<url>/Blog/Collection%20%E6%9E%B6%E6%A7%8B/</url>
<content><![CDATA[<h1 id="Collection-架構"><a href="#Collection-架構" class="headerlink" title="Collection 架構"></a>Collection 架構</h1><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">graph LR</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">C_1_1 -.-> C_1</span><br><span class="line">C_1_2 -.-> C_1</span><br><span class="line">C_1_2 -.-> C_3_1</span><br><span class="line">C_2_1 -.-> C_2</span><br><span class="line">C_2_2 -.-> C_2</span><br><span class="line">C_3_1 -.-> C_3</span><br><span class="line">C_3_2 -.-> C_3</span><br><span class="line">C_3_3 -.-> C_3_1</span><br><span class="line">C_1 -.-> B</span><br><span class="line">C_2 -.-> B</span><br><span class="line">C_3 -.-> B</span><br><span class="line">B -.-> A</span><br><span class="line">A[Iterable]</span><br><span class="line">B[Collection]</span><br><span class="line">C_1[List]</span><br><span class="line">C_2[Set]</span><br><span class="line">C_3[Queue]</span><br><span class="line">C_1_1(ArrayList)</span><br><span class="line">C_1_2(LinkedList)</span><br><span class="line">C_2_1(HashSet)</span><br><span class="line">C_2_2(TreeSet)</span><br><span class="line">C_3_1(Deque)</span><br><span class="line">C_3_2(PriorityQueue)</span><br><span class="line">C_3_3(ArrayDeque)</span><br></pre></td></tr></table></figure>
<ol>
<li><strong>List</strong> 允許重複的有序集合,如:<code>ArrayList</code>、<code>LinkedList</code>。<ol>
<li><code>ArrayList</code> 訪問速度快,但是向 List 中間插入或刪除元素的速度慢。</li>
<li><code>LinkedList</code> 訪問速度慢,但是向 List 中間插入或刪除元素的速度快。<br> <strong>P.S.</strong> 當操作的陣列頻繁使用查詢,則使用 <code>ArrayList</code><br> ,若需要頻繁的從前面或中間添加數據就使用 <code>LinkedList</code>。 </li>
</ol>
</li>
<li><strong>Set</strong> 集合中的物件不按特定的方式排序且無重複物件。,如:<code>HashSet</code>、<code>TreeSet</code>。<ol>
<li><code>HashSet</code> 按照哈希算法來存取集合中的物件,存取速度較快。 </li>
<li><code>TreeSet</code> 能夠對集合中的物件進行排序。<br> <strong>P.S.</strong> 不同之處在於,像 add,remove,contains,size …等操作,HashSet 比TreeSet 有更好的性能。</li>
</ol>
</li>
<li><strong>Queue</strong> 順序存取的結構,依照先進先出的原則來存取的佇列 *(FIFO)*,如:<code>ArrayDeque</code>,<code>PriorityQueue</code>。<ol>
<li><code>ArrayDeque</code> 因為實現了 Deque 接口,可以在隊列頭部和尾部進行操作。</li>
<li><code>PriorityQueue</code> 每次從隊列中取出的是最高優先權的元素,若沒有提供 Comparator ,優先對列中元素默認為自然順序。</li>
</ol>
</li>
</ol>
<ul>
<li>有序:取出和存入的顺序一致。</li>
<li>無序:取出和存入的顺序不一致。</li>
</ul>
<hr>
<h2 id="List"><a href="#List" class="headerlink" title="List"></a>List</h2><p><code>private int testCount = 100000;</code></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addMethod</span><span class="params">(List list)</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 取得 Class Name</span></span><br><span class="line"> String className = getClassSimpleName(list);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">long</span> startTime = getCurTimeMills();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < testCount; i++) {</span><br><span class="line"> list.add(<span class="number">0</span>, i);</span><br><span class="line"> }</span><br><span class="line"> printIntervalTimeMillis(startTime, className, <span class="string">"Add"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>ArrayList–Add–執行時間 : 977<br>LinkedList–Add–執行時間 : 6</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">getMethod</span><span class="params">(List list)</span> </span>{</span><br><span class="line"> <span class="comment">// 取得 Class Name</span></span><br><span class="line"> String className = getClassSimpleName(list);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">long</span> startTime = getCurTimeMills();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < testCount; i++) {</span><br><span class="line"> list.get(i);</span><br><span class="line"> }</span><br><span class="line"> printIntervalTimeMillis(startTime, className, <span class="string">"Get"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>ArrayList–Get–執行時間 : 7<br>LinkedList–Get–執行時間 : 3419</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">removeMethod</span><span class="params">(List list)</span> </span>{</span><br><span class="line"> <span class="comment">// 取得 Class Name</span></span><br><span class="line"> String className = getClassSimpleName(list);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">long</span> startTime = getCurTimeMills();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < testCount; i++) {</span><br><span class="line"> list.remove(<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> printIntervalTimeMillis(startTime, className, <span class="string">"Remove"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>ArrayList–Remove–執行時間 : 529<br>LinkedList–Remove–執行時間 : 5</p>
<p>通用方法:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 打印執行時間</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">printIntervalTimeMillis</span><span class="params">(<span class="keyword">long</span> startTime, String className, String methodName)</span> </span>{</span><br><span class="line"> System.out.println(className + <span class="string">"--"</span> + methodName + <span class="string">"--"</span> + <span class="string">"執行時間 : "</span> + (getCurTimeMills() - startTime));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 取得當前系統時間</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">long</span> <span class="title">getCurTimeMills</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> System.currentTimeMillis();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> String <span class="title">getClassSimpleName</span><span class="params">(List list)</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> list.getClass().getSimpleName();</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<hr>
<h2 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h2><p>暫時沒有寫,對此還不熟悉。</p>
<h2 id="Queue"><a href="#Queue" class="headerlink" title="Queue"></a>Queue</h2><p>[外链图片转存失败(img-ntuWhDEX-1566362962711)(<a href="https://i.imgur.com/pAi8Qhw.jpg)]">https://i.imgur.com/pAi8Qhw.jpg)]</a></p>
<p><strong>先進先出 ( First - In - First - Out, FIFO) 的排程</strong></p>
<ol>
<li>enqueue :將資料放入佇列尾端。<br> <strong>P.S.</strong> C++ 用 push,JAVA 用 offer。</li>
<li>dequeue:取出佇列前端的資料。<br> <strong>P.S.</strong> C++ 用 pop,JAVA 用 poll。</li>
</ol>
<hr>
<h2 id="參考文獻"><a href="#參考文獻" class="headerlink" title="參考文獻"></a>參考文獻</h2><ol>
<li><a href="https://www.jianshu.com/p/de271d35591c">LinkedList 與 ArrayList 的比較</a></li>
<li><a href="https://www.jianshu.com/p/403ca855a6a8">HashSet 與 TreeSet 的比較</a></li>
<li><a href="https://blog.csdn.net/securitit/article/details/46919149">ArrayDeque 與 PriorityQueue 的比較</a></li>
<li><a href="http://finalfrank.pixnet.net/blog/post/22382141-queue--%E4%BD%87%E5%88%97">什麼是 Queue ?</a></li>
</ol>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>Glide 基本概念</title>
<url>/Blog/Glide%20%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</url>
<content><![CDATA[<ul>
<li>Model <ul>
<li>ModelLoader 負責從數據源獲得數據</li>
</ul>
</li>
<li>Data <ul>
<li>Decoder 負責解碼數據源的數據</li>
</ul>
</li>
<li>Resource 解碼後的資源,負責解碼 ResourceDecoder<ul>
<li>ResourceTransformed 負責轉換資源</li>
</ul>
</li>
<li>TransformedResource 轉換後的資源<ul>
<li>TransCode 負責轉碼操作</li>
</ul>
</li>
<li>TransCodedResource 轉碼後的資源, 將Bitmap 轉為 BitmapDrawable</li>
<li>Target 顯示的圖片封裝至 Target 上 </li>
</ul>
<h2 id="with-方法"><a href="#with-方法" class="headerlink" title="with 方法"></a>with 方法</h2><p>設計很多 with 重載方法,方便用戶使用。</p>
<h4 id="RequestManagerRetriever"><a href="#RequestManagerRetriever" class="headerlink" title="RequestManagerRetriever"></a>RequestManagerRetriever</h4><p>因為 Glide 為單一實例所以 RequestManagerRetriever 也會是單一實例。</p>
<p>Glide 在創建時生成 RequestManagerRetriever。</p>
<p>概念:根據傳入不同的的參數獲取相對的 RequestManager</p>
<h3 id="為什麼要傳入-Context-?"><a href="#為什麼要傳入-Context-?" class="headerlink" title="為什麼要傳入 Context ?"></a>為什麼要傳入 Context ?</h3><p>主要是 Glide 在加載圖片時會綁定傳入的 Context 的生命週期,為了<br>Activity or Fragment 在被銷毀後,會停止圖片的加載。好處是避免消耗多餘的資源。</p>
<p>通常都是通過 getRetriever 取得 RequestManagerRetriever,<br>再由 RequestManagerRetriever 去取得 RequestManager</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> RequestManager <span class="title">with</span><span class="params">(<span class="meta">@NonNull</span> Context context)</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 首先取得 RequestManagerRetriever</span></span><br><span class="line"> <span class="comment">// 不管傳入哪個類型的 Context 內部創建時都會是以 ApplicationContext創建</span></span><br><span class="line"> RequestManagerRetriever retriever = getRetriever(context);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 之後使用 RequestManagerRetriever 創建 RequestManager</span></span><br><span class="line"> RequestManager requestManager = retriever.get(context);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> requestManager;</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>通過傳入的 Context 不同的類型做不同的操作。以下給出兩個傳入不同參數所執行的方法塊。</p>
<ol>
<li><strong>Context</strong><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> RequestManager <span class="title">get</span><span class="params">(<span class="meta">@NonNull</span> Context context)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (context == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"You cannot start a load on a null Context"</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (Util.isOnMainThread() && !(context <span class="keyword">instanceof</span> Application)) {</span><br><span class="line"> <span class="comment">// 當前線程是主線程且 context 不是 Application 的實例;</span></span><br><span class="line"> <span class="comment">// 根據 context 的類型做不同的處理。</span></span><br><span class="line"> <span class="keyword">if</span> (context <span class="keyword">instanceof</span> FragmentActivity) {</span><br><span class="line"> <span class="keyword">return</span> get((FragmentActivity) context);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (context <span class="keyword">instanceof</span> Activity) {</span><br><span class="line"> <span class="keyword">return</span> get((Activity) context);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (context <span class="keyword">instanceof</span> ContextWrapper</span><br><span class="line"> && ((ContextWrapper) context).getBaseContext().getApplicationContext() != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> get(((ContextWrapper) context).getBaseContext());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 此方法取得的 RequestManager 是為單例,因生命週期與程序一樣</span></span><br><span class="line"> <span class="keyword">return</span> getApplicationManager(context);</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
<li><strong>FragmentActivity</strong><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> RequestManager <span class="title">get</span><span class="params">(<span class="meta">@NonNull</span> FragmentActivity activity)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (Util.isOnBackgroundThread()) {</span><br><span class="line"> <span class="comment">// 如果當前線程不是主線程</span></span><br><span class="line"> <span class="keyword">return</span> get(activity.getApplicationContext());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 判斷版本號是否大於 17 且 Activity是否被銷毀,若符合則拋出錯誤</span></span><br><span class="line"> assertNotDestroyed(activity);</span><br><span class="line"> FragmentManager fm = activity.getSupportFragmentManager();</span><br><span class="line"> <span class="keyword">return</span> supportFragmentGet(activity, fm, <span class="comment">/*parentHint=*/</span> <span class="keyword">null</span>, isActivityVisible(activity));</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></li>
</ol>
<p><strong>supportFragmentGet</strong>這個方法在當前的 Activity 創建一個無介面的 Fragment 且 add 到<br>當前 Activity 中,以此來實現對 Activity 生命週期的監聽。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> RequestManager <span class="title">supportFragmentGet</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="meta">@NonNull</span> Context context,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="meta">@NonNull</span> FragmentManager fm,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="meta">@Nullable</span> Fragment parentHint,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">boolean</span> isParentVisible)</span> </span>{</span><br><span class="line"> <span class="comment">// 在當前 Activity 創建一個無介面的 Fragment 且 add 到當前 Activity 中</span></span><br><span class="line"> SupportRequestManagerFragment current =</span><br><span class="line"> getSupportRequestManagerFragment(fm, parentHint, isParentVisible);</span><br><span class="line"> RequestManager requestManager = current.getRequestManager();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (requestManager == <span class="keyword">null</span>) {</span><br><span class="line"> Glide glide = Glide.get(context);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 創建一個 RequestManager</span></span><br><span class="line"> requestManager =</span><br><span class="line"> factory.build(</span><br><span class="line"> glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);</span><br><span class="line"> current.setRequestManager(requestManager);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> requestManager;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h4 id="RequestManager-主要負責請求管理"><a href="#RequestManager-主要負責請求管理" class="headerlink" title="RequestManager 主要負責請求管理"></a>RequestManager 主要負責請求管理</h4><ul>
<li>通過 Glide 的 getRetriever 靜態方法,獲取 RequestManagerRetriever 的對象。</li>
<li>通過Glide獲取的 RequestManagerRetriever 使用 get() 通過不同的參數做不同的處理:<ul>
<li><p>context 是 Application,通過 getApplicationManager(Context context) 得到同應用程序生命週期相同的 RequestManager。</p>
</li>
<li><p>context 是 Activity,通過 supportFragmentGet 方法,在當前 Activity 創建且添加一個無介面的 Fragment,實現圖片加載與 Activity 生命週期綁定,之後創建並返回一個 RequestManager 對象。</p>
<h2 id="load-方法"><a href="#load-方法" class="headerlink" title="load 方法"></a>load 方法</h2></li>
</ul>
</li>
</ul>
<p>load 方法分為兩步驟:</p>
<ol>
<li>調用 asDrawable 方法,創建 RequestBuilder</li>
<li>調用 RequestBuilder 內的 load 方法,將 數據來源設置道 model 內,再將數據來源是否已經設置的 isModelSet 設置為 true。</li>
</ol>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="meta">@CheckResult</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> RequestBuilder<Drawable> <span class="title">load</span><span class="params">(<span class="meta">@Nullable</span> String string)</span> </span>{</span><br><span class="line"> <span class="comment">// 創建並返回一個 RequestBuilder 對象</span></span><br><span class="line"> <span class="comment">// 此方法統一返回的結果會是 Drawable</span></span><br><span class="line"> RequestBuilder<Drawable> drawableRequestBuilder = asDrawable();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 設定 model </span></span><br><span class="line"> RequestBuilder<Drawable> load = drawableRequestBuilder.load(string);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> load;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h2 id="into-方法"><a href="#into-方法" class="headerlink" title="into 方法"></a>into 方法</h2><p>前兩步驟可以理解為對圖片加載的配置請求,僅僅是一個請求,而並沒有去執行。在 Glide 最後一步 into 方法中,這個請求才會被執行。</p>
<p>關鍵代碼為最後一行, into() 方法。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> ViewTarget<ImageView, TranscodeType> <span class="title">into</span><span class="params">(<span class="meta">@NonNull</span> ImageView view)</span> </span>{</span><br><span class="line"> <span class="comment">// 判斷當前線程是否為主線程,若為否則拋出異常。</span></span><br><span class="line"> Util.assertMainThread();</span><br><span class="line"> <span class="comment">// 檢查傳進來的 view 是否為空。</span></span><br><span class="line"> Preconditions.checkNotNull(view);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 對 ScaleType 進行配置</span></span><br><span class="line"> BaseRequestOptions<?> requestOptions = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">if</span> (!requestOptions.isTransformationSet()</span><br><span class="line"> && requestOptions.isTransformationAllowed()</span><br><span class="line"> && view.getScaleType() != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="comment">//...略</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> into(</span><br><span class="line"> <span class="comment">// 根據 transCodeClass 創建 ImageView 設置圖片的對應方法。</span></span><br><span class="line"> <span class="comment">// Bitmap -> BitmapImageViewTarget</span></span><br><span class="line"> <span class="comment">// Drawable -> DrawableImageViewTarget</span></span><br><span class="line"> glideContext.buildImageViewTarget(view, transcodeClass),</span><br><span class="line"> <span class="comment">/*targetListener=*/</span> <span class="keyword">null</span>,</span><br><span class="line"> <span class="comment">// 圖片加載配置設定</span></span><br><span class="line"> requestOptions,</span><br><span class="line"> Executors.mainThreadExecutor());</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>首先通過 buildImageViewTarget 方法創建一個 Target 類型的對象。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="keyword">public</span> <X> <span class="function">ViewTarget<ImageView, X> <span class="title">buildImageViewTarget</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="meta">@NonNull</span> ImageView imageView, <span class="meta">@NonNull</span> Class<X> transcodeClass)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> imageViewTargetFactory.buildTarget(imageView, transcodeClass);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>真正執行創建 Target 對象為 ImageViewTargetFactory。</p>
<p>根據圖片來源類型的不同獲取相對的 Target 對象。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@NonNull</span></span><br><span class="line"> <span class="meta">@SuppressWarnings("unchecked")</span></span><br><span class="line"> <span class="keyword">public</span> <Z> <span class="function">ViewTarget<ImageView, Z> <span class="title">buildTarget</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="meta">@NonNull</span> ImageView view, <span class="meta">@NonNull</span> Class<Z> clazz)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (Bitmap.class.equals(clazz)) {</span><br><span class="line"> <span class="keyword">return</span> (ViewTarget<ImageView, Z>) <span class="keyword">new</span> BitmapImageViewTarget(view);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (Drawable.class.isAssignableFrom(clazz)) {</span><br><span class="line"> <span class="keyword">return</span> (ViewTarget<ImageView, Z>) <span class="keyword">new</span> DrawableImageViewTarget(view);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(</span><br><span class="line"> <span class="string">"Unhandled class: "</span> + clazz + <span class="string">", try .as*(Class).transcode(ResourceTranscoder)"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>獲取相對應的 Target 對象後執行 into 方法</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <Y extends Target<TranscodeType>> <span class="function">Y <span class="title">into</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="meta">@NonNull</span> Y target,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="meta">@Nullable</span> RequestListener<TranscodeType> targetListener,</span></span></span><br><span class="line"><span class="function"><span class="params"> BaseRequestOptions<?> options,</span></span></span><br><span class="line"><span class="function"><span class="params"> Executor callbackExecutor)</span> </span>{</span><br><span class="line"> <span class="comment">// 檢查 target 是否為空,若是則拋出錯誤。</span></span><br><span class="line"> Preconditions.checkNotNull(target);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 檢查數據來源是否已經設定</span></span><br><span class="line"> <span class="keyword">if</span> (!isModelSet) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"You must call #load() before calling #into()"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Request request = buildRequest(target, targetListener, options, callbackExecutor);</span><br><span class="line"></span><br><span class="line"> Request previous = target.getRequest();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (request.isEquivalentTo(previous)</span><br><span class="line"> && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {</span><br><span class="line"> <span class="comment">// 條件一:新創建的 Request 是否跟 target 已創建的 Request 相等</span></span><br><span class="line"> <span class="comment">// 條件二:不跳過內存緩存 | 先前請求尚未完成</span></span><br><span class="line"></span><br><span class="line"> request.recycle();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!Preconditions.checkNotNull(previous).isRunning()) {</span><br><span class="line"> <span class="comment">// 先前的請求尚未開始運行中,則使用先前的請求</span></span><br><span class="line"> previous.begin();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> target;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> requestManager.clear(target);</span><br><span class="line"> target.setRequest(request);</span><br><span class="line"> requestManager.track(target, request);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> target;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>RequestManager 執行 track 方法</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">track</span><span class="params">(<span class="meta">@NonNull</span> Target<?> target, <span class="meta">@NonNull</span> Request request)</span> </span>{</span><br><span class="line"> <span class="comment">// 將 Target 設置追蹤,生命週期改變時會執行相對應的方法。</span></span><br><span class="line"> targetTracker.track(target);</span><br><span class="line"> <span class="comment">// 執行創建的請求</span></span><br><span class="line"> requestTracker.runRequest(request);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>Library</category>
</categories>
<tags>
<tag>Android , Libary</tag>
</tags>
</entry>
<entry>
<title>Http 介紹</title>
<url>/Blog/Http%20%E4%BB%8B%E7%B4%B9/</url>
<content><![CDATA[<h1 id="Http-介紹"><a href="#Http-介紹" class="headerlink" title="Http 介紹"></a>Http 介紹</h1><h2 id="簡介"><a href="#簡介" class="headerlink" title="簡介"></a>簡介</h2><p><code>HTTP</code>屬於應用層的面向對象協議。</p>
<h2 id="特點"><a href="#特點" class="headerlink" title="特點"></a>特點</h2><ol>
<li>支持 C/S(客戶/服務器) 模式。</li>
<li>簡單快速:客戶向服務器請求時,只需傳送請求方法和路徑。如:<code>GET</code>、<code>HEAD</code>、<code>POST</code>……等</li>
<li>靈活:<code>HTTP</code>允許傳輸任意類型的數據對象,類型以<code>Content-Type</code>標記。</li>
<li>無連接:限制每次連接只處理一個請求,服務器處理完客戶的請求,並收到客戶的應答,即斷開連接。</li>
<li>無狀態:指對事務處理沒有記憶能力。若缺少狀態則意味著如果後續需要前面的信息,則它必須重傳。</li>
</ol>
<h2 id="訊息格式-Message-Format"><a href="#訊息格式-Message-Format" class="headerlink" title="訊息格式(Message Format)"></a>訊息格式(Message Format)</h2><p>**訊息(Message)**:又譯為報文、信息、消息。是<code>HTTP/1.1</code>的最小傳輸單位。</p>
<blockquote>
<p>註:<code>HTTP/2</code>的最小傳輸單元為訊息框(Frame),而多個訊息框組合為一個訊息。</p>
</blockquote>
<p>所有訊息都是由:</p>
<ul>
<li>起始行(start-line)開始。</li>
<li>0 or 多個表頭欄位(header-field)+CRLF,合稱為『表頭(headers)』</li>
<li>再加上一個 CRLF</li>
<li>最後始可選的(optional)訊息主體(message-body)</li>
</ul>
<p><img src="https://i.imgur.com/q13Vcwj.png"></p>
<p><strong>請求範例:</strong><br><img src="https://i.imgur.com/qj4Jegc.png"></p>
<p><strong>回應範例:</strong><br><img src="https://i.imgur.com/ZEYDFHX.png"></p>
<blockquote>
<p>CRLF(carriage return followed by line feed)<br>網際網路(Internet)嚴謹的換行(newline)標準 => <code>\r\n</code></p>
<p>CR = 回車(Carriage Return),又稱歸位。<br>源於傳統的電傳印表機,用於回到一行字的起頭,非換行。<br>許多語言表示:<code>\r</code>,Unicode 中為 0x0D(十進制的13)</p>
<p>LF = 換行(Line Feed)<br>許多語言表示:<code>\n</code>,Unicode 中為 0x0A(十進制的 10)</p>
<p>CRLF,接續在表頭(Header)之後的必要部分。</p>
</blockquote>
<h3 id="起始行-start-line"><a href="#起始行-start-line" class="headerlink" title="起始行(start line)"></a>起始行(start line)</h3><p>起始行(start line),作為訊息的開始,是請求訊息和回應訊息內容上最大的差異。</p>
<ul>
<li>請求:請求行(request-line)</li>
<li>回應:狀態行(status-line)</li>
</ul>
<p><strong>請求行(request-line)</strong></p>
<p>格式:方法(method)+空白(SP)+請求目標(request-target)+空白(SP)+HTTP版本(HTTP-version)+CRLF(carriage return followed by line feed)。</p>
<ol>
<li>方法(method):全稱為請求方法(request method)<br> 如:<code>GET</code>、<code>POST</code>、<code>PUT</code>、<code>DELETE</code>……稱為方法(method)。</li>
<li>請求目標(request-target):總共有四種形式,採用何種形式取決於使用的請求方法(request method)與代理(proxy)方式。<blockquote>
<p>註:不能為空路徑,必須以<code>"/"</code>開頭。</p>
</blockquote>
</li>
<li>HTTP 版本(HTTP-version)<br> 如:<code>HTTP/1.1</code>、<code>HTTP/1.0</code>。</li>
</ol>
<p><strong>狀態行(status-line)</strong></p>
<p>格式:HTTP版本(HTTP-version)+空白(SP)+狀態碼(status-code)+空白(SP)+原因短語(reason-phrase)、CRLF(carriage return followed by line feed)</p>
<ol>
<li>狀態碼(status-code)、原因短語(reason-phrase)<br> 如:<code>200 OK</code></li>
</ol>
<p><img src="https://i.imgur.com/FpvGqGR.png"></p>
<h3 id="表頭-Header"><a href="#表頭-Header" class="headerlink" title="表頭(Header)"></a>表頭(Header)</h3><p>表頭(Header),又譯為首部、檔頭、標頭,由 0 or 多個表頭欄位(header-field)+ CRLF 組成。</p>
<p><strong>表頭欄位(header-field)</strong></p>
<p>單個表頭欄位(header-field)的組成:</p>
<ul>
<li>一個不區分大小寫的欄位名稱(field-name)</li>
<li>緊接著冒號(:)</li>
<li>欄位值(field-value)</li>
</ul>
<p>如:header:{field-name}:{field-value}。</p>
<blockquote>
<p>註:欄位名稱(field-name)與冒號(colon)之間不可有空白!</p>
<p>HTTP/2 以表頭壓縮(Header Compression)增進效能與擴充性!<br>註:表頭壓縮(Header Compression)指將表頭欄位壓縮成二進制的有序串列。 </p>
</blockquote>
<h3 id="訊息主體-Message-body"><a href="#訊息主體-Message-body" class="headerlink" title="訊息主體(Message body)"></a>訊息主體(Message body)</h3><p>訊息主體(message body),又譯為訊息體、報文主體,向包裹的箱子,是訊息(message)中乘載資料的地方。</p>
<p><strong>酬載(payload)</strong></p>
<p>資料酬載(payload),又譯為酬載、有效負荷,是傳輸時實際預期的資料,可能是完整 or 部分的表示(representation)。</p>
<p>酬載(payload)語意上不考慮資料的內容是何種格式、語言、編碼…</p>
<p>描述酬載的元資料(metadata):酬載表頭欄位(payload header fields)</p>
<ul>
<li>傳輸編碼(Transfer-Encoding)</li>
<li>內容類型(Content-Type)</li>
<li>內容範圍(Content-Range)</li>
<li>拖曳(Trailer)</li>
<li>…….</li>
</ul>
<p><strong>內容類型(Content-Type)</strong></p>
<p>內容類型(content-type)指相關表示的媒體類型(media type),用於定義資料格式(data format),以供接收者以相應的方式處理。</p>
<p>媒體類型(Media Type):由主要類型/次要類型以及可選的參數(paramter)所構成。</p>
<p>主要類型分為:</p>
<ul>
<li>文字(text)</li>
<li>影像(image)</li>
<li>音訊(audio)</li>
<li>影片(video)</li>
<li>應用(application)</li>
</ul>
<p><img src="https://i.imgur.com/CHFtGqG.png"></p>
<blockquote>
<p>其中『application/x-www-form-urlencoded』or『application/x-www-form-urlencoded;charset=utf-8』是類似百分比編碼的健值對形式。<br>例如:『name=%E5%8B%9D&password=9487』(“勝”的表分比編碼:%E5%8B%9D)</p>
</blockquote>
<h4 id="百分比編碼"><a href="#百分比編碼" class="headerlink" title="百分比編碼"></a>百分比編碼</h4><p>規則:把字元 ASCll 碼以十六進位表示,前方再加上一個百分比符號。</p>
<p>例如<code>#</code>的的 ASCll 碼是 0x23,經過百分比編碼轉換成 %23。</p>
<p>若遇到非 ASCll 的字元(例如中文字),則會將資料以 UTF-8 編碼方式表示成一連串的位元組串列,再將每個位元組以百分比編碼的方式進行編碼。</p>
]]></content>
<categories>
<category>Http</category>
</categories>
<tags>
<tag>Http</tag>
</tags>