您好,登錄后才能下訂單哦!
這篇文章主要講解了“源碼中都使用16進制進行狀態管理的原因”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“源碼中都使用16進制進行狀態管理的原因”吧!
在Android源碼中,對于“多狀態”的管理總是通過16進制數字來表示,類似這種格式:
//ViewGroup.java protected int mGroupFlags; static final int FLAG_CLIP_CHILDREN = 0x1; private static final int FLAG_CLIP_TO_PADDING = 0x2; static final int FLAG_INVALIDATE_REQUIRED = 0x4; private static final int FLAG_RUN_ANIMATION = 0x8; static final int FLAG_ANIMATION_DONE = 0x10; private static final int FLAG_PADDING_NOT_NULL = 0x20;
那么,你有沒有想過為什么遇到多狀態的管理,就選擇用16進制?
來舉個實際的例子,我們作為一個人,身上肯定會有很多標簽,比如帥氣、可愛、博學、機智、懶惰、小氣。
針對這些標簽,我們就可以設定不同的人設:
//定義實體類 data class Person(var tag : String) //修改標簽 val person1 = Person("帥氣") //判斷標簽 fun isCute():Boolean{ return person1.tag == "可愛" }
當一個人只有一個標簽的時候是很簡單的,直接賦值或者取值判斷即可。但是,如果一個人有多個標簽呢?
也很簡單,使用集合存儲即可:
val person2 = Person(mutableListOf()) person2.tags.add("帥氣") person2.tags.add("可愛") person2.tags.remove("可愛") person2.tags.contains("可愛")
但是用到集合之后,這個計算就變得比較復雜了,由于remove和contains方法都是通過遍歷集合的方式實現的,從時間復雜度角度看的話,當刪除某個標簽或者判斷某個標簽是否存在的時間復雜度都是O(n)。
有沒有什么辦法讓多個標簽也像剛才的單個標簽那么簡單地使用操作呢?
當然有啦,不然這篇文章也不會有了,在這之前,我們先復習下二進制的幾種運算。
1、按位與(&)
當兩個對應位的值都為1,則結果為1,否則為0。
舉例:0x1 & 0x4
0001 & 0100 = 0000
2、按位或(|)
當兩個對應位的值都只要有一位是1,則結果為1。
舉例:0x1 | 0x4
0001 | 0100 = 0101
3、取反( ~ )
將一個數按位取反。
舉例:~ 0x1
0001 ~ = 1110
好了,有了這三種運算,我們的狀態管理就足夠了。
接下來,就來完成一個完整的狀態管理例子。
//設定所有狀態對應的16進制值 //可愛,對應二進制0001 val TAG_CUTE = Ox1 //帥氣,對應二進制0010 val TAG_HANDSOME = Ox2 //博學,對應二進制0100 val TAG_LEARNED = Ox4 var personTag = 0
如果一個二進制數字想留下另一個二進制數字的痕跡,我們可以通過或運算,這樣只要第二個數字某位上有1,那么最終的結果在同樣的位數肯定也是1。
所以,我們可以通過這個方法來完成狀態增加的功能:
//增加可愛狀態 personTag |= TAG_CUTE 0000 | 0001 = 0001
這樣操作之后,personTag的第四位上的數字就為1了,也就帶有TAG_CUTE這個標記了。
按照上述的邏輯,狀態的移除其實就是需要把對應的位數從1改為0。
假設personTag現在的值變成了二進制數0111。
如果要刪除TAG_CUTE屬性,就需要把第四位的1改為0。那么我們可以做的操作就是先對TAG_CUTE取反,也就是把0001,變成了1110。然后再和personTag進行與運算,這樣第四位肯定就會變為0,而其他位上面的值不變。
//personTag為二進制數0111 personTag &= ~TAG_CUTE 0001 ~ = 1110 & 0111 = 0110
完成對TAG_CUTE狀態的移除。
同理,對是否有某個狀態的判斷,其實就是判斷在某個位上是否值為1。所以我們只需要對狀態進行 與運算,如果結果為0,就代表沒有這個狀態,否則就代表有這個狀態。
//personTag為二進制數0111 (personTag & TAG_CUTE) != 0 0111 & 0001 = 0001
結果不為0,所以代表personTag 包含了 TAG_CUTE 這個狀態。
細心的朋友可能會發現,剛才我們用到的16進制值,跳過了Ox3這個值,這是為什么呢?
其實不難發現,所謂的通過16進制管理狀態,其實是通過二進制來管理狀態,歸根結底是通過二進制中的1所在的位數來進行管理。
所以我們對狀態賦值,需要選取單獨占有一位的二進制值,比如0001 ,0010,0100,1000,10000等等。
如果用了其他值會發生什么呢?舉個例子,增加Ox3的TAG。
//懶惰,對應二進制0011 val TAG_LAZY = Ox3 //增加可愛狀態 personTag |= TAG_CUTE //增加帥氣狀態 personTag |= TAG_HANDSOME
在我們增加了可愛和帥氣狀態之后,personTag的二進制值為 0011。
這時候再對它進行判斷,是否含有懶惰狀態:
//是否含有懶惰狀態 (personTag & TAG_LAZY) != 0 0011 & 0011 = 0011
結果不為0,難道我們增加了懶惰狀態嗎?很明顯沒有,我不懶但是卻說我懶,這是誣陷!
所以你明白狀態取值的范圍了嗎?
到此,通過16進制管理狀態的功能已經實現了,很明顯這種方式管理狀態要簡便許多,其根本原理就是通過二進制的計算來完成對狀態的管理。
有人又要問了,既然本質是通過二進制來完成管理,那么用10進制來表示也可以啊,比如上述的例子:
//設定所有狀態對應的10進制值 //可愛,對應二進制0001 val TAG_CUTE = 1 //帥氣,對應二進制0010 val TAG_HANDSOME = 2 //博學,對應二進制0100 val TAG_LEARNED = 4 var personTag = 0
這跟16進制不是一樣么?
從根本來說,確實是一樣的,但是16進制有16進制的好處,這就涉及到16進制為什么被設計出來的原因了。
在計算機中,一個字節有八位,最大值為 1111 1111。對應的10進制數是255,對應的16進制是 FF。所以半個字節用16進制是可以通過一個字母就能表示,而轉換成10進制就是一個無規律的數字。為了方便,代碼中一般使用16進制來表示 二進制,就是因為其可以和二進制進行一個更方便直觀的轉換。
感謝各位的閱讀,以上就是“源碼中都使用16進制進行狀態管理的原因”的內容了,經過本文的學習后,相信大家對源碼中都使用16進制進行狀態管理的原因這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。