-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1311 lines (828 loc) · 170 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
<link rel="dns-prefetch" href="http://www.imzhiqiang.com">
<title>倾城之泪的个人博客</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="description" content="既然琴瑟起,何以笙箫默">
<meta property="og:type" content="website">
<meta property="og:title" content="倾城之泪的个人博客">
<meta property="og:url" content="http://www.imzhiqiang.com/index.html">
<meta property="og:site_name" content="倾城之泪的个人博客">
<meta property="og:description" content="既然琴瑟起,何以笙箫默">
<meta property="og:locale">
<meta property="article:author" content="倾城之泪">
<meta name="twitter:card" content="summary">
<link rel="alternative" href="/atom.xml" title="倾城之泪的个人博客" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link rel="stylesheet" type="text/css" href="/./main.0cf68a.css">
<style type="text/css">
#container.show {
background: linear-gradient(200deg,#a0cfe4,#e8c37e);
}
</style>
<meta name="generator" content="Hexo 5.4.0"></head>
<body>
<div id="container" q-class="show:isCtnShow">
<canvas id="anm-canvas" class="anm-canvas"></canvas>
<div class="left-col" q-class="show:isShow">
<div class="overlay" style="background: #4d4d4d"></div>
<div class="intrude-less">
<header id="header" class="inner">
<a href="/" class="profilepic">
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gorutddnkvj30cs0csab8.jpg" class="js-avatar">
</a>
<hgroup>
<h1 class="header-author"><a href="/"></a></h1>
</hgroup>
<nav class="header-menu">
<ul>
<li><a href="/">主页</a></li>
<li><a href="/tags/%E9%9A%8F%E7%AC%94/">随笔</a></li>
</ul>
</nav>
<nav class="header-smart-menu">
<a q-on="click: openSlider(e, 'innerArchive')" href="javascript:void(0)">所有文章</a>
<a q-on="click: openSlider(e, 'friends')" href="javascript:void(0)">友链</a>
<a q-on="click: openSlider(e, 'aboutme')" href="javascript:void(0)">关于我</a>
</nav>
<nav class="header-nav">
<div class="social">
<a class="github" target="_blank" href="https://github.com/Alluretears" title="github"><i class="icon-github"></i></a>
<a class="weibo" target="_blank" href="http://www.weibo.com/qczhilei" title="weibo"><i class="icon-weibo"></i></a>
</div>
</nav>
</header>
</div>
</div>
<div class="mid-col" q-class="show:isShow,hide:isShow|isFalse">
<nav id="mobile-nav">
<div class="overlay js-overlay" style="background: #4d4d4d"></div>
<div class="btnctn js-mobile-btnctn">
<div class="slider-trigger list" q-on="click: openSlider(e)"><i class="icon icon-sort"></i></div>
</div>
<div class="intrude-less">
<header id="header" class="inner">
<div class="profilepic">
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gorutddnkvj30cs0csab8.jpg" class="js-avatar">
</div>
<hgroup>
<h1 class="header-author js-header-author"></h1>
</hgroup>
<nav class="header-nav">
<div class="social">
<a class="github" target="_blank" href="https://github.com/Alluretears" title="github"><i class="icon-github"></i></a>
<a class="weibo" target="_blank" href="http://www.weibo.com/qczhilei" title="weibo"><i class="icon-weibo"></i></a>
</div>
</nav>
<nav class="header-menu js-header-menu">
<ul style="width: 50%">
<li style="width: 50%"><a href="/">主页</a></li>
<li style="width: 50%"><a href="/tags/%E9%9A%8F%E7%AC%94/">随笔</a></li>
</ul>
</nav>
</header>
</div>
<div class="mobile-mask" style="display:none" q-show="isShow"></div>
</nav>
<div id="wrapper" class="body-wrap">
<div class="menu-l">
<div class="canvas-wrap">
<canvas data-colors="#eaeaea" data-sectionHeight="100" data-contentId="js-content" id="myCanvas1" class="anm-canvas"></canvas>
</div>
<div id="js-content" class="content-ll">
<article id="post-Kotlin-coroutines-on-Android" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2021/02/19/Kotlin-coroutines-on-Android/">Kotlin coroutines on Android</a>
</h1>
<a href="/2021/02/19/Kotlin-coroutines-on-Android/" class="archive-article-date">
<time datetime="2021-02-19T07:19:42.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2021-02-19</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="What-is-coroutines"><a href="#What-is-coroutines" class="headerlink" title="What is coroutines?"></a>What is coroutines?</h1><h2 id="维基百科的定义"><a href="#维基百科的定义" class="headerlink" title="维基百科的定义"></a>维基百科的定义</h2><p>维基百科上对协程的定义:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">协程是计算机程序的一类组件,推广了协作式多任务的子程序,允许执行被挂起与被恢复。</span><br></pre></td></tr></table></figure>
<div align="center">
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gorvgh1hg7j30a00a0dgn.jpg" alt="听上去怎么这么抽象?" />
</div>
<h2 id="从线程说起"><a href="#从线程说起" class="headerlink" title="从线程说起"></a>从线程说起</h2><div align="center">
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gorvh9k7vjj30hd08x765.jpg" alt="理想中的线程和实际上的线程" />
</div>
<p>我们都知道线程是<strong>抢占式</strong>的,你可以给线程设置优先级,但是 CPU 实际执行的是哪个线程,我们并不能控制,只能通过<strong>锁</strong>的方式来保证程序的逻辑正确。</p>
<p>协程是<strong>协作式</strong>的,是编程语言层级的,而非系统层级。当我们切换协程时,不涉及任何系统调用,因此可以把协程看作是<strong>轻量的线程</strong>。</p>
<a class="article-more-a" href="/2021/02/19/Kotlin-coroutines-on-Android/#more">more >></a>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2021/02/19/Kotlin-coroutines-on-Android/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-from-livedata-to-stream" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/05/26/from-livedata-to-stream/">从 LiveData 到流</a>
</h1>
<a href="/2020/05/26/from-livedata-to-stream/" class="archive-article-date">
<time datetime="2020-05-26T06:39:09.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2020-05-26</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="什么是-LiveData"><a href="#什么是-LiveData" class="headerlink" title="什么是 LiveData?"></a>什么是 LiveData?</h1><blockquote>
<p>一个具有生命周期感知能力的可观察的数据存储类。</p>
</blockquote>
<ul>
<li>生命周期感知能力</li>
<li>可观察</li>
<li>数据存储</li>
</ul>
<a class="article-more-a" href="/2020/05/26/from-livedata-to-stream/#more">more >></a>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2020/05/26/from-livedata-to-stream/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-Android-build-speed-opt" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/07/22/Android-build-speed-opt/">Android 项目编译速度优化</a>
</h1>
<a href="/2019/07/22/Android-build-speed-opt/" class="archive-article-date">
<time datetime="2019-07-22T12:44:27.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2019-07-22</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h3 id="Android-编译这件小事"><a href="#Android-编译这件小事" class="headerlink" title="Android 编译这件小事"></a>Android 编译这件小事</h3><h4 id="什么是编译?"><a href="#什么是编译?" class="headerlink" title="什么是编译?"></a>什么是编译?</h4><p>我们每天都要经历数十次的编译,那么什么是编译呢?简单来说,就是把高级语言转化为机器或虚拟机能识别的低级语言的过程。在 Android 中,就是把我们认识的 Java 或 Kotlin 语言转化为 Android 虚拟机可以执行的 Dalvik 字节码的过程。</p>
<a class="article-more-a" href="/2019/07/22/Android-build-speed-opt/#more">more >></a>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2019/07/22/Android-build-speed-opt/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-31DaysOfKotlin" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/06/23/31DaysOfKotlin/">31DaysOfKotlin</a>
</h1>
<a href="/2019/06/23/31DaysOfKotlin/" class="archive-article-date">
<time datetime="2019-06-23T09:40:39.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2019-06-23</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h2 id="31-天学习-Kotlin-—-第一周回顾"><a href="#31-天学习-Kotlin-—-第一周回顾" class="headerlink" title="#31 天学习 Kotlin — 第一周回顾"></a>#31 天学习 Kotlin — 第一周回顾</h2><p>我们写的 Kotlin 代码越多,我们越喜欢她!Kotlin 的现代语言特性和 <a target="_blank" rel="noopener" href="https://github.com/android/android-ktx">Android KTX</a> 使我们的 Android 代码更加的简洁,清晰和优雅。我们 (<a target="_blank" rel="noopener" href="https://twitter.com/FMuntenescu">@FMuntenescu</a> 和 <a target="_blank" rel="noopener" href="https://twitter.com/objcode">@objcode</a>)启动了 <a target="_blank" rel="noopener" href="https://twitter.com/search?q=%2331DaysOfKotlin">#31DaysOfKotlin</a> 系列作为分享我们最喜爱的 Kotlin 和 Android KTX 特性的一种方式,希望你和我们一样,越来越喜欢她。</p>
<p>在前 7 天的时间里,我们专注于基础知识。</p>
<h2 id="Day-1-Elvis-操作符"><a href="#Day-1-Elvis-操作符" class="headerlink" title="Day 1: Elvis 操作符"></a>Day 1: Elvis 操作符</h2><p>需要处理代码中的空值?可以使用 elvis 操作符,避免您的 “空情况” (null-erplate)。这只是替换空作为值或者返回事件情况的一个小语法。文档: <a target="_blank" rel="noopener" href="https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator">Elvis operator</a>.</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">val</span> name: String = person.name ?: “unknown”</span><br><span class="line"><span class="keyword">val</span> age = person.age ?: <span class="keyword">return</span></span><br></pre></td></tr></table></figure>
<h2 id="Day-2-字符串模板"><a href="#Day-2-字符串模板" class="headerlink" title="Day 2: 字符串模板"></a>Day 2: 字符串模板</h2><p>格式化字符串?将 $ 符放在变量名的前面表达字符串中的变量和表达式。使用 ${expression} 求表达式的值。文档: <a target="_blank" rel="noopener" href="https://kotlinlang.org/docs/reference/basic-types.html#string-templates">string templates</a>.</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">val</span> language = “Kotlin”</span><br><span class="line"></span><br><span class="line"><span class="comment">// “Kotlin has 6 characters”</span></span><br><span class="line"><span class="keyword">val</span> text = “$language has ${language.length} characters”</span><br></pre></td></tr></table></figure>
<a class="article-more-a" href="/2019/06/23/31DaysOfKotlin/#more">more >></a>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color2">Kotlin</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2019/06/23/31DaysOfKotlin/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-In-app-resource-opt" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/03/02/In-app-resource-opt/">应用内资源文件优化</a>
</h1>
<a href="/2019/03/02/In-app-resource-opt/" class="archive-article-date">
<time datetime="2019-03-02T12:41:03.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2019-03-02</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h2 id="使用-lint-检查无用资源"><a href="#使用-lint-检查无用资源" class="headerlink" title="使用 lint 检查无用资源"></a>使用 lint 检查无用资源</h2><p>使用lint检测工具检查无用代码,注意不要使用一键删除,避免以下两个问题:</p>
<ul>
<li>通过反射获取资源,可以将反射资源加入lint.xml,避过lint检测</li>
<li>koltin目前对lint检测支持并不友好</li>
</ul>
<a class="article-more-a" href="/2019/03/02/In-app-resource-opt/#more">more >></a>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2019/03/02/In-app-resource-opt/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-action-image-capture-issue" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2017/09/04/action-image-capture-issue/">使用ACTION_IMAGE_CAPTURE可能存在的风险</a>
</h1>
<a href="/2017/09/04/action-image-capture-issue/" class="archive-article-date">
<time datetime="2017-09-04T03:16:11.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2017-09-04</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<p>很多的 Android App 中都有使用相机拍摄用户头像的功能。大部分开发者都会使用<code>MediaStore.ACTION_IMAGE_CAPTURE</code>来满足这一需求。这可以节省很多时间,不需要单独开发相机 UI,直接调用系统相机;不需要向系统请求 Camera 权限。正如官方文档里面说的那样,<a target="_blank" rel="noopener" href="https://developer.android.com/training/camera/photobasics.html#TaskCaptureIntent">Taking Photos Simply</a>。然而在最近的一次的测试中,我发现并没有那么简单。因为运行了几年的代码竟然发生了 Crash。具体的 log 如下:</p>
<blockquote>
<p>java.lang.SecurityException: Permission Denial: starting Intent { act=android.media.action.IMAGE_CAPTURE cat=[android.intent.category.DEFAULT] flg=0x3 cmp=com.google.android.GoogleCamera/com.android.camera.activity.CaptureActivity clip={text/uri-list U:content://com.imzhiqiang.example.fileprovider/imageCache/tmp_avatar.jpg} (has extras) } from ProcessRecord{bf70afd 18107:com.imzhiqiang.example/u0a108} (pid=18107, uid=10108) with revoked permission android.permission.CAMERA</p>
</blockquote>
<p>看上去是因为没有处理运行时权限导致的 Crash。<strong>Interesting!</strong> 我并没有在 manifest 文件中声明 Camera 的权限,为什么会出现没有处理 Camera 运行时权限的问题呢?随后我想到了可能是引用的 library 中声明了该权限。在 Android Studio 中查看了 Merged Manifest,果然是这样。图中深色背景的权限是我自己声明的,下面的权限是第三方的 library 声明的。</p>
<p><img src="http://ww2.sinaimg.cn/large/006tNc79ly1g425ora0u0j30g309egmv.jpg" alt="permission"></p>
<p>然而这和 Intent 又有什么关系?使用 ACTION_IMAGE_CAPTURE 不是可以避免请求 Camera 权限吗?经过几番周折过后,最后终于在官方文档中找到了答案。</p>
<p><img src="http://ww2.sinaimg.cn/large/006tNc79ly1g425pm6qncj30yg0faq63.jpg" alt="action_image_capture"></p>
<p>虽然很难理解 Google 这样的做法,不过总算找到了问题的根本所在。在对 Camera 权限进行正确的处理后,终于正常运行了。</p>
<p><strong>结论</strong></p>
<ol>
<li>如果没有在 manifest 文件中声明 Camera 权限,使用 ACTION_IMAGE_CAPTURE 不需要对 Camera 权限做运行时权限处理,代码正常运行。如果声明了就必须要做权限处理。</li>
<li>使用 Intent 的 action 时,一定要仔细阅读官方文档,避免类似的风险。</li>
<li>引用第三方 library 时,除了熟悉其内部原理和源码外,还要注意它在 manifest 文件中添加的东西。</li>
</ol>
<p><strong>扩展阅读</strong></p>
<ol>
<li><a target="_blank" rel="noopener" href="https://blog.egorand.me/taking-photos-not-so-simply-how-i-got-bitten-by-action_image_capture/">Taking Photos Not So Simply: How I Got Bitten By ACTION_IMAGE_CAPTURE</a></li>
<li><a target="_blank" rel="noopener" href="https://issuetracker.google.com/issues/37063818"> Use intent ACTION_IMAGE_CAPTURE to launch camera app requires CAMERA permission</a></li>
<li><a target="_blank" rel="noopener" href="https://commonsware.com/blog/2015/06/08/action-image-capture-fallacy.html">The ACTION_IMAGE_CAPTURE Fallacy</a></li>
</ol>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color4">Image Capture</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2017/09/04/action-image-capture-issue/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-Cache-in-Glide" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2017/03/05/Cache-in-Glide/">Glide中的缓存</a>
</h1>
<a href="/2017/03/05/Cache-in-Glide/" class="archive-article-date">
<time datetime="2017-03-05T07:49:32.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2017-03-05</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<p>本文主要介绍了如何配置和管理 Glide 中的缓存,其中大部分内容都可以直接在官方 Wiki 中找到,这里只是进行了整理和汇总。言归正传,Glide 支持图片的二级缓存(并不是三级缓存,因为从网络加载并不属于缓存),即内存缓存和磁盘缓存。</p>
<h4 id="磁盘缓存"><a href="#磁盘缓存" class="headerlink" title="磁盘缓存"></a>磁盘缓存</h4><p>一般的图片缓存指的就是磁盘缓存,把网络上的图片缓存到本地,这样就不需要每次都从网络加载,既提高了加载速度,又为用户节省了流量。Glide 在默认情况下是开启磁盘缓存的,而且提供了丰富的 API 来让开发者自己配置和管理磁盘缓存。</p>
<p><strong>缓存位置和大小</strong><br>开发者可以通过构建一个自定义的<a target="_blank" rel="noopener" href="https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/module/GlideModule.java">GlideModule</a>来配置 Glide 磁盘缓存的位置和大小。最简单的方法如下:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DiskCacheMoudle</span> <span class="keyword">implements</span> <span class="title">GlideModule</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">applyOptions</span><span class="params">(Context context, GlideBuilder builder)</span> </span>{</span><br><span class="line"> builder.setDiskCache(</span><br><span class="line"> <span class="keyword">new</span> InternalCacheDiskCacheFactory(context, <span class="string">"glide_cache"</span>, <span class="number">100</span> * <span class="number">1024</span> * <span class="number">1024</span>));</span><br><span class="line"> <span class="comment">//builder.setDiskCache(</span></span><br><span class="line"> <span class="comment">// new ExternalCacheDiskCacheFactory(context, "glide_cache", 100 * 1024 * 1024));</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerComponents</span><span class="params">(Context context, Glide glide)</span> </span>{</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其中 InternalCache 和 ExternalCache 都最多接收 3 个参数:第一个参数为 Context,没啥好说的;第二个为缓存的目录名称;第三个为缓存大小,单位是 Byte。它们之间唯一的不同就在于 InternalCache 构建的缓存是在应用的内部储存,而 ExternalCache 则是在外部储存。内部储存中的缓存文件是其他应用程序是无法获取到的,更加安全。关于内部储存和外部储存的更多内容,请<a target="_blank" rel="noopener" href="https://developer.android.google.cn/guide/topics/data/data-storage.html">点击这里</a>查看官方文档。</p>
<p>如果不想把缓存放在上面的两个位置怎么办?Glide 当然也支持,具体通过 DiskLruCacheFactory 来实现:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">builder.setDiskCache(</span><br><span class="line"> <span class="keyword">new</span> DiskLruCacheFactory(<span class="keyword">new</span> DiskLruCacheFactory.CacheDirectoryGetter() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> File <span class="title">getCacheDirectory</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> getMyCacheLocationBlockingIO();</span><br><span class="line"> }</span><br><span class="line"> }), <span class="number">100</span> * <span class="number">1024</span> * <span class="number">1024</span>);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>Note: getMyCacheLocationBlockingIO 方法返回的文件不能为空,而且必须是一个已经创建好的文件目录,不可以是文件。</p>
</blockquote>
<p><strong>缓存策略</strong><br>与其他图片加载库的缓存机制不同,Glide 缓存图片时默认只缓存最终加载的那张图片。举个栗子,你要加载的图片分辨率为 1000x1000,但是最终显示该图片的 ImageView 大小只有 500x500,那么 Glide 就会只缓存 500x500 的小图。这也是在从磁盘缓存中加载图片时 Glide 比 Picasso 快的原因。Glide 目前提供了四种缓存策略:</p>
<ol>
<li>DiskCacheStrategy.NONE 不缓存文件</li>
<li>DiskCacheStrategy.SOURCE 只缓存原图</li>
<li>DiskCacheStrategy.RESULT 只缓存最终加载的图(默认的缓存策略)</li>
<li>DiskCacheStrategy.ALL 同时缓存原图和结果图</li>
</ol>
<p><strong>缓存算法</strong><br>在 Glide 中磁盘缓存默认使用的是 LRU(Least Recently Used)算法。如果你想使用其他的缓存算法,就只能通过实现 DiskCache 接口来完成了。</p>
<h4 id="内存缓存"><a href="#内存缓存" class="headerlink" title="内存缓存"></a>内存缓存</h4><p>使用内存缓存可以获得更快的图片加载速度,因为减少了耗时的 IO 操作。众所周知,Bitmap 是 Android 中的内存大户,频繁的创建和回收 Bitmap 必然会引起内存抖动。Glide 中有一个叫做 BitmapPool 的类,可以复用其中的 Bitmap 对象,从而避免 Bitmap 对象的创建,减小内存开销。当配置内存缓存时,我们也应该同时配置 BitmapPool 的大小。具体方法也是通过自定义的 GlideModule 来实现的:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">builder.setMemoryCache(<span class="keyword">new</span> LruResourceCache(yourSizeInBytes));</span><br><span class="line">builder.setBitmapPool(<span class="keyword">new</span> LruBitmapPool(sizeInBytes));</span><br></pre></td></tr></table></figure>
<p>一般情况下,开发者是不需要自己去指定它们的大小的,因为 Glide 已经帮我们做好了。默认的内存缓存和 bitmapPool 的大小由<a target="_blank" rel="noopener" href="https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java">MemorySizeCalculator</a>根据当前设备的屏幕大小和可用内存计算得到。同时 Glide 还支持动态的缓存大小调整,在存在大量图片的 Activity/Fragment 中,开发者可以通过 setMemoryCategory 方法来提高 Glide 的内存缓存大小,从而加快图片的加载速度。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Glide.get(context).setMemoryCategory(MemoryCategory.HIGH);</span><br></pre></td></tr></table></figure>
<p>MemoryCategory 有 3 个值可供选择:</p>
<ol>
<li>MemoryCategory.HIGH(初始缓存大小的 1.5 倍)</li>
<li>MemoryCategory.NORMAL(初始缓存大小的 1 倍)</li>
<li>MemoryCategory.LOW(初始缓存大小的 0.5 倍)</li>
</ol>
<p>在有些情况下我们不希望做内存缓存(比如加载 GIF 图片),这个时候可以调用 skipMemoryCache(true)方法跳过内存缓存。</p>
<h4 id="如何缓存动态-Url-的图片"><a href="#如何缓存动态-Url-的图片" class="headerlink" title="如何缓存动态 Url 的图片"></a>如何缓存动态 Url 的图片</h4><p>一般情况下我们从网络上获取到的图片 Url 都是静态的,即一张图片对应一个 Url。那么如果是一张图片对应多个 Url 呢?缓存不就没有意义了。因为图片加载库都是拿图片的 Url 来作为缓存的 key 的,Glide 也不例外,只是会更加复杂一些。如果你开启了 Glide 的 log,就会在控制台看到 Glide 是如何指定缓存 key 的。关于如何打开 log,请参考<a target="_blank" rel="noopener" href="http://www.jianshu.com/p/9bd6efca8724">这篇文章</a>。一般来说,Glide 的 key 由图片的 url、view 的宽和高、屏幕的尺寸大小和 signature 组成。</p>
<p>在什么情况下才会出现动态的 Url 呢?一个很典型的例子就是因为图片的安全问题在原来图片的 Url 后面加上访问凭证。访问凭证与时间关联,这样一来,在不同时间同一图片的 Url 就会不同,缓存就会失效。以七牛的私有空间为例,我们来看看如何去缓存这类图片。从七牛关于私有空间的<a target="_blank" rel="noopener" href="https://developer.qiniu.com/kodo/manual/download-token">文档</a>中可以得到:最终的 Url = 原 Url + ?e=过期时间 + token=下载凭证。那么就只需要在 Glide 缓存时将 Url 中“?”后面的字符串截去就可以了。</p>
<p>首先新建一个叫做 QiNiuImage 的类:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">QiNiuImage</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> String imageUrl;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">QiNiuImage</span><span class="params">(String imageUrl)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.imageUrl = imageUrl;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getImageUrl</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> imageUrl;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getImageId</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (imageUrl.contains(<span class="string">"?"</span>)) {</span><br><span class="line"> <span class="keyword">return</span> imageUrl.substring(<span class="number">0</span>, imageUrl.lastIndexOf(<span class="string">"?"</span>));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> imageUrl;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其中 getImageUrl 方法返回真实的 Url,getImageId 方法返回未添加下载凭证前的 Url。<br>然后再自定义一个实现<a target="_blank" rel="noopener" href="https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/load/model/ModelLoader.java">ModelLoader</a>接口的 QiNiuImageLoader:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">QiNiuImageLoader</span> <span class="keyword">implements</span> <span class="title">StreamModelLoader</span><<span class="title">QiNiuImage</span>> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> DataFetcher<InputStream> <span class="title">getResourceFetcher</span><span class="params">(<span class="keyword">final</span> QiNiuImage model, <span class="keyword">int</span> width,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">int</span> height)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> HttpUrlFetcher(<span class="keyword">new</span> GlideUrl(model.getImageUrl())) {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getId</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> model.getImageId();</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Factory</span> <span class="keyword">implements</span> <span class="title">ModelLoaderFactory</span><<span class="title">QiNiuImage</span>, <span class="title">InputStream</span>> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> ModelLoader<QiNiuImage, InputStream> <span class="title">build</span><span class="params">(Context context,</span></span></span><br><span class="line"><span class="function"><span class="params"> GenericLoaderFactory factories)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> QiNiuImageLoader();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">teardown</span><span class="params">()</span> </span>{ <span class="comment">/* no op */</span> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其中 HttpUrlFetcher 的 getId 方法就是组成缓存的 key 的重要部分。这也是我们的核心原理。<br>将这个 ModelLoader 注册到 GlideModule 中,并在 AndroidManifest.xml 中注册:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">QiNiuModule</span> <span class="keyword">implements</span> <span class="title">GlideModule</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">applyOptions</span><span class="params">(Context context, GlideBuilder builder)</span> </span>{</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerComponents</span><span class="params">(Context context, Glide glide)</span> </span>{</span><br><span class="line"> glide.register(QiNiuImage.class, InputStream.class, <span class="keyword">new</span> QiNiuImageLoader.Factory());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><meta-data</span><br><span class="line"> android:name="com.yourpackagename.QiNiuModule"</span><br><span class="line"> android:value="GlideModule"/></span><br></pre></td></tr></table></figure>
<p>最后只需要在加载此类图片时,使用下面这段代码就可以了。即使图片的 token 更换了也不会重新从网络上下载而是直接读取本地缓存。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Glide.with(context)</span><br><span class="line"> .load(<span class="keyword">new</span> QiNiuImage(imageUrl)</span><br><span class="line"> .into(imageView);</span><br></pre></td></tr></table></figure>
<p>参考资料:</p>
<ol>
<li><a target="_blank" rel="noopener" href="https://github.com/bumptech/glide/issues/607">https://github.com/bumptech/glide/issues/607</a></li>
<li><a target="_blank" rel="noopener" href="https://github.com/bumptech/glide/issues/501">https://github.com/bumptech/glide/issues/501</a></li>
</ol>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color1">Cache</a>
</li>
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color1">Glide</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2017/03/05/Cache-in-Glide/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-Several-important-classes-in-Android-media-framework" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/09/24/Several-important-classes-in-Android-media-framework/">Android多媒体框架中几个重要的类</a>
</h1>
<a href="/2016/09/24/Several-important-classes-in-Android-media-framework/" class="archive-article-date">
<time datetime="2016-09-24T02:10:09.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2016-09-24</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<p>与 iOS 中强大的 AVFoundation 框架相比,Android framework 中提供的有关多媒体处理的类可谓屈指可数,但总比没有好吧。今天我们就来谈谈这几个类。</p>
<blockquote>
<p>这里提到的多媒体处理主要是指音视频处理。包括音视频的裁剪、合并;视频画面的各种变换,旋转、缩放、翻转;视频滤镜;音视频的播放,快速、慢速、倒序播放等等。</p>
</blockquote>
<p>主要涉及到的类有:</p>
<ol>
<li>MediaExtractor:媒体提取器</li>
<li>MediaCodec:编解码器</li>
<li>MediaMuxer:媒体混合器</li>
<li>MediaMetadataRetriever: 获取音视频信息的类</li>
<li>MediaFormat: 包含音视频帧信息的类</li>
<li>GLSurfaceView: 展示 openGL 渲染的 View</li>
<li>OpenGL 相关的类</li>
</ol>
<p>MediaExtractor 在 Android4.1(API16)加入。可以从一段音视频中提取出一帧一帧的数据,与 MediaMuxer 配合使用可以完成视频的裁剪和合并,与 MediaCodec、GLSurfaceView 配合使用可以完成视频的播放。</p>
<p>MediaCodec 在 Android4.1(API16)加入。在 Android4.3(API18)提供输入可以为 Surface。在 Android5.0(API21)又增加了异步处理模式。它是一个低等级的媒体编解码器,可以作为编码器,也可以作为解码器。 可攻可受,嘿嘿嘿。是音视频处理中最为核心的类。</p>
<p>由于相关文档在以前不是很完善,来自 Android 媒体团队的 fadden(现已不在)维护了一个网站 <a target="_blank" rel="noopener" href="http://bigflake.com/mediacodec/">http://bigflake.com/mediacodec/</a> 。上面有大量的相关资源。此外在 stackoverflow 上面只要是 MeidaCodec 相关的问题随处可见 fadden 的身影。感谢 fadden。现在官方文档已经相当详细了,不过都是英文的,对于阅读困难的人,国内也有人进行了翻译。地址在[这里](<a target="_blank" rel="noopener" href="http://www.cnblogs.com/xiaoshubao/archive/2016/04/11/5368183.html%EF%BC%89">http://www.cnblogs.com/xiaoshubao/archive/2016/04/11/5368183.html)</a> 。</p>
<p>MediaMuxer 在 Android4.3(API18)。可以合成 MP4 格式的视频,输入源通常为从 MediaExtractor 或者 MediaCodec 提供的已编码的数据。</p>
<p>MediaMetadataRetriever 主要用来获取视频的方向信息。在合成视频时,可纠正视频方向。此外还可以获取视频某一帧画面的 bitmap,前提必须是 android 支持的视频格式。</p>
<p>MediaFormat 内部持有一个包含音视频帧信息的 map。</p>
<p>GLSurfaceView 可与 MediaPlayer 配合,完成视频变换的各种效果实时预览。</p>
<p>OpenGL 是一门单独的技术,然而关于其在 Android 中使用的文档和列子实在太少。唯一的一本书《OpenGL ES 应用开发实践指南 Android 卷》在网上也买不到,只能去淘宝买复印版。。。</p>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color4">多媒体</a>
</li>
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color1">MediaCodec</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2016/09/24/Several-important-classes-in-Android-media-framework/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-How-to-debug-glide" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/12/01/How-to-debug-glide/">如何调试Glide加载图片</a>
</h1>
<a href="/2015/12/01/How-to-debug-glide/" class="archive-article-date">
<time datetime="2015-12-01T07:23:23.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2015-12-01</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>与其他图片加载库不同,在 Glide 加载图片的过程中默认是没有任何 log 输出的。这样使得加载失败的原因难以调试。到底是网络错误还是图片根本就不存在亦或者解码出错,我们不得而知。当然官方也给出了调试的方法,这篇文章就来介绍下如何调试 Glide 加载图片,内容主要是对官方 wiki 的翻译。</p>
<a class="article-more-a" href="/2015/12/01/How-to-debug-glide/#more">more >></a>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color1">Glide</a>
</li>
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color3">调试</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2015/12/01/How-to-debug-glide/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-An-accident-about-SwipeRefreshLayout-in-support-v4-package" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/11/19/An-accident-about-SwipeRefreshLayout-in-support-v4-package/">记录一次v4包中SwipeRefreshLayout的“坑爹”事件</a>
</h1>
<a href="/2015/11/19/An-accident-about-SwipeRefreshLayout-in-support-v4-package/" class="archive-article-date">
<time datetime="2015-11-19T05:29:16.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2015-11-19</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<p>当 android support v4 包和 v7 包版本不一样时,v4 包中的 SwipeRefreshLayout 和 v7 包中的 RecyclerView 不能很好地一起工作,会导致 SwipeRefreshLayout 下拉刷新时动画卡住的情况,类似下面的情况:</p>
<p><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g425li2eiwg30dc0a0u0x.gif" alt="sample"></p>
<p>详情请参考:</p>
<p><a target="_blank" rel="noopener" href="http://stackoverflow.com/questions/33032036/swiperefreshlayout-freezes-on-api-4-2-2%E3%80%82">http://stackoverflow.com/questions/33032036/swiperefreshlayout-freezes-on-api-4-2-2。</a></p>
<a class="article-more-a" href="/2015/11/19/An-accident-about-SwipeRefreshLayout-in-support-v4-package/#more">more >></a>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color2">坑</a>
</li>
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color4">SwipeRefreshLayout</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2015/11/19/An-accident-about-SwipeRefreshLayout-in-support-v4-package/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>