一、基础知识点概括
在查看源码中,经常会看到很多这样的符号“&”、“|”、“~”,"^","<>"很多人对此比较头疼,现在来简单讲述下这些符号的用法以及在项目中的实用:
1、与运算符 &
知识点:两位同时为“1”,结果才为“1”,否则为“0”。
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;
其实就是运算的位要完全一样,才保持原样,否则就变为0。
2、或运算符 |
知识点:只要有一位为1,其值为1,否则为“0”。
运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=1;
其实就是只要有1,结果就为1。
3、与运算符 ^
知识点:只要有两个是相异的,为1,否则为“0”。
运算规则:0|0=0; 0|1=1; 1|0=1; 1|1=0;
其实就是不同为1,相同为0。
4、与运算符 ~
知识点:对各二进位按位求反。
~(000001)=111110
5、左移运算符 <<
知识点:左移运算符“<
例如: a<<4 指把a的各二进位向左移动4位。如a=00000011(十进制3),左移 4位后为00110000(十进制48)。
6、又移运算符 >>
知识点:右移运算符“>>”是双目运算符。右移n位就是除以2的n次方。
例如:设 a=15,a>>2 表示把000001111右移为00000011(十进制3)。
二、运算符在源码中的体现
首先是左移动和右移运算符,想到了啥?
android 源码里经典的MeasureSpec类啊。我们来看下其成员变量:
public static class MeasureSpec {
private static final int MODE_SHIFT = 30;
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
/** @hide */
@IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
@Retention(RetentionPolicy.SOURCE)
public @interface MeasureSpecMode {}
/**
* Measure specification mode: The parent has not imposed any constraint
* on the child. It can be whatever size it wants.
*/
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
/**
* Measure specification mode: The parent has determined an exact size
* for the child. The child is going to be given those bounds regardless
* of how big it wants to be.
*/
public static final int EXACTLY = 1 << MODE_SHIFT;
/**
* Measure specification mode: The child can be as large as it wants up
* to the specified size.
*/
public static final int AT_MOST = 2 << MODE_SHIFT;
首先我们都知道measure的参数就是传measurespec的两个值进去,也就是两个32位的int值,而这个一个32位的int值包括了宽高信息以及测量模式,那实现原理就是如此。
从源码中看到MODE_MASK其实就是
0000 0000 0000 0000 0000 0000 0000 0011
左移30位就是
1100 0000 0000 0000 0000 0000 0000 0000
以此类推:
UNSPECIFIED:
0000 0000 0000 0000 0000 0000 0000 0000
EXACTLY:
0100 0000 0000 0000 0000 0000 0000 0000
AT_MOST:
1000 0000 0000 0000 0000 0000 0000 0000
由此可见:
把32位的前2位是测量模式,后30位是值的存放地,再来看下makeMeasureSpec的具体实现:
public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
@MeasureSpecMode int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
分析下:
比如size是503:(传进去size),mode是EXACTLY
size & ~MODE_MASK
~MODE_MASK 就是
0011 1111 1111 1111 1111 1111 1111 1111
503的二进制是:
0000 0000 0000 0000 0000 0001 1111 0111
结果为:
0000 0000 0000 0000 0000 0001 1111 0111
(mode & MODE_MASK);
mode 为
0100 0000 0000 0000 0000 0000 0000 0000
MODE_MASK:
1100 0000 0000 0000 0000 0000 0000 0000
结果就是
0100 0000 0000 0000 0000 0000 0000 0000
两者的结果为
0100 0000 0000 0000 0000 0001 1111 0111
此时宽高信息以及测量模式都保存在了一个int值中
然后在看下get的代码:
@MeasureSpecMode
public static int getMode(int measureSpec) {
//noinspection ResourceType
return (measureSpec & MODE_MASK);
}
/**
* Extracts the size from the supplied measure specification.
*
* @param measureSpec the measure specification to extract the size from
* @return the size in pixels defined in the supplied measure specification
*/
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
}
很明显把刚刚的值通过&运算符与遮罩mode(mode_mask)运算后就能获得宽高信息以及尺寸的大小了。
总结;
只介绍了部分的运算符的一处用法,其实在view里的mViewFlags也是相同的用法,省去了很多变量的命名。
最后很多用法等着我们去挖掘~