ForewordIntheAndroidsourcecode,themanagementof"multi-state"isalwaysrepresentedbyhexadecimalnumbers,similartothisformat://ViewGroup.javaprotectedintmGroupFlags;staticfinalintFLAG_CLIP_CHILDREN=0x1;privatestaticfinalintFLAG_CLIP_TO_PADDING=0x2;staticfinalintFLAG_INVALIDATE_REQUIRED_REQUIRED_REQUIRED_PrivatestaticR=0x8;staticfinalintFLAG_ANIMATION_DONE=0x10;privatestaticfinalintFLAG_PADDING_NOT_NULL=0x20;那么,大家有没有想过,在遇到多状态管理的时候,为什么要选择使用十六进制呢?简单的状态表示举一个实际的例子,作为一个人,我们必然会有很多标签,比如帅气、可爱、知识渊博、机智、懒惰、小资。对于这些标签,我们可以设置不同的person设置://定义实体类dataclassPerson(vartag:String)//修改标签valperson1=Person("handsome")//判断标签funisCute():Boolean{returnperson1.tag=="cute"}当一个人只有一个标签时,很简单,直接赋值或判断值即可。但是如果一个人有多个标签呢?也很简单,就是用一个集合来存储:person2.tags.contains("cute")但是使用了集合之后,计算就变得复杂了,因为remove和contains方法都是遍历集合实现的,从时间复杂度来看,删除一个的时间复杂度标记或判断标记是否存在是O(n)。有没有什么办法可以让多个标签像刚才的单个标签一样方便使用呢?当然还有二元运算,不然就不会有这篇文章了。在此之前,我们先来回顾几个二元运算。1.按位与(&)当两个对应位的值都为1时,结果为1,否则为0。例子:0x1&0x40001&0100=00002.按位或(|)当两个值都为1时,结果为0。对应的两个位为1,则结果为1。例:0x1|0x40001|0100=01013.否定(~)逐位反转数字。例子:~0x10001~=1110好了,有了这三个操作,我们的状态管理就足够了。引入十六进制接下来,让我们完成一个完整的状态管理示例。//设置所有状态对应的十六进制值//可爱,对应二进制0001valTAG_CUTE=Ox1//帅气,对应二进制0010valTAG_HANDSOME=Ox2//博学,对应二进制0100valTAG_LEARNED=Ox4varpersonTag=0状态增加如果一个二进制数想要留下另一个二进制数的踪迹,我们可以使用OR运算,这样只要第二个数的某位有1,最后的结果也一定是同一位为1。因此,我们可以用这个方法来完成增加状态的功能://增加可爱的状态personTag|=TAG_CUTE0000|0001=0001这样操作后,personTag的第4位数字就会变成1,也有TAG_CUTE标记向上。去除状态按照上面的逻辑,去除状态其实就是需要把对应的位从1变成0。假设personTag当前的值变成了二进制数0111。如果要删除TAG_CUTE属性,需要改变1的第4位变成0。那么我们可以做的就是先把TAG_CUTE取反,也就是把0001变成1110。然后和personTag做AND运算,这样第4位肯定会变成0,而数值其他位保持不变。//personTag为二进制数0111personTag&=~TAG_CUTE0001~=1110&0111=0110完成TAG_CUTE状态的去除。状态判断是一样的。判断是否存在某个状态,其实就是判断某个位的值是否为1。所以我们只需要对状态进行AND运算即可。如果结果为0,则表示不存在该状态,否则表示存在该状态。//personTag是一个二进制数0111(personTag&TAG_CUTE)!=00111&0001=0001,结果不为0,说明personTag包含TAG_CUTE的状态。细心的朋友可能会发现我们刚才用的十六进制值跳过了Ox3的值。为什么?其实不难发现,所谓通过十六进制来管理状态,其实就是通过二进制来管理状态,归根结底是通过二进制中1所在的位数来管理的。因此,我们需要选择一个占用单个位的二进制值进行状态赋值,如0001、0010、0100、1000、10000等。如果使用其他值会怎样?例如,增加Ox3的TAG。//lazy,对应二进制0011valTAG_LAZY=Ox3//添加可爱状态personTag|=TAG_CUTE//添加帅气状态personTag|=TAG_HANDSOME我们添加可爱帅气状态后,pe??rsonTag的二进制值为0011,此时判断是否包含惰性状态://是否包含惰性状态(personTag&TAG_LAZY)!=00011&0011=0011结果不为0,我们是否添加了惰性状态?显然不是,我不懒惰却说我懒惰,这是诬告!那么你了解状态值的范围吗?为什么是十六进制?至此,实现了通过十六进制管理状态的功能。显然,以这种方式管理状态要容易得多。基本原理是通过二进制计算来管理状态。有人又要问了,既然本质是通过二进制来完成管理,那么也可以用十进制来表示,比如上面的例子://设置所有状态对应的十进制值//Cute,对应二进制0001valTAG_CUTE=1//帅气,对应二进制0010valTAG_HANDSOME=2//有教养,对应二进制0100valTAG_LEARNED=4varpersonTag=0这不是和十六进制一样吗?从根本上来说确实是一样的,但是十六进制中有十六进制的好处,这就涉及到为什么要设计十六进制的原因了。在计算机中,一个字节有八位,最大值为11111111。对应的十进制数为255,对应的十六进制数为FF。所以,半个字节在十六进制中可以用一个字母来表示,换算成十进制就是一个不规则的数。为了方便,代码中一般用十六进制来表示二进制,因为这样可以和二进制进行更方便直观的转换。小结今天给大家介绍一下源码中常用的十六进制转二进制管理状态的方法。简单的基本原则解决大问题,也许这就是简单的意义吧?
