为什么要通过 mask 的位运算才能判断 flag

2022-12-04 18:29:33 +08:00
 fhj

public static final int VISIBLE = 0x00000000;

public static final int INVISIBLE = 0x00000004;

public static final int GONE = 0x00000008;

static final int VISIBILITY_MASK = 0x0000000C;

判断 flags 时是这么判断的:if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE)

为什么不这样判断:if ((child.mViewFlags & VISIBLE) == VISIBLE)
9369 次点击
所在节点    Android
15 条回复
yongfrank
2022-12-04 18:34:21 +08:00
刚刚用 ChatGPT 出了一个答案

在计算机程序中,通过 mask 的位运算来判断 flag 通常是为了将 flag 的多个属性(例如是否启用、是否可读、是否可写等)用一个整数来表示。

在位运算中,通过与掩码( mask )进行与(&)运算可以判断 flag 的某一位是否被设置为 1 。例如,如果要判断 flag 的第 3 位是否被设置为 1 ,可以将 flag 与掩码 0b100 进行与运算,如果结果为 0 则表示 flag 的第 3 位被设置为 0 ,否则表示 flag 的第 3 位被设置为 1 。

使用 mask 的位运算来判断 flag 的好处在于它可以节省存储空间,将多个属性用一个整数来表示,而不需要单独开辟多个变量来存储每个属性。例如,如果使用多个变量来表示 flag 的多个属性,则需要开辟多个 8 位的存储空间,而如果使用 mask 的位运算,则只需要开辟一个 8 位的存储空间就可以表示多个属性。
hello2090
2022-12-04 18:34:47 +08:00
你这个 if ((child.mViewFlags & VISIBLE) == VISIBLE) 不是 永远 true 吗?
fhj
2022-12-04 18:37:40 +08:00
@hello2090 mViewFlags 没有设置不就是 false 了吗
Cat7373
2022-12-04 18:39:19 +08:00
@hello2090 #2 并不是的,MASK 说明了 0x0C 这一位表示是否可视,VISIBLE 的值说明了这一位是 0 时是可视,是 1 时是不可视,即 MASK 表示哪一位代表这个开关,VISIBLE 表示值是什么的时候代表什么结果
fhj
2022-12-04 18:40:06 +08:00
@yongfrank 谢谢,刚才看到一段这样的代码,这或许就是 mask 的作用把
switch (mViewFlags&VISIBILITY_MASK) {
case VISIBLE: out.append('V'); break;
case INVISIBLE: out.append('I'); break;
case GONE: out.append('G'); break;
default: out.append('.'); break;
}
cxtrinityy
2022-12-04 18:40:40 +08:00
VISIBILITY_MASK 是 0x0000000C -- 二进制是 1100
invisible 是 0x00000004 -- 二进制是 0100
gone 是 0x00000008 -- 二进制是 1000
也就是 gone 和 invisible 是用不同位来表示, visible 要保证 gone 和 invisible 都未设置, 一次位运算就能验证两个设置
Cat7373
2022-12-04 18:41:29 +08:00
@Cat7373 #4 修正一下,0x0C 有两个 bit 位为 1 ,因此这两个 bit 位任意一个为 1 ,此判断结果都为不可视,均为 0 ,才为可视,具体代码设计中,这两个 bit 位各代表什么意思这里看不出,但设计上可以实现,有两个各代表某个意思的开关,任意一个打开,都代表不可视
Cat7373
2022-12-04 18:42:03 +08:00
@cxtrinityy #6 啊这,没注意到上面两个常量,丢人了丢人了
viggoc
2022-12-04 18:43:27 +08:00
@fhj #3 任何数 & 0x00000000 不都是 0x00000000 吗
fhj
2022-12-04 18:47:06 +08:00
@viggoc 那应该是默认是 0,有其他需要再设置就好了
DeweyReed
2022-12-04 18:48:15 +08:00
public static final int VISIBLE = 0x00000000;
jeesk
2022-12-04 21:58:02 +08:00
最近自己优化内存用到的代码直接贴出来给你了。
```
object BitStatesUtils {
const val isFavorite = (1L shl 0).toByte()
const val isDownload = (1L shl 1).toByte()
const val isTrashed = (1L shl 2).toByte()

public const val SIZE_BITS: Byte = 0

/**
* @param states 所有状态值
* @param value 需要判断状态值
* @return 是否存在
*/
fun hasState(states: Byte, value: Byte): Boolean {
val byte = (states and value) as Byte
return byte != SIZE_BITS
}

fun Byte.HasState(value: Byte): Boolean {
return BitStatesUtils.hasState(this, value)
}

/**
* @param states 已有状态值
* @param value 需要添加状态值
* @return 新的状态值
*/
fun addState(states: Byte, value: Byte): Byte {
return if (hasState(states, value)) {
states
} else (states or value)
}

fun Byte.AddState(value: Byte): Byte {
return addState(this, value)
}

/**
* @param states 已有状态值
* @param value 需要删除状态值
* @return 新的状态值
*/
fun removeState(states: Byte, value: Byte): Byte {
return if (!hasState(states, value)) {
states
} else (states xor value)
}


}
```
FranzKafka95
2022-12-04 23:04:47 +08:00
嵌入式里很常见的操作,尤其是当你需要用一个 bit 表示一个状态,同时又想节省空间时,位操作就非常有必要了。
Building
2022-12-04 23:11:22 +08:00
Mask 和 Optional Value 就像锁和钥匙,你可以把运算过程想像成把钥匙插入锁里面,全部凹槽都配平才能打开
lysS
2022-12-05 11:53:11 +08:00
用位表示 flag ,是为了正交隔离

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/900022

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX