今天准备讲讲在Android Framework中按位操作符的运用,讲之前大家最好再回顾一下,按位“与”(&)、按位“或”(|)、按位“非”(~)、按位“异或”(^)的定义
// VISIBILITY_MASK = VISIBLE + INVISIBLE + GONE
// VISIBILITY_MASK 称为掩位码
public static final int VISIBLE = 0x00000000;
public static final int INVISIBLE = 0x00000004;
public static final int GONE = 0x00000008;
static final int VISIBILITY_MASK = 0x0000000C;
private static final int NOT_FOCUSABLE = 0x00000000;
private static final int FOCUSABLE = 0x00000001;
private static final int FOCUSABLE_MASK = 0x00000001;
static final int ENABLED = 0x00000000;
static final int DISABLED = 0x00000020;
static final int ENABLED_MASK = 0x00000020;
int mViewFlags;
通过View源码,看看能不能发现什么规律。
- INVISIBLE + VISIBLE + GONE = VISIBILITY_MASK
- INVISIBLE & VISIBILITY_MASK; //0100 & 1100 = 0100; = >INVISIBLE
- VISIBLE & VISIBILITY_MASK;// 0000 & 1100 = 0000;=> VISIBLE
- GONE & VISIBILITY_MASK;// 1000 & 1100 = 1000; => GONE
- mViewFlags = INVISIBLE | FOCUSABLE;// 0100 | 0001= 0101
- mViewFlags & FOCUSABLE_MASK;// 0101 & 0001 = 0001; => FOCUSABLE
- mViewFlags & ENABLED_MASK;// 000101 & 100000 = 000000; => ENABLE
- mViewFlags & = ~INVISIBLE;// mViewFlags = 0101 & 1011 = 0001 =>FOCUSABLE
- mViewFlags & = ~FOCUSABLE;// mViewFlags = 0001 & 1110 => 0
- 重新执行第5步mViewFlags = 0101
- mViewFlags & ~VISIBILITY_MASK;// 0101 & 0011 = 0001;=> FOCUSABLE
小结:
- 1,2,3,4是这类常量在View或者Android中的通用规律,
INVISIBLE
、VISIBLE
、GONE
都是控制View的可见性的常量,而VISIBILITY_MASK恰好是这三个常量之和,前面三个常量的每一个与VISIBILITY_MASK按位“与”操作可得到本身的值。 - 5用到了按位“或”操作,可以使用按位“或”(|),来为mViewFlags添加值。
- 6表示与FOCUSABLE_MASK进行按位“与”(&),可以得到对应的XX_MASK属性的状态。
- 7表示与ENABLED_MASK进行按位“与”(&),得到了对应ENABLED_MASK的属性的默认状态ENABLED
- 8,9则表明可以用
&= ~
的方式从mViewFlags删除某个值 - 10,11则表明通过mViewFlags & ~XX_MASK可以删除这一类的标记
接下来在View.java
中还有一处用到了按位运算:
// 这里假设 mViewFlags = FOCUSABLE | SAVE_DISABLED = 0x00000001 | 0x000010000
// => 0x00010001
// flags 和mask这两个参数,我们调用setVisibility(View.GONE),即
// flags = GONE,mask = VISIBILITY_MASK
void setFlags(int flags, int mask) {
int old = mViewFlags;// old = 0x00010001
// mViewFlags = (0x00010001 & 0x11110011) | (0x00001000 & 0x00001100)
// = 0x00010001 | 0x00001000
// = 0x00011001
mViewFlags = (mViewFlags & ~mask) | (flags & mask);
int changed = mViewFlags ^ old; // 0x00011001 ^ 0x00010001 = 0x00001000 // = GONE
if (changed == 0) {
return;
}
}
小结:
- 其中比较难理解的一句就是mViewFlags = (mViewFlags & ~mask) | (flags & mask);上面的小结中已经提到了
mViewFlags & ~mask
是将mask下的标记删除;flags & mask
也在上一小结中介绍过可以得到flags
,这样(mViewFlags & ~mask) | (flags & mask)的结果就是将mask下的flags添加到mViewFlags中。 - 一个是带有新的mViewFlags,一个是旧的mViewFlags(old),从得出的结果0x00001000(GONE),恰好是要添加的新flags—GONE。所以这里的按位“异或”就是获得两者的差异。
总结:
Android中使用按位操作来计算某种属性(比如,可见性)状态的改变。特征是状态1;状态2;。。。状态n,属性_MASK。这里的属性_MASK叫做掩码(MaskBit)。XX_MASK = 状态1 + 状态2 + 。。。+ 状态n;
不同的属性应该有默认状态,比如visibility(可见性)默认值是VISIBLE(0X00000000),所有的默认值都是0;这样做的好处是不用初始化。
运算
添加某种状态:
mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
删除特定的某种状态:
viewFlagValues &= ~SOUND_EFFECTS_ENABLED;// 方法一 mViewFlags ^= SCROLLBARS_HORIZONTAL;//方法二
删除某种属性
mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK;
获取指定属性的状态值
public int getVisibility() { return mViewFlags & VISIBILITY_MASK; }
比较两个flags的区别
int old = mViewFlags; mViewFlags = (mViewFlags & ~mask) | (flags & mask); int changed = mViewFlags ^ old;