Android源碼使用16進(jìn)制進(jìn)行狀態(tài)管理的方法
前言
在Android源碼中,對(duì)于“多狀態(tài)”的管理總是通過(guò)16進(jìn)制數(shù)字來(lái)表示,類似這種格式:
//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;
那么,你有沒(méi)有想過(guò)為什么遇到多狀態(tài)的管理,就需要用到16進(jìn)制?
簡(jiǎn)單的狀態(tài)表示
來(lái)舉個(gè)實(shí)際的例子,我們作為一個(gè)人,身上肯定會(huì)有很多標(biāo)簽,比如帥氣、可愛(ài)、博學(xué)、機(jī)智、懶惰、小氣
。
針對(duì)這些標(biāo)簽,我們就可以設(shè)定不同的人設(shè):
//定義實(shí)體類 data class Person(var tag : String) //修改標(biāo)簽 val person1 = Person("帥氣") //判斷標(biāo)簽 fun isCute():Boolean{ return person1.tag == "可愛(ài)" }
當(dāng)一個(gè)人只有一個(gè)標(biāo)簽的時(shí)候是很簡(jiǎn)單的,直接賦值或者取值判斷即可。但是,如果一個(gè)人有多個(gè)標(biāo)簽?zāi)兀?/p>
也很簡(jiǎn)單,使用集合存儲(chǔ)即可:
val person2 = Person(mutableListOf()) person2.tags.add("帥氣") person2.tags.add("可愛(ài)") person2.tags.remove("可愛(ài)") person2.tags.contains("可愛(ài)")
但是用到集合之后,這個(gè)計(jì)算就變得比較復(fù)雜了,由于remove
和contains
方法都是通過(guò)遍歷集合的方式實(shí)現(xiàn)的,從時(shí)間復(fù)雜度角度看的話,當(dāng)刪除某個(gè)標(biāo)簽或者判斷某個(gè)標(biāo)簽是否存在的時(shí)間復(fù)雜度都是O(n)
。
有沒(méi)有什么辦法讓多個(gè)標(biāo)簽也像剛才的單個(gè)標(biāo)簽?zāi)敲春?jiǎn)單地使用操作呢?
二進(jìn)制運(yùn)算
當(dāng)然有啦,不然這篇文章也不會(huì)有了,在這之前,我們先復(fù)習(xí)下二進(jìn)制的幾種運(yùn)算。
1、按位與(&)
當(dāng)兩個(gè)對(duì)應(yīng)位的值都為1,則結(jié)果為1,否則為0。
舉例:0x1 & 0x4
0001 &
0100
=
0000
2、按位或(|)
當(dāng)兩個(gè)對(duì)應(yīng)位的值都只要有一位是1,則結(jié)果為1。
舉例:0x1 | 0x4
0001 |
0100
=
0101
3、取反( ~ )
將一個(gè)數(shù)按位取反。
舉例:~ 0x1
0001 ~
=
1110
好了,有了這三種運(yùn)算,我們的狀態(tài)管理就足夠了。
引入16進(jìn)制
接下來(lái),就來(lái)完成一個(gè)完整的狀態(tài)管理例子。
//設(shè)定所有狀態(tài)對(duì)應(yīng)的16進(jìn)制值 //可愛(ài),對(duì)應(yīng)二進(jìn)制0001 val TAG_CUTE = Ox1 //帥氣,對(duì)應(yīng)二進(jìn)制0010 val TAG_HANDSOME = Ox2 //博學(xué),對(duì)應(yīng)二進(jìn)制0100 val TAG_LEARNED = Ox4 var personTag = 0
狀態(tài)增加
如果一個(gè)二進(jìn)制數(shù)字想留下另一個(gè)二進(jìn)制數(shù)字的痕跡(數(shù)字1的痕跡),我們可以通過(guò)或運(yùn)算,這樣只要第二個(gè)數(shù)字某位上有1,那么最終的結(jié)果在同樣的位數(shù)肯定也是1。
所以,我們可以通過(guò)這個(gè)方法來(lái)完成狀態(tài)增加的功能:
//增加可愛(ài)狀態(tài) personTag |= TAG_CUTE 0000 | 0001 = 0001
這樣操作之后,personTag的第四位上的數(shù)字就為1了,也就帶有TAG_CUTE
這個(gè)標(biāo)記了。
狀態(tài)移除
按照上述的邏輯,狀態(tài)的移除其實(shí)就是需要把對(duì)應(yīng)的位數(shù)從1改為0。
假設(shè)personTag
現(xiàn)在的值變成了二進(jìn)制數(shù)0111
。
如果要?jiǎng)h除TAG_CUTE
屬性,就需要把第四位的1改為0。那么我們可以做的操作就是先對(duì)TAG_CUTE
取反,也就是把0001,變成了1110。然后再和personTag
進(jìn)行與運(yùn)算,這樣第四位肯定就會(huì)變?yōu)?,而其他位上面的值不變。
//personTag為二進(jìn)制數(shù)0111 personTag &= ~TAG_CUTE 0001 ~ = 1110 & 0111 = 0110
完成對(duì)TAG_CUTE
狀態(tài)的移除。
狀態(tài)判斷
同理,對(duì)是否有某個(gè)狀態(tài)的判斷,其實(shí)就是判斷在某個(gè)位上是否值為1。
所以我們只需要對(duì)狀態(tài)進(jìn)行 與運(yùn)算,如果結(jié)果為0,就代表沒(méi)有這個(gè)狀態(tài),否則就代表有這個(gè)狀態(tài)。
//personTag為二進(jìn)制數(shù)0111 (personTag & TAG_CUTE) != 0 0111 & 0001 = 0001
結(jié)果不為0,所以代表personTag
包含了 TAG_CUTE
這個(gè)狀態(tài)。
注意的點(diǎn)
細(xì)心的朋友可能會(huì)發(fā)現(xiàn),剛才我們用到的16進(jìn)制值,跳過(guò)了Ox3
這個(gè)值,這是為什么呢?
其實(shí)不難發(fā)現(xiàn),所謂的通過(guò)16進(jìn)制管理狀態(tài),其實(shí)是通過(guò)二進(jìn)制來(lái)管理狀態(tài),歸根結(jié)底是通過(guò)二進(jìn)制中的1所在的位數(shù)來(lái)進(jìn)行管理。
所以我們對(duì)狀態(tài)賦值,需要選取單獨(dú)占有一位的二進(jìn)制值,比如 0001 ,0010,0100,1000,10000
等等。
如果用了其他值會(huì)發(fā)生什么呢?舉個(gè)例子,增加Ox3
的TAG。
//懶惰,對(duì)應(yīng)二進(jìn)制0011 val TAG_LAZY = Ox3 //增加可愛(ài)狀態(tài) personTag |= TAG_CUTE //增加帥氣狀態(tài) personTag |= TAG_HANDSOME
在我們?cè)黾恿丝蓯?ài)和帥氣狀態(tài)之后,personTag
的二進(jìn)制值為 0011
。
這時(shí)候再對(duì)它進(jìn)行判斷,是否含有懶惰狀態(tài):
//是否含有懶惰狀態(tài) (personTag & TAG_LAZY) != 0 0011 & 0011 = 0011
結(jié)果不為0,難道我們?cè)黾恿藨卸锠顟B(tài)嗎?很明顯沒(méi)有,我不懶但是卻說(shuō)我懶,這是誣陷!
所以你明白狀態(tài)取值的范圍了嗎?
為什么是16進(jìn)制?
到此,通過(guò)16進(jìn)制管理狀態(tài)的功能已經(jīng)實(shí)現(xiàn)了,很明顯這種方式管理狀態(tài)要簡(jiǎn)便許多,其根本原理就是通過(guò)二進(jìn)制的計(jì)算來(lái)完成對(duì)狀態(tài)的管理。
有人又要問(wèn)了,既然本質(zhì)是通過(guò)二進(jìn)制來(lái)完成管理,那么用10進(jìn)制來(lái)表示也可以啊,比如上述的例子:
//設(shè)定所有狀態(tài)對(duì)應(yīng)的10進(jìn)制值 //可愛(ài),對(duì)應(yīng)二進(jìn)制0001 val TAG_CUTE = 1 //帥氣,對(duì)應(yīng)二進(jìn)制0010 val TAG_HANDSOME = 2 //博學(xué),對(duì)應(yīng)二進(jìn)制0100 val TAG_LEARNED = 4 var personTag = 0
這跟16進(jìn)制不是一樣么?
從根本來(lái)說(shuō),確實(shí)是一樣的,但是16進(jìn)制有16進(jìn)制的好處,這就涉及到16進(jìn)制為什么被設(shè)計(jì)出來(lái)的原因了。
在計(jì)算機(jī)中,一個(gè)字節(jié)有八位,最大值為 1111 1111。對(duì)應(yīng)的10進(jìn)制數(shù)是255,對(duì)應(yīng)的16進(jìn)制是 FF。
所以半個(gè)字節(jié)用16進(jìn)制是可以通過(guò)一個(gè)字母就能表示,而轉(zhuǎn)換成10進(jìn)制就是一個(gè)無(wú)規(guī)律的數(shù)字。
為了方便,代碼中一般使用16進(jìn)制來(lái)表示 二進(jìn)制,就是因?yàn)槠淇梢院投M(jìn)制進(jìn)行一個(gè)更方便直觀的轉(zhuǎn)換。
總結(jié)
今天和大家介紹了下源碼中常用的通過(guò)16進(jìn)制轉(zhuǎn)換2進(jìn)制來(lái)管理狀態(tài)的方法。
到此這篇關(guān)于Android源碼使用16進(jìn)制進(jìn)行狀態(tài)管理的文章就介紹到這了,更多相關(guān)Android 16進(jìn)制狀態(tài)管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程實(shí)現(xiàn)3D滑動(dòng)旋轉(zhuǎn)效果的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)3D滑動(dòng)旋轉(zhuǎn)效果的方法,主要通過(guò)繼承Animation自定義Rotate3D來(lái)實(shí)現(xiàn)3D翻頁(yè)效果,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11Android應(yīng)用設(shè)置獨(dú)立的多語(yǔ)言實(shí)戰(zhàn)技巧詳解
這篇文章主要為大家介紹了Android應(yīng)用設(shè)置獨(dú)立的多語(yǔ)言實(shí)戰(zhàn)技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12RecyclerView使用payload實(shí)現(xiàn)局部刷新
這篇文章主要為大家詳細(xì)介紹了RecyclerView使用payload實(shí)現(xiàn)局部刷新,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Android標(biāo)題欄上添加多個(gè)Menu按鈕的實(shí)例
這篇文章主要介紹了Android標(biāo)題欄上添加多個(gè)Menu按鈕的實(shí)例的相關(guān)資料,這里提供簡(jiǎn)單實(shí)例說(shuō)明如何添加多個(gè)menu按鈕的方法,需要的朋友可以參考下2017-09-09Android仿微信滑動(dòng)彈出編輯、刪除菜單效果、增加下拉刷新功能
這篇文章主要介紹了Android仿微信滑動(dòng)彈出編輯、刪除菜單效果、增加下拉刷新功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01Android界面 NotificationManager使用Bitmap做圖標(biāo)
Android界面 NotificationManager使用Bitmap做圖標(biāo),如何實(shí)現(xiàn)呢,本文將介紹解決方法,需要的朋友可以參考下2012-12-12Android App調(diào)試內(nèi)存泄露之Cursor篇
最近在工作中處理了一些內(nèi)存泄露的問(wèn)題,在這個(gè)過(guò)程中我尤其發(fā)現(xiàn)了一些基本的問(wèn)題反而忽略導(dǎo)致內(nèi)存泄露2012-11-11