-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1076 lines (804 loc) · 72.8 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">
<title>crazymongo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="description">
<meta property="og:type" content="website">
<meta property="og:title" content="crazymongo">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="crazymongo">
<meta property="og:description">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="crazymongo">
<meta name="twitter:description">
<link rel="alternative" href="/atom.xml" title="crazymongo" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="/css/style.css" type="text/css">
</head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">crazymongo</a>
</h1>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
<a id="nav-search-btn" class="nav-icon" title="Search"></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-Android-Activity管理" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/04/20/Android-Activity管理/" class="article-date">
<time datetime="2016-04-20T11:00:13.000Z" itemprop="datePublished">2016-04-20</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/04/20/Android-Activity管理/">Android_Activity管理</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>我们在开发应用的过程中经常会遇到这样一个问题,当我们在页面A时,需要通过A进入页面B,然后在进入页面C等等,在业务处理过程中,允许客户回退到上一个页面,即每一个过程页面暂时都不能关闭。当我们在页面C中处理完业务然后,要求直接回到页面A,且中间涉及的页面也同时被关掉。</p>
<p>非常常见的一种处理方法就是建立一个Activity的管理类,把业务所经过的页面按顺序放到一个栈中,当需要返回栈底页面时,依次取出栈中页面进行销毁,直到需要恢复的页面。</p>
<p>其实,我们完全没有必要这样做,因为系统本身就维护了一个类似的Activity回退栈。我们可以通过简单的几步就可以达到效果。</p>
<p>第一种方式就是把起始Activity的启动模式设置为singleTask,在需要返回到起始页的页面调用startActivity方法就可以了。</p>
<p>第二种方式就更简单了,通过设置Intent的标记实现,intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2016/04/20/Android-Activity管理/" data-id="cin8r00lw002rbomfer5vm1u2" class="article-share-link">Share</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Activity管理/">Activity管理</a></li></ul>
</footer>
</div>
</article>
<article id="post-Android-launchMode分析" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/04/18/Android-launchMode分析/" class="article-date">
<time datetime="2016-04-18T10:10:11.000Z" itemprop="datePublished">2016-04-18</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/04/18/Android-launchMode分析/">Android_launchMode分析</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>我们知道Android的luanchMode有四种,分别是:standard, singleTop, singleTask和singleInstance。下面我们将一次介绍这几种启动模式</p>
<p>##standard</p>
<p>Activity默认的启动模式就是standard,每当用户调用startActivity启动这个Activity时,系统都会创建一个新的Activity实例。</p>
<p>##singleTop</p>
<p>singleTop其实和standard几乎一样,使用singleTop的Activity也可以创建很多个实例。唯一的区别就是,如果调用的目标Activity已经位于调用者的Task栈顶,则不创建新实例,而是使用当前的这个Activity实例,并调用这个实例的onNewIntent方法。</p>
<p>##singleTask</p>
<p>使用singleTask启动模式的Activity在系统中只会存在一个实例。如果这个实例已经存在,intent就好通过onNewIntent传递到这个Activity。否则创建新的Activity实例。</p>
<p>在同一程序内,如果系统中不存在singleTask Activity的实例,那么就需要创建这个Activity的实例,并将这个实例放入和调用者相同的Task中(可以通过android:taskAffinity属性放入不同的Task中),并位于栈顶。如果Activity的实例已经存在,那么在Activity回退栈中,所有位于该Activity上面的Activity实例都将被销毁掉(销毁过程会调用Activity生命周期函数),这样使得singleTask Activity实例位于栈顶。于此同时,Intent会通过onNewIntent函数传递到这个Activity实例。</p>
<p>在不同程序之间,如果系统中不存在singleTask Activity的实例,那么将创建一个新的Task,然后要创建Activity的实例,将其放入新的Task中。如果singleTask Activity所在的应用进程存在,但是该Activity实例不存在,那么从别的应用启动这个Activity,新的Activity实例会被创建,并放入到所属进程所在的Task中,并位于栈顶位置。更复杂的一种情况,如果singleTask Activity实例存在,从其他程序被启动,那么这个Activity所在的Task会被移到顶部,并且在这个Task中,位于这个Activity实例之上的所有Activity将会被正常销毁掉。如果我们按返回键,那么我们首先会回退到这个task中的其他Activity,直到当前Task的Activity回退栈为空时,才返回到调用者的task。</p>
<p>##singleInstance</p>
<p>这个模式和singleTask差不多,因为他们在系统中都只有一份实例。唯一不同的就是存放singleInstance Activity实例的Task只能存放一个该模式的Activity实例,其它任何的Activity实例都无法进入到这个Task中。注意:从任务管理器中进入应用,按返回键无法回退到上一个task中。</p>
<p>默认情况下,除了launchMode为singleInstance的Activity被单独放在一个task中,其它启动方式的Activity实例被放到同一个task中。</p>
<p>由于在不同的任务栈中,导致launchMode为singleInstance的Activity实例的onActivityResult函数调用失败。</p>
<p>可以通过adb shell dumpsys activity命令查看相关信息</p>
<p>参考:<a href="http://droidyue.com/blog/2015/08/16/dive-into-android-activity-launchmode/" target="_blank" rel="external">http://droidyue.com/blog/2015/08/16/dive-into-android-activity-launchmode/</a></p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2016/04/18/Android-launchMode分析/" data-id="cin8r00kv0025bomf0pc1mfa9" class="article-share-link">Share</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Android-launchMode/">Android launchMode</a></li></ul>
</footer>
</div>
</article>
<article id="post-Java编程原则" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/04/08/Java编程原则/" class="article-date">
<time datetime="2016-04-08T06:47:23.982Z" itemprop="datePublished">2016-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/04/08/Java编程原则/">Java编程原则</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p><strong>开-闭原则</strong></p>
<p>一个软件实体应对对扩展开放,对修改关闭。其中抽象化是关键。<br>“开-闭”原则如果从另外一个角度讲述,就是所谓的“对可变性的封装原则”,也就是找到一个系统的可变因素,将之封装起来。<br>“对可变性的封装原则”意味着两点:<br>(1)一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。同一种可变性的不同表象意味着同一个继承等级结构中的具体子类。继承应当被看做是封装变化的方法,而不应当被认为是从一般的对象生成特殊的对象的方法。<br>(2)一种可变性不应当与另一种可变性混合在一起</p>
<p><strong>里氏代换原则</strong></p>
<p>一个软件实体如果使用的是一个基类的话,那么一定适用于其子类,而且它根本不能觉察出基类对象和子类对象的区别。<br>里氏代换原则是继承复用的基石。只有当子类可以替换掉基类,软件单位的功能不会受到影响时,基类才能真正被复用,而子类也才能够在基类的基础上增加新的行为。</p>
<p><strong>依赖倒转原则</strong></p>
<p>实现“开-闭”原则的关键是抽象化,并且从抽象化导出具体实现。如果说“开-闭”原则是面向对象设计的目标的话,依赖倒转原则就是这个面向对象设计的主要机制。<br>依赖倒转原则讲的是:要依赖于抽象,不要依赖于具体。<br>依赖倒转原则是COM、CORBA、JavaBean以及EJB等构建设计模型背后的基本原则。<br>在面向对象里,两个类之间可以发生三种不同的依赖(耦合)关系:</p>
<ul>
<li><p>零耦合:如果两个类没有耦合关系,就称为零耦合。</p>
</li>
<li><p>具体耦合:具体性耦合发生在两个具体的(可实例化的)类之间,经由一个类对另一个类的直接引用造成。</p>
</li>
<li><p>抽象耦合:发生在一个具体类和一个抽象类(或接口)之间,使两个必须发生关系的类之间存在最大的灵活性。</p>
</li>
</ul>
<p>依赖倒转原则要求客户端依赖于抽象耦合。依赖倒转原则的表述是:抽象不应该依赖细节;细节应当依赖于抽象。另一种表述是:要针对接口编程,不要针对实现编程。针对接口编程的意思就是说,因应当使用Java接口和抽象Java类进行变量的类型声明、参量的类型声明、方法的返回类型声明,以及数据类型的转换等。要保证做到这一点,一个具体Java类应当只实现Java接口和抽象Java类中声明过的方法,而不应当给出多余的方法。</p>
<p>变量被声明时的类型叫做变量的静态类型,变量所引用的对象的真实类型叫做变量的实际类型。在很多情况下,一个Java程序需要引用一个对象。这个时候,如果这个对象有一个抽象类型的话,应当使用抽象类型作为变量的静态类型。这就是针对接口编程的含义。</p>
<p><strong>接口隔离原则</strong></p>
<p>接口隔离原则讲的是:使用多个专门的接口比使用单一的总接口要好。换言之,从一个客户类的角度来讲:一个类对另一个类的依赖性应当是建立在最小接口上的。</p>
<p>一个接口相当于剧本中的一个角色,而此角色在一个舞台上由哪一个演员来演则相当于接口的实现。因此,一个接口应带简单地代表一个角色。如果系统涉及到多个角色的话,那么每一个角色应当由一个特定的接口代表。</p>
<p><strong>聚合复用原则</strong></p>
<p>聚合复用原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。这个设计原则有另一个更简短的表述:要尽量使用聚合,尽量不要使用继承。</p>
<p>聚合复用的好处:</p>
<ul>
<li><p>新对象存取成分对象的唯一方法是通过成分对象的接口。</p>
</li>
<li><p>这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的。</p>
</li>
<li><p>这种复用支持包装。</p>
</li>
<li><p>每一个新的类可以将焦点集中在一个任务上。</p>
</li>
<li><p>这种复用可以在运行时间内动态进行,新对象可以动态地引用与成分对象类型相同的对象。</p>
</li>
</ul>
<p>继承复用的好处:</p>
<ul>
<li><p>新的实现较为容易,因为父类的大部分功能可以通过继承关系自动进入子类。</p>
</li>
<li><p>修改或扩展继承而来的实现较为容易。</p>
</li>
</ul>
<p>继承复用的缺点:</p>
<ul>
<li><p>继承复用破坏包装,因为继承将父类的实现细节暴露给子类。由于父类的内部细节常常是对子类透明的,因此这种复用是透明的复用,又称“白箱”复用。</p>
</li>
<li><p>如果父类的实现发生改变,那么子类的实现也不得不发生改变。因此,一个基类发生改变时,这种改变会像水中投入石子引起的水波一样,将变化一圈一圈地传导到一级一级的子类,使设计师不得不相应地改变这些子类,以适应父类的变化。</p>
</li>
<li><p>从父类继承而来的实现是静态的,不可能在运行时间内发生改变,因此没有足够的灵活性。</p>
</li>
</ul>
<p><strong>迪米特法则</strong></p>
<p>迪米特法则又叫最少知识原则,就是说,一个对象应当对其他对象有尽可能少的了解。</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2016/04/08/Java编程原则/" data-id="cin8r00i9000mbomfvyfx035b" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-Java Immutable对象" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/04/08/Java Immutable对象/" class="article-date">
<time datetime="2016-04-08T06:47:23.961Z" itemprop="datePublished">2016-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/04/08/Java Immutable对象/">Java Immutable对象</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>所谓Immutable Object就是那些一旦被创建,它们的状态就不能被改变的Objects,每次对它们的改变都是产生新的Immutable的对象。</p>
<p>举个例子:String和StringBuilder,String是immutable的,每次对于String对象的修改都将产生一个新的String对象,而原来的对象保存不变,而StringBuilder是mutable,因为每次对于它的修改都作用于该对象的本身,并没有产生新的对象。</p>
<p>immutable objects比传统的mutable对象在多线程应用中更具优势,它不仅能够保证对象的状态不被改变,而且还可以不使用锁机制就能被其他线程共享。</p>
<p>实际上JDK本身就自带一些immutable类,比如String、Integer以及其他包装类。</p>
<p>##<strong>如何在Java中写出Immutable的类?</strong></p>
<p>要写出这样的类,需要遵循以下几个原则:</p>
<ul>
<li><p>Immutable对象的状态在创建后就不能发生改变,任何对他的改变都应该产生一个新的对象。</p>
</li>
<li><p>Immutable类的所有属性都应该是final的。</p>
</li>
<li><p>对象必须被正确的创建,比如:对象引用在对象创建过程中不能泄露。</p>
</li>
<li><p>对象应该是final的,以此来限制子类继承父类,以避免改变父类的Immutable特性。</p>
</li>
<li><p>如果类中包含mutable类对象,那么返回给客户端的时候,返回该对象的一个拷贝,而不是该对象本身。</p>
</li>
</ul>
<p>##<strong>使用Immutable类的好处</strong></p>
<ul>
<li><p>Immutable对象是线程安全的,可以不用被synchronize修饰就能在并发环境中共享</p>
</li>
<li><p>Immutable对象简化了程序开发,因为它无需使用额外的锁机制就可以在线程间共享</p>
</li>
</ul>
<p>当然使用Immutable类也有一个缺点,就是制造大量垃圾。</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2016/04/08/Java Immutable对象/" data-id="cin8r00jq001ibomfm9jb7cyk" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-HashSet和HashMap" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/01/13/HashSet和HashMap/" class="article-date">
<time datetime="2016-01-13T09:59:07.000Z" itemprop="datePublished">2016-01-13</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/01/13/HashSet和HashMap/">HashSet、HashMap和Hashtable</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p><strong>HashSet</strong></p>
<p>HashSet实现了Set接口,内部由哈希表(实际上是HashMap实例)支持。HashSet不保证集合的迭代顺序,特别是它不保证该顺序恒久不变。HashSet允许null元素。</p>
<p>HashSet是非同步的,如果多个线程同时访问集合,且至少一个线程修改这个集合,那么这个集合在外部必须被同步。避免偶然地不同步访问集合发生,我们在创建set时最好使用Collections.synchronizedSet(new HashSet(…))方法。</p>
<p>通过HashSet的iterator()方法获得的迭代器是“fail-fast”:在获取迭代器之后,除了通过迭代器本身移除元素之外,其它任何对集合的修改都将导致迭代器抛出ConcurrentModificationException。因此,面对并发修改,迭代器很快就会失败,而不冒将来在某个不确定时间发生任何不确定行为的风险。</p>
<p><strong>HashMap</strong></p>
<p>HashMap是基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许null值和null键。(除了非同步和允许使用null之外,HashMap类与Hashtable大致相同)。HashMap不保证映射的顺序,特别是它不保证顺序恒久不变。</p>
<p>有两个参数影响HashMap的性能,及初识容量和加载因子。容量是哈希表中桶的数量,初识容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对哈希表进行rehash操作(即重建内部数据结构),从而哈希表将具有大约两倍的容量。</p>
<p>通常,默认加载因子(.75)在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本。</p>
<p>HashMap是非同步的,如果多个线程同时访问集合,且至少一个线程修改这个集合,那么这个集合在外部必须被同步。避免偶然地不同步访问集合发生,我们在创建set时最好使用Collections.synchronizedMap(new HashMap(…))方法。</p>
<p>由所有此类的“collection 视图方法”所返回的迭代器都是快速失败 的:在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒在将来不确定的时间发生任意不确定行为的风险。</p>
<p><strong>Hashtable</strong></p>
<p>Hashtable实现一个哈希表,该哈希表将键映射到相应的值。任何非null对象都可以作为键或值。</p>
<p>为了成功地在哈希表中存储和获取对象,用作键的对象必须实现hashCode方法和equals方法。</p>
<p>Hashtable是同步的,如果程序不需要线程安全的哈希表实现,推荐使用HashMap。如果需要线程安全、高并发的哈希表实现,推荐使用ConcurrentHashMap。</p>
<p><strong>TreeMap</strong></p>
<p>TreeMap是基于红黑树(Red-Black tree)的NavigableMap实现。该映射根据其键的自然顺序进行排序,或者根据创建时提供的Comparator进行排序,具体取决于使用的构造方法。</p>
<p>TreeMap为方法contrainKey、get、put和remove等操作提供受保证的log(n)时间开销。</p>
<p><strong>TreeSet</strong></p>
<p>TreeSet是基于TreeMap的NavigableSet实现。使用元素的自然顺序对元素进行排序,或者根据创建Set时提供的Comparator进行排序。此实现为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销。</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2016/01/13/HashSet和HashMap/" data-id="cin8r00jy001mbomfvmrgcsfl" class="article-share-link">Share</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/HashSet-HashMap-Hashtable/">HashSet HashMap Hashtable</a></li></ul>
</footer>
</div>
</article>
<article id="post-Android-UniversalImageLoader-MemoryCache" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2016/01/03/Android-UniversalImageLoader-MemoryCache/" class="article-date">
<time datetime="2016-01-03T11:21:37.000Z" itemprop="datePublished">2016-01-03</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2016/01/03/Android-UniversalImageLoader-MemoryCache/">Android-UniversalImageLoader-MemoryCache</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>UniversalImageLoader提供多种内存缓存策略,大致分为三类:</p>
<ul>
<li>内存缓存大小固定的内存缓存策略</li>
<li>可以由用户设定内存缓存空间大小的缓存策略</li>
<li>没有内存大小限定的缓存策略</li>
</ul>
<p>首先,我们先来学习一下内存缓存大小固定的内存缓存策略,其中框架提供了多种实现,包括:FIFOLimitedMemoryCache, LargestLimitedMemoryCache, UsingFreqLimitedMemoryCache, LRULimitedMemoryCache。这几个类都继承了抽象类LimitedMemoryCache。而LimitedMemoryCache派生自BaseMemoryCache。</p>
<p>抽象类BaseMemoryCache基本实现了对象的软缓存,其内部通过HashMap<string, reference<bitmap="">>())的对象来保存对象引用。</string,></p>
<p>抽象类LimitedMemoryCache基本实现了对象的硬缓存,其内部通过LinkedList<bitmap>的对象来保存对象引用。该类规定了最大的内存缓存大小为16M。当缓存大小超过这个值的时候,就会根据某种方式移除某些对象。子类需要提供移除某些对象的策略。</bitmap></p>
<p>FIFOLimitedMemoryCache每次移除最先进入队列的对象,其策略如下:</p>
<pre><code><span class="keyword">private</span> <span class="keyword">final</span> List<Bitmap> queue = Collections.synchronizedList(<span class="keyword">new</span> LinkedList<Bitmap>());
<span class="annotation">@Override</span>
<span class="keyword">protected</span> <span class="function">Bitmap <span class="title">removeNext</span><span class="params">()</span> </span>{
<span class="function"><span class="keyword">return</span> queue.<span class="title">remove</span><span class="params">(<span class="number">0</span>)</span></span>;
}
</code></pre><p>UsingFreqLimitedMemoryCache每次移除使用率最小那个对象,其实现如下:</p>
<pre><code><span class="keyword">private</span> <span class="keyword">final</span> Map<Bitmap, <span class="type">Integer</span>> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, <span class="type">Integer</span>>());
@Override
<span class="keyword">protected</span> Bitmap removeNext() {
<span class="type">Integer</span> minUsageCount = null;
Bitmap leastUsedValue = null;
Set<<span class="built_in">Entry</span><Bitmap, <span class="type">Integer</span>>> entries = usingCounts.entrySet();
synchronized (usingCounts) {
for (<span class="built_in">Entry</span><Bitmap, <span class="type">Integer</span>> <span class="built_in">entry</span> : entries) {
<span class="keyword">if</span> (leastUsedValue == null) {
leastUsedValue = <span class="built_in">entry</span>.getKey();
minUsageCount = <span class="built_in">entry</span>.getValue();
} <span class="keyword">else</span> {
<span class="type">Integer</span> lastValueUsage = <span class="built_in">entry</span>.getValue();
<span class="keyword">if</span> (lastValueUsage < minUsageCount) {
minUsageCount = lastValueUsage;
leastUsedValue = <span class="built_in">entry</span>.getKey();
}
}
}
}
usingCounts.remove(leastUsedValue);
<span class="keyword">return</span> leastUsedValue;
}
</code></pre><p>用户每次调用get(String key)方法时,相对于的对象的使用频率加1。</p>
<p>LargestLimitedMemoryCache每次都会移除内存占用最大的那个对象,其实现如下:</p>
<pre><code><span class="keyword">private</span> <span class="keyword">final</span> Map<Bitmap, <span class="type">Integer</span>> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, <span class="type">Integer</span>>());
@Override
<span class="keyword">protected</span> Bitmap removeNext() {
<span class="type">Integer</span> maxSize = null;
Bitmap largestValue = null;
Set<<span class="built_in">Entry</span><Bitmap, <span class="type">Integer</span>>> entries = valueSizes.entrySet();
synchronized (valueSizes) {
for (<span class="built_in">Entry</span><Bitmap, <span class="type">Integer</span>> <span class="built_in">entry</span> : entries) {
<span class="keyword">if</span> (largestValue == null) {
largestValue = <span class="built_in">entry</span>.getKey();
maxSize = <span class="built_in">entry</span>.getValue();
} <span class="keyword">else</span> {
<span class="type">Integer</span> <span class="built_in">size</span> = <span class="built_in">entry</span>.getValue();
<span class="keyword">if</span> (<span class="built_in">size</span> > maxSize) {
maxSize = <span class="built_in">size</span>;
largestValue = <span class="built_in">entry</span>.getKey();
}
}
}
}
valueSizes.remove(largestValue);
<span class="keyword">return</span> largestValue;
}
</code></pre><p>LRULimitedMemoryCache每次移除最近使用次数最少的那个(及LRU算法),其实现如下:</p>
<pre><code><span class="label">private</span> final <span class="preprocessor">Map</span><<span class="keyword">String, </span><span class="keyword">Bitmap> </span>lruCache = Collections.synchronizedMap(new LinkedHashMap<<span class="keyword">String, </span><span class="keyword">Bitmap>(INITIAL_CAPACITY, </span>LOAD_FACTOR, true))<span class="comment">;</span>
<span class="comment">@Override</span>
<span class="label">protected</span> <span class="keyword">Bitmap </span>removeNext() {
<span class="keyword">Bitmap </span>mostLongUsedValue = null<span class="comment">;</span>
synchronized (lruCache) {
<span class="keyword">Iterator<Entry<String, </span><span class="keyword">Bitmap>> </span><span class="keyword">it </span>= lruCache.entrySet().<span class="keyword">iterator();
</span> <span class="preprocessor">if</span> (<span class="keyword">it.hasNext()) </span>{
<span class="preprocessor">Entry</span><<span class="keyword">String, </span><span class="keyword">Bitmap> </span><span class="preprocessor">entry</span> = <span class="keyword">it.next();
</span> mostLongUsedValue = <span class="preprocessor">entry</span>.getValue()<span class="comment">;</span>
<span class="keyword">it.remove();
</span> }
}
return mostLongUsedValue<span class="comment">;</span>
}
</code></pre><p>接下来,我们将学习可以由用户设定内存缓存空间大小的缓存策略,框架目前只提供了LruMemoryCache实现,其内部实现原理跟LRULimitedMemoryCache一样,都是通过LinkedHashMap实现的,我们在此就不做过多讲解了。</p>
<p>最后,让我们来看一下没有内存大小限定的缓存策略,框架目前只提供了WeakMemroyCache实现,其内部实现原理就是为每个对象建立一个软引用,这样系统GC可以随时根据需要消耗对象。</p>
<pre><code>@<span class="function">Override
<span class="keyword">protected</span> Reference<Bitmap> <span class="title">createReference</span>(<span class="params">Bitmap <span class="keyword">value</span></span>) </span>{
<span class="keyword">return</span> <span class="keyword">new</span> WeakReference<Bitmap>(<span class="keyword">value</span>);
}
</code></pre>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2016/01/03/Android-UniversalImageLoader-MemoryCache/" data-id="cin8r00ky0028bomfiyeem30m" class="article-share-link">Share</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Android-UniversalImageLoader-MemoryCache/">Android UniversalImageLoader MemoryCache</a></li></ul>
</footer>
</div>
</article>
<article id="post-Android-Settings类初识" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2015/12/25/Android-Settings类初识/" class="article-date">
<time datetime="2015-12-25T03:57:49.000Z" itemprop="datePublished">2015-12-25</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/12/25/Android-Settings类初识/">Android-Settings类初识</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Settings类的作用主要是提供系统级别的全局设置。</p>
<p>Settings类中包含Intent的Action常量,通过调用可以打开相应的设置界面。例如:</p>
<pre><code>/<span class="keyword">*</span><span class="keyword">*</span>
<span class="keyword">*</span> Activity Action: Show system settings.
<span class="keyword">*</span> <span class="variable"><p></span>
<span class="keyword">*</span> Input: Nothing.
<span class="keyword">*</span> <span class="variable"><p></span>
<span class="keyword">*</span> Output: Nothing.
<span class="keyword">*</span>/
<span class="comment">@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)</span>
public static final String ACTION_SETTINGS = <span class="string">"android.settings.SETTINGS"</span>;
/<span class="keyword">*</span><span class="keyword">*</span>
<span class="keyword">*</span> Activity Action: Show settings to allow configuration of wireless controls
<span class="keyword">*</span> such as Wi-Fi, Bluetooth and Mobile networks.
<span class="keyword">*</span> <span class="variable"><p></span>
<span class="keyword">*</span> In some cases, a matching Activity may not exist, so ensure you
<span class="keyword">*</span> safeguard against this.
<span class="keyword">*</span> <span class="variable"><p></span>
<span class="keyword">*</span> Input: Nothing.
<span class="keyword">*</span> <span class="variable"><p></span>
<span class="keyword">*</span> Output: Nothing.
<span class="keyword">*</span>/
<span class="comment">@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)</span>
public static final String ACTION_WIRELESS_SETTINGS =
<span class="string">"android.settings.WIRELESS_SETTINGS"</span>;
</code></pre><p><strong>Settings内部类System</strong></p>
<p>系统设置表,包含各种各样的系统设置,以名值对的形式进行存储。System类提供了一些方便的方法去访问这些个人设置。</p>
<p>通过这个类,我们也可以把应用中的一些需要持久化保存的简单的数据保存到系统设置表,即使应用被卸载了,这些数据仍会存在。恢复出厂化设置,数据就会被清除了。</p>
<pre><code>Settings<span class="class">.System</span><span class="class">.putString</span>(<span class="function"><span class="title">getContentResolver</span><span class="params">()</span></span>, <span class="string">"crazymongo"</span>, <span class="string">"test system store"</span>);
Settings<span class="class">.System</span><span class="class">.getString</span>(<span class="function"><span class="title">getContentResolver</span><span class="params">()</span></span>, <span class="string">"crazymongo"</span>);
</code></pre><p><strong>Settings内部类Secure</strong></p>
<p>Secure system settings, containing system preferences that applications can read but are not allowed to write. These are for preferences that the user must explicitly modify through the system UI or specialized APIs for those values, not modified directly by applications.(就不翻译了,Poor English)</p>
<p><strong>Settings内部类Global</strong></p>
<p>Global system settings, containing preferences that always apply identically to all defined users. Applications can read these but are not allowed to write;like the “Secure” settings, these are for preferences that the user must explicitly modify through the system UI or specialized APIs for those values.</p>
<p><strong>Settings内部类Bookmarks</strong></p>
<p>User-defined bookmarks and shortcuts. The target of each bookmark is an Intent URL, allowing it to be either a web page or a particular application activity.</p>
<p>在查看源码的的过程中发现ContentValues这个类,该类使用一个HashMap<string, object="">存储数据,并封装了一下常用的工具。</string,></p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2015/12/25/Android-Settings类初识/" data-id="cin8r00l8002ebomfoiaxp2tn" class="article-share-link">Share</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Android-Settings/">Android Settings</a></li></ul>
</footer>
</div>
</article>
<article id="post-Android-plugin-for-gradle" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2015/12/22/Android-plugin-for-gradle/" class="article-date">
<time datetime="2015-12-22T09:03:37.000Z" itemprop="datePublished">2015-12-22</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/12/22/Android-plugin-for-gradle/">Android_plugin_for_gradle</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Android构建系统包含一个Android插件工具。Gradle是一个高级的构建工具,可以用来管理依赖,允许用户定义自己的构建逻辑。</p>
<p>The Android plugin for Gradle独立于AS运行。也就是说,我们不仅可以在AS中构建程序,也可以通过本机的命令行或者没有安装AS的机器上构建程序。无论通过哪种构建方式,结果都是相同的。</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2015/12/22/Android-plugin-for-gradle/" data-id="cin8r00ks0024bomfi1i0q31x" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-Class-forName作用" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2015/12/15/Class-forName作用/" class="article-date">
<time datetime="2015-12-15T08:05:44.000Z" itemprop="datePublished">2015-12-15</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/12/15/Class-forName作用/">Class.forName作用</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Class.forName(“classname”)返回的是一个类Class。首先我们要明白在Java里面任何class都要装载在虚拟机上才可运行。这个方法就是用来装载类的(和new不一样,要分清楚)。</p>
<p>如何创建一个类实例?很多人首先想到的就是new这个关键字,没错,使用new关键字确实可以创建我们想要的类实例。不过还有一种方法,如下所示:</p>
<pre><code><span class="comment">//创建一个Person类的实例</span>
<span class="keyword">Class</span> mClass=<span class="keyword">Class</span>.forName(<span class="string">"Person类的完整类名"</span>);
Person person=mClass.newInstance();
</code></pre><p>那么这两种创建类实例的方法有什么不同吗?</p>
<p>首先创建对象的方式不一样,一个使用类加载机制,另一个是创建一个新类。那么为什么会有两种创建对象的方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。</p>
<p>Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。</p>
<p>从JVM的角度看,我们使用new创建一个类实例的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须要保证这个类已经加载,且这个类已经连接了。而完成上面两个步骤的正是forName()方法完成的,这个方法调用了启动类的加载器,即加载Java API的那个加载器。</p>
<pre><code><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">Class</span><?> forName(String className)
<span class="keyword">throws</span> ClassNotFoundException {
<span class="keyword">return</span> forName0(className, <span class="keyword">true</span>,
ClassLoader.getClassLoader(Reflection.getCallerClass()));
}
</code></pre><p>这个加载器也是加载Class的加载器。</p>
<p>现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用class的forName方法时获得更好的灵活性,提供了一种降耦的手段。</p>
<p>此外,newInstance()效率比较低,只能调用无参构造。</p>
<p>注意:静态代码是和Class绑定的,Class装载成功就表示执行了你的静态代码了。而且以后不会再走这段静态代码了。</p>
<p>通过Class.forName方法可以实现预加载功能,提高程序效率。</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2015/12/15/Class-forName作用/" data-id="cin8r00kd001sbomfom79z8un" class="article-share-link">Share</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Java-Class/">Java Class</a></li></ul>
</footer>
</div>
</article>
<article id="post-Android百分比布局学习" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-meta">
<a href="/2015/12/13/Android百分比布局学习/" class="article-date">
<time datetime="2015-12-13T11:08:49.000Z" itemprop="datePublished">2015-12-13</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2015/12/13/Android百分比布局学习/">Android百分比布局学习</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Android应用的适配问题,让很多人头痛过,我也不例外。前段时间看到Google提供了一个支持库,该支持库可以用来进行百分比的布局,对此支持库特别感兴趣,于是抱着学习的态度开始阅读其源码。</p>
<p>该支持库中只有三个类,包括:PercentFrameLayout,PercentRelativeLayout,PercentLayoutHelper。</p>
<p>查看源码之后,发现PercentRelativeLayout和PercentFrameLayout的实现方法几乎一模一样,都同属于一个模板。</p>
<p>下面是PercentFrameLayout的源码:</p>
<pre><code><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PercentFrameLayout</span> <span class="keyword">extends</span> <span class="title">FrameLayout</span> </span>{
<span class="keyword">private</span> <span class="keyword">final</span> PercentLayoutHelper mHelper = <span class="keyword">new</span> PercentLayoutHelper(<span class="keyword">this</span>);
<span class="function"><span class="keyword">public</span> <span class="title">PercentFrameLayout</span><span class="params">(Context context)</span> </span>{
<span class="keyword">super</span>(context);
}
<span class="function"><span class="keyword">public</span> <span class="title">PercentFrameLayout</span><span class="params">(Context context, AttributeSet attrs)</span> </span>{
<span class="keyword">super</span>(context, attrs);
}
<span class="function"><span class="keyword">public</span> <span class="title">PercentFrameLayout</span><span class="params">(Context context, AttributeSet attrs, <span class="keyword">int</span> defStyleAttr)</span> </span>{
<span class="keyword">super</span>(context, attrs, defStyleAttr);
}
<span class="annotation">@Override</span>
<span class="function"><span class="keyword">protected</span> LayoutParams <span class="title">generateDefaultLayoutParams</span><span class="params">()</span> </span>{
<span class="keyword">return</span> <span class="keyword">new</span> LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
<span class="annotation">@Override</span>
<span class="function"><span class="keyword">public</span> LayoutParams <span class="title">generateLayoutParams</span><span class="params">(AttributeSet attrs)</span> </span>{
<span class="keyword">return</span> <span class="keyword">new</span> LayoutParams(getContext(), attrs);
}
<span class="annotation">@Override</span>
<span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onMeasure</span><span class="params">(<span class="keyword">int</span> widthMeasureSpec, <span class="keyword">int</span> heightMeasureSpec)</span> </span>{
mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
<span class="keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec);
<span class="keyword">if</span> (mHelper.handleMeasuredStateTooSmall()) {
<span class="keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
<span class="annotation">@Override</span>
<span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onLayout</span><span class="params">(<span class="keyword">boolean</span> changed, <span class="keyword">int</span> left, <span class="keyword">int</span> top, <span class="keyword">int</span> right, <span class="keyword">int</span> bottom)</span> </span>{
<span class="keyword">super</span>.onLayout(changed, left, top, right, bottom);
mHelper.restoreOriginalParams();
}
<span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">LayoutParams</span> <span class="keyword">extends</span> <span class="title">FrameLayout</span>.<span class="title">LayoutParams</span>
<span class="keyword">implements</span> <span class="title">PercentLayoutHelper</span>.<span class="title">PercentLayoutParams</span> </span>{
<span class="keyword">private</span> PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
<span class="function"><span class="keyword">public</span> <span class="title">LayoutParams</span><span class="params">(Context c, AttributeSet attrs)</span> </span>{
<span class="keyword">super</span>(c, attrs);
mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
}
<span class="function"><span class="keyword">public</span> <span class="title">LayoutParams</span><span class="params">(<span class="keyword">int</span> width, <span class="keyword">int</span> height)</span> </span>{
<span class="keyword">super</span>(width, height);
}
<span class="function"><span class="keyword">public</span> <span class="title">LayoutParams</span><span class="params">(<span class="keyword">int</span> width, <span class="keyword">int</span> height, <span class="keyword">int</span> gravity)</span> </span>{
<span class="keyword">super</span>(width, height, gravity);
}
<span class="function"><span class="keyword">public</span> <span class="title">LayoutParams</span><span class="params">(ViewGroup.LayoutParams source)</span> </span>{
<span class="keyword">super</span>(source);
}
<span class="function"><span class="keyword">public</span> <span class="title">LayoutParams</span><span class="params">(MarginLayoutParams source)</span> </span>{
<span class="keyword">super</span>(source);
}
<span class="function"><span class="keyword">public</span> <span class="title">LayoutParams</span><span class="params">(FrameLayout.LayoutParams source)</span> </span>{
<span class="keyword">super</span>((MarginLayoutParams) source);
gravity = source.gravity;
}
<span class="function"><span class="keyword">public</span> <span class="title">LayoutParams</span><span class="params">(LayoutParams source)</span> </span>{
<span class="keyword">this</span>((FrameLayout.LayoutParams) source);
mPercentLayoutInfo = source.mPercentLayoutInfo;
}
<span class="annotation">@Override</span>
<span class="keyword">public</span> PercentLayoutHelper.<span class="function">PercentLayoutInfo <span class="title">getPercentLayoutInfo</span><span class="params">()</span> </span>{
<span class="keyword">if</span> (mPercentLayoutInfo == <span class="keyword">null</span>) {
mPercentLayoutInfo = <span class="keyword">new</span> PercentLayoutHelper.PercentLayoutInfo();
}
<span class="keyword">return</span> mPercentLayoutInfo;
}
<span class="annotation">@Override</span>
<span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">setBaseAttributes</span><span class="params">(TypedArray a, <span class="keyword">int</span> widthAttr, <span class="keyword">int</span> heightAttr)</span> </span>{
PercentLayoutHelper.fetchWidthAndHeight(<span class="keyword">this</span>, a, widthAttr, heightAttr);
}
}
}
</code></pre><p>很明显,PercentFrameLayout是FrameLayout的一个子类,接下来,我将对每个函数逐个进行分析。</p>
<p><strong>首先是generateDefaultLayoutParams()函数</strong></p>
<p>通过该函数的名字,我们大概就能知道该函数的作用了,主要就是用来生成一个默认的布局参数。其主要是在addView(View child)之类的函数中使用,如果child本身没有设置布局参数,就通过该函数生成一个,作为该child的布局参数。</p>
<p><strong>generateLayoutParams(AttributeSet attrs)</strong></p>
<p>这个函数也是用来生成一个布局参数,不过该布局参数是根据AttributeSet(xml布局文件中设置的属性)生成的。该函数主要在填充布局的时候被调用,即当LayoutInflater.inflater()方法调用时。有一点我们要知道,此函数也是用来为子视图生成布局参数的,也就是说子视图的布局参数由父容器生成。</p>
<p><strong>onMeasure(int widthMeasureSpec, int heightMeasureSpec)</strong></p>
<p>此函数主要用来测量每个视图的大小,因此,实现百分比布局时,自然而然的就要从这个函数入手。接下来就是实现百分比布局的关键点了,通过调用<br>PercentLayoutHelper.adjustChildren方法重新计算每个视图的大小,</p>
<p><strong>onLayout(boolean changed, int left, int top, int right, int bottom)</strong></p>
<p>在此函数中,每个子视图的layout方法将被调用。</p>
<p>下面我将对实现百分比布局的关键类PercentLayoutHelper进行分析:</p>
<p>首先先分析PercentLayoutInfo类,下面是其源码:</p>
<pre><code> <span class="comment">/**
* Container for information about percentage dimensions and margins. It acts as an extension
* for {@code LayoutParams}.
*/</span>
<span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title">PercentLayoutInfo</span> {
<span class="keyword">public</span> <span class="keyword">float</span> widthPercent;
<span class="keyword">public</span> <span class="keyword">float</span> heightPercent;
<span class="keyword">public</span> <span class="keyword">float</span> leftMarginPercent;
<span class="keyword">public</span> <span class="keyword">float</span> topMarginPercent;
<span class="keyword">public</span> <span class="keyword">float</span> rightMarginPercent;
<span class="keyword">public</span> <span class="keyword">float</span> bottomMarginPercent;
<span class="keyword">public</span> <span class="keyword">float</span> startMarginPercent;
<span class="keyword">public</span> <span class="keyword">float</span> endMarginPercent;
<span class="keyword">public</span> <span class="keyword">float</span> aspectRatio;
<span class="comment">/* package */</span> final ViewGroup.MarginLayoutParams mPreservedParams;
<span class="function"><span class="keyword">public</span> <span class="title">PercentLayoutInfo</span>(<span class="params"></span>) </span>{
widthPercent = -<span class="number">1</span>f;
heightPercent = -<span class="number">1</span>f;
leftMarginPercent = -<span class="number">1</span>f;
topMarginPercent = -<span class="number">1</span>f;
rightMarginPercent = -<span class="number">1</span>f;
bottomMarginPercent = -<span class="number">1</span>f;
startMarginPercent = -<span class="number">1</span>f;
endMarginPercent = -<span class="number">1</span>f;
mPreservedParams = <span class="keyword">new</span> ViewGroup.MarginLayoutParams(<span class="number">0</span>, <span class="number">0</span>);
}
<span class="comment">/**
* Fills {@code ViewGroup.LayoutParams} dimensions based on percentage values.
*/</span>
<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fillLayoutParams</span>(<span class="params">ViewGroup.LayoutParams <span class="keyword">params</span>, <span class="keyword">int</span> widthHint,
<span class="keyword">int</span> heightHint</span>) </span>{
<span class="comment">// Preserve the original layout params, so we can restore them after the measure step.</span>
mPreservedParams.width = <span class="keyword">params</span>.width;
mPreservedParams.height = <span class="keyword">params</span>.height;
<span class="comment">// We assume that width/height set to 0 means that value was unset. This might not</span>
<span class="comment">// necessarily be true, as the user might explicitly set it to 0. However, we use this</span>
<span class="comment">// information only for the aspect ratio. If the user set the aspect ratio attribute,</span>
<span class="comment">// it means they accept or soon discover that it will be disregarded.</span>
final boolean widthNotSet = <span class="keyword">params</span>.width == <span class="number">0</span> && widthPercent < <span class="number">0</span>;
final boolean heightNotSet = <span class="keyword">params</span>.height == <span class="number">0</span> && heightPercent < <span class="number">0</span>;
<span class="keyword">if</span> (widthPercent >= <span class="number">0</span>) {
<span class="keyword">params</span>.width = (<span class="keyword">int</span>) (widthHint * widthPercent);
}
<span class="keyword">if</span> (heightPercent >= <span class="number">0</span>) {
<span class="keyword">params</span>.height = (<span class="keyword">int</span>) (heightHint * heightPercent);
}
<span class="keyword">if</span> (aspectRatio >= <span class="number">0</span>) {
<span class="keyword">if</span> (widthNotSet) {
<span class="keyword">params</span>.width = (<span class="keyword">int</span>) (<span class="keyword">params</span>.height * aspectRatio);
}
<span class="keyword">if</span> (heightNotSet) {
<span class="keyword">params</span>.height = (<span class="keyword">int</span>) (<span class="keyword">params</span>.width / aspectRatio);
}
}
<span class="keyword">if</span> (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, <span class="string">"after fillLayoutParams: ("</span> + <span class="keyword">params</span>.width + <span class="string">", "</span> + <span class="keyword">params</span>.height + <span class="string">")"</span>);
}
}
<span class="comment">/**
* Fills {@code ViewGroup.MarginLayoutParams} dimensions and margins based on percentage
* values.
*/</span>
<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fillMarginLayoutParams</span>(<span class="params">ViewGroup.MarginLayoutParams <span class="keyword">params</span>, <span class="keyword">int</span> widthHint,
<span class="keyword">int</span> heightHint</span>) </span>{
fillLayoutParams(<span class="keyword">params</span>, widthHint, heightHint);
<span class="comment">// Preserver the original margins, so we can restore them after the measure step.</span>
mPreservedParams.leftMargin = <span class="keyword">params</span>.leftMargin;
mPreservedParams.topMargin = <span class="keyword">params</span>.topMargin;
mPreservedParams.rightMargin = <span class="keyword">params</span>.rightMargin;
mPreservedParams.bottomMargin = <span class="keyword">params</span>.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(mPreservedParams,
MarginLayoutParamsCompat.getMarginStart(<span class="keyword">params</span>));
MarginLayoutParamsCompat.setMarginEnd(mPreservedParams,
MarginLayoutParamsCompat.getMarginEnd(<span class="keyword">params</span>));
<span class="keyword">if</span> (leftMarginPercent >= <span class="number">0</span>) {
<span class="keyword">params</span>.leftMargin = (<span class="keyword">int</span>) (widthHint * leftMarginPercent);
}
<span class="keyword">if</span> (topMarginPercent >= <span class="number">0</span>) {
<span class="keyword">params</span>.topMargin = (<span class="keyword">int</span>) (heightHint * topMarginPercent);
}
<span class="keyword">if</span> (rightMarginPercent >= <span class="number">0</span>) {
<span class="keyword">params</span>.rightMargin = (<span class="keyword">int</span>) (widthHint * rightMarginPercent);
}
<span class="keyword">if</span> (bottomMarginPercent >= <span class="number">0</span>) {
<span class="keyword">params</span>.bottomMargin = (<span class="keyword">int</span>) (heightHint * bottomMarginPercent);
}
<span class="keyword">if</span> (startMarginPercent >= <span class="number">0</span>) {
MarginLayoutParamsCompat.setMarginStart(<span class="keyword">params</span>,
(<span class="keyword">int</span>) (widthHint * startMarginPercent));
}
<span class="keyword">if</span> (endMarginPercent >= <span class="number">0</span>) {
MarginLayoutParamsCompat.setMarginEnd(<span class="keyword">params</span>,
(<span class="keyword">int</span>) (widthHint * endMarginPercent));
}
<span class="keyword">if</span> (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, <span class="string">"after fillMarginLayoutParams: ("</span> + <span class="keyword">params</span>.width + <span class="string">", "</span> + <span class="keyword">params</span>.height
+ <span class="string">")"</span>);
}
}
@<span class="function">Override
<span class="keyword">public</span> String <span class="title">toString</span>(<span class="params"></span>) </span>{
<span class="keyword">return</span> String.format(<span class="string">"PercentLayoutInformation width: %f height %f, margins (%f, %f, "</span>
+ <span class="string">" %f, %f, %f, %f)"</span>, widthPercent, heightPercent, leftMarginPercent,
topMarginPercent, rightMarginPercent, bottomMarginPercent, startMarginPercent,
endMarginPercent);
}
<span class="comment">/**
* Restores original dimensions and margins after they were changed for percentage based
* values. Calling this method only makes sense if you previously called
* {@link PercentLayoutHelper.PercentLayoutInfo#fillMarginLayoutParams}.
*/</span>
<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">restoreMarginLayoutParams</span>(<span class="params">ViewGroup.MarginLayoutParams <span class="keyword">params</span></span>) </span>{
restoreLayoutParams(<span class="keyword">params</span>);
<span class="keyword">params</span>.leftMargin = mPreservedParams.leftMargin;
<span class="keyword">params</span>.topMargin = mPreservedParams.topMargin;
<span class="keyword">params</span>.rightMargin = mPreservedParams.rightMargin;
<span class="keyword">params</span>.bottomMargin = mPreservedParams.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(<span class="keyword">params</span>,
MarginLayoutParamsCompat.getMarginStart(mPreservedParams));
MarginLayoutParamsCompat.setMarginEnd(<span class="keyword">params</span>,
MarginLayoutParamsCompat.getMarginEnd(mPreservedParams));
}
<span class="comment">/**
* Restores original dimensions after they were changed for percentage based values. Calling
* this method only makes sense if you previously called
* {@link PercentLayoutHelper.PercentLayoutInfo#fillLayoutParams}.
*/</span>
<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">restoreLayoutParams</span>(<span class="params">ViewGroup.LayoutParams <span class="keyword">params</span></span>) </span>{
<span class="keyword">params</span>.width = mPreservedParams.width;
<span class="keyword">params</span>.height = mPreservedParams.height;
}
}
</code></pre><p>正如其所注释的那样,该类充当LayoutParams的扩展,包含尺寸和边距的百分比信息。其fillLayoutParams和fillMarginLayoutParams方法用来计算视图的宽和高,以及边距的具体大小。</p>
<p>静态方法PercentLayoutHelper.getPercentLayoutInfo(Context context, AttributeSet attrs)用来得到一个PercentLayoutInfo对象。</p>
<p>PercentLayoutHelper.adjustChildren(int widthMeasureSpec, int heightMeasureSpec)方法主要用来根据百分比属性计算具体的宽、高等参数。</p>
<p>PercentLayoutHelper.handleMeasuredStateTooSmall方法,主要处理子视图的大小是否需要重新调整。当子视图的具体宽高不足以包裹其内容大小,且子视图的宽高属性至少一个设置成WRAP_CONTENT,那么就会重新计算改视图的大小。</p>
<p>PercentLayoutHelper.restoreOriginalParams()方法用来恢复子视图原始布局参数,以供下次使用。</p>
<p>PercentLayoutHelper.fetchWidthAndHeight方法,在百分比布局类的布局参数的setBaseAttributes(TypedArray a, int widthAttr, int heightAttr)方法中被调用,其作用就是给布局参数的宽高属性赋值,从而避免抛出RuntimeException。因为在ViewGroup.LayoutParams类中setBaseAttributes(TypedArray a, int widthAttr, int heightAttr)的默认实现方法如下所示:</p>
<pre><code><span class="keyword">protected</span> <span class="keyword">void</span> setBaseAttributes(TypedArray a, <span class="built_in">int</span> widthAttr, <span class="built_in">int</span> heightAttr) {
<span class="variable">width</span> = a.getLayoutDimension(widthAttr, <span class="string">"layout_width"</span>);
<span class="variable">height</span> = a.getLayoutDimension(heightAttr, <span class="string">"layout_height"</span>);
}
</code></pre><p>其中TypedArray.getLayoutDimension(int index, String name)方法在找不到名为name的相关属性时,会抛出RuntimeException异常。</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2015/12/13/Android百分比布局学习/" data-id="cin8r00kk001ybomf28lp5kct" class="article-share-link">Share</a>
<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Android-百分比布局/">Android 百分比布局</a></li></ul>
</footer>
</div>
</article>
<nav id="page-nav">
<span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><a class="page-number" href="/page/4/">4</a><a class="extend next" rel="next" href="/page/2/">Next »</a>
</nav>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">Tags</h3>
<div class="widget">
<ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Activity管理/">Activity管理</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-百分比布局/">Android 百分比布局</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-Handler/">Android Handler</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-Message/">Android Message</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-Messenger/">Android Messenger</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-Settings/">Android Settings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-UniversalImageLoader-MemoryCache/">Android UniversalImageLoader MemoryCache</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-launchMode/">Android launchMode</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android-屏幕切换/">Android 屏幕切换</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/AndroidStudio-Gradle/">AndroidStudio Gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/CGI/">CGI</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/HashSet-HashMap-Hashtable/">HashSet HashMap Hashtable</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-ByteArrayOutputStream/">Java ByteArrayOutputStream</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-Callable/">Java Callable</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-Class/">Java Class</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-Closeable-Flushable/">Java Closeable Flushable</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-DataOutput/">Java DataOutput</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-Executor/">Java Executor</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-ExecutorService/">Java ExecutorService</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-FilterOutputStream/">Java FilterOutputStream</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-Future/">Java Future</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java-泛型/">Java 泛型</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Servlet/">Servlet</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Volley/">Volley</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/android-EventBus/">android EventBus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java-DataInput/">java DataInput</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java-线程池/">java 线程池</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/分布式-负载均衡算法/">分布式 负载均衡算法</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/编程技巧-对象池/">编程技巧 对象池</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/闭包/">闭包</a><span class="tag-list-count">1</span></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Tag Cloud</h3>
<div class="widget tagcloud">
<a href="/tags/Activity管理/" style="font-size: 10px;">Activity管理</a> <a href="/tags/Android-百分比布局/" style="font-size: 10px;">Android 百分比布局</a> <a href="/tags/Android-Handler/" style="font-size: 10px;">Android Handler</a> <a href="/tags/Android-Message/" style="font-size: 10px;">Android Message</a> <a href="/tags/Android-Messenger/" style="font-size: 10px;">Android Messenger</a> <a href="/tags/Android-Settings/" style="font-size: 10px;">Android Settings</a> <a href="/tags/Android-UniversalImageLoader-MemoryCache/" style="font-size: 10px;">Android UniversalImageLoader MemoryCache</a> <a href="/tags/Android-launchMode/" style="font-size: 10px;">Android launchMode</a> <a href="/tags/Android-屏幕切换/" style="font-size: 10px;">Android 屏幕切换</a> <a href="/tags/AndroidStudio-Gradle/" style="font-size: 10px;">AndroidStudio Gradle</a> <a href="/tags/CGI/" style="font-size: 10px;">CGI</a> <a href="/tags/HashSet-HashMap-Hashtable/" style="font-size: 10px;">HashSet HashMap Hashtable</a> <a href="/tags/Java-ByteArrayOutputStream/" style="font-size: 10px;">Java ByteArrayOutputStream</a> <a href="/tags/Java-Callable/" style="font-size: 10px;">Java Callable</a> <a href="/tags/Java-Class/" style="font-size: 10px;">Java Class</a> <a href="/tags/Java-Closeable-Flushable/" style="font-size: 10px;">Java Closeable Flushable</a> <a href="/tags/Java-DataOutput/" style="font-size: 10px;">Java DataOutput</a> <a href="/tags/Java-Executor/" style="font-size: 10px;">Java Executor</a> <a href="/tags/Java-ExecutorService/" style="font-size: 10px;">Java ExecutorService</a> <a href="/tags/Java-FilterOutputStream/" style="font-size: 10px;">Java FilterOutputStream</a> <a href="/tags/Java-Future/" style="font-size: 10px;">Java Future</a> <a href="/tags/Java-泛型/" style="font-size: 10px;">Java 泛型</a> <a href="/tags/Servlet/" style="font-size: 10px;">Servlet</a> <a href="/tags/Volley/" style="font-size: 10px;">Volley</a> <a href="/tags/android-EventBus/" style="font-size: 10px;">android EventBus</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/java-DataInput/" style="font-size: 10px;">java DataInput</a> <a href="/tags/java-线程池/" style="font-size: 10px;">java 线程池</a> <a href="/tags/分布式-负载均衡算法/" style="font-size: 10px;">分布式 负载均衡算法</a> <a href="/tags/编程技巧-对象池/" style="font-size: 10px;">编程技巧 对象池</a> <a href="/tags/闭包/" style="font-size: 10px;">闭包</a>
</div>
</div>