Android源码中的位运算

97 阅读8分钟

在android的系统类中经常可以看到巧妙的位运算,下面我们来学习一下。

例如View中的flag

static final int PFLAG_WANTS_FOCUS                 = 0x00000001;
/** {@hide} */
static final int PFLAG_FOCUSED                     = 0x00000002;
/** {@hide} */
static final int PFLAG_SELECTED                    = 0x00000004;
/** {@hide} */
static final int PFLAG_IS_ROOT_NAMESPACE           = 0x00000008;
/** {@hide} */
static final int PFLAG_HAS_BOUNDS                  = 0x00000010;
/** {@hide} */
static final int PFLAG_DRAWN                       = 0x00000020;
/**
 * When this flag is set, this view is running an animation on behalf of its
 * children and should therefore not cancel invalidate requests, even if they
 * lie outside of this view's bounds.
 *
 * {@hide}
 */
static final int PFLAG_DRAW_ANIMATION              = 0x00000040;
/** {@hide} */
static final int PFLAG_SKIP_DRAW                   = 0x00000080;
/** {@hide} */
static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200;
/** {@hide} */
static final int PFLAG_DRAWABLE_STATE_DIRTY        = 0x00000400;
/** {@hide} */
static final int PFLAG_MEASURED_DIMENSION_SET      = 0x00000800;
/** {@hide} */
static final int PFLAG_FORCE_LAYOUT                = 0x00001000;
/** {@hide} */
static final int PFLAG_LAYOUT_REQUIRED             = 0x00002000;

private static final int PFLAG_PRESSED             = 0x00004000;

/** {@hide} */
static final int PFLAG_DRAWING_CACHE_VALID         = 0x00008000;
/**
 * Flag used to indicate that this view should be drawn once more (and only once
 * more) after its animation has completed.
 * {@hide}
 */
static final int PFLAG_ANIMATION_STARTED           = 0x00010000;

private static final int PFLAG_SAVE_STATE_CALLED   = 0x00020000;

/**
 * Indicates that the View returned true when onSetAlpha() was called and that
 * the alpha must be restored.
 * {@hide}
 */
static final int PFLAG_ALPHA_SET                   = 0x00040000;

/**
 * Set by {@link #setScrollContainer(boolean)}.
 */
static final int PFLAG_SCROLL_CONTAINER            = 0x00080000;

/**
 * Set by {@link #setScrollContainer(boolean)}.
 */
static final int PFLAG_SCROLL_CONTAINER_ADDED      = 0x00100000;

/**
 * View flag indicating whether this view was invalidated (fully or partially.)
 *
 * @hide
 */
static final int PFLAG_DIRTY                       = 0x00200000;

/**
 * Mask for {@link #PFLAG_DIRTY}.
 *
 * @hide
 */
static final int PFLAG_DIRTY_MASK                  = 0x00200000;

/**
 * Indicates whether the background is opaque.
 *
 * @hide
 */
static final int PFLAG_OPAQUE_BACKGROUND           = 0x00800000;

/**
 * Indicates whether the scrollbars are opaque.
 *
 * @hide
 */
static final int PFLAG_OPAQUE_SCROLLBARS           = 0x01000000;

/**
 * Indicates whether the view is opaque.
 *
 * @hide
 */
static final int PFLAG_OPAQUE_MASK                 = 0x01800000;

/**
 * Indicates a prepressed state;
 * the short time between ACTION_DOWN and recognizing
 * a 'real' press. Prepressed is used to recognize quick taps
 * even when they are shorter than ViewConfiguration.getTapTimeout().
 *
 * @hide
 */
private static final int PFLAG_PREPRESSED          = 0x02000000;

/**
 * Indicates whether the view is temporarily detached.
 *
 * @hide
 */
static final int PFLAG_CANCEL_NEXT_UP_EVENT        = 0x04000000;

/**
 * Indicates that we should awaken scroll bars once attached
 *
 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged
 * during window attachment and it is no longer needed. Feel free to repurpose it.
 *
 * @hide
 */
private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;

/**
 * Indicates that the view has received HOVER_ENTER.  Cleared on HOVER_EXIT.
 * @hide
 */
private static final int PFLAG_HOVERED             = 0x10000000;

/**
 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked.
 */
private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000;

/** {@hide} */
static final int PFLAG_ACTIVATED                   = 0x40000000;

/**
 * Indicates that this view was specifically invalidated, not just dirtied because some
 * child view was invalidated. The flag is used to determine when we need to recreate
 * a view's display list (as opposed to just returning a reference to its existing
 * display list).
 *
 * @hide
 */
static final int PFLAG_INVALIDATED                 = 0x80000000;

这些flag都是int类型的,并且都是以0x开头的也就是十六进制数。这些flag转为二进制后有个特点只有一位为1,其余都是0

// 0000 0000 0000 0000 0000 0000 0000 0000  //二进制转为十进制0
// 代表什么标志位都没有
int flag_mask = 0x00000000;  //十六进制0的写法

// 0000 0000 0000 0000 0000 0000 0000 0001  //二进制转为十进制1   等同于1<<0
int a1 = 0x00000001;  //十六进制1的写法

// 0000 0000 0000 0000 0000 0000 0000 0010  //二进制转为十进制2   等同于1<<1
int a2 = 0x00000002;  //十六进制2的写法

// 0000 0000 0000 0000 0000 0000 0000 0100 //二进制转为十进制4    等同于1<<2
int a3 = 0x00000004;  //十六进制4的写法

// 0000 0000 0000 0000 0000 0000 0000 1000 //二进制转为十进制8    等同于1<<3
int a4 = 0x00000008;  //十六进制8的写法

// 0000 0000 0000 0000 0000 0000 0001 0000 //二进制转为十进制16   等同于1<<4
int a5 = 0x00000010;  //十六进制16的写法

// 0000 0000 0000 0000 0000 0000 0010 0000 //二进制转为十进制32   等同于1<<5
int a6 = 0x00000020;  //十六进制32的写法

1 添加标志:

//现在我们往flag_mask添加标志a1,a4
        flag_mask |= a1;
        flag_mask |= a4;
        Log.i("zhangqing","添加标志:"+Integer.toBinaryString(flag_mask));

//        分析:
//        flag_mask=00000000 00000000 00000000 00000000  int是4字节,32位的
//        a1       =00000000 00000000 00000000 00000001
//        按位或操作的结果:
//        result   =00000000 00000000 00000000 00000001
//        a4       =00000000 00000000 00000000 00001000
//        result1  =00000000 00000000 00000000 00001001
//        所以通过|操作符可以实现标志位的添加功能

运行结果:

image.png

结果转为十六进制0x00001001

2 提取标志

//提取标志
        //提取的功能主要是用来判断某个标志位是否存在,是否已经设置了
        boolean isA1Seted = (flag_mask & a1) == a1;
        Log.i("zhangqing", "a1是否设置:" + isA1Seted);

        boolean isA4Seted = (flag_mask & a4) == a4;
        Log.i("zhangqing", "a4是否设置:" + isA4Seted);

        boolean isA3Seted = (flag_mask & a3) == a3;
        Log.i("zhangqing", "a4是否设置:" + isA3Seted);


//        分析:
//        flag_mask=00000000 00000000 00000000 00001001  int是4字节,32位的
//        a1       =00000000 00000000 00000000 00000001
//        a4       =00000000 00000000 00000000 00001000
//        a3       =00000000 00000000 00000000 00000100
//        通过按位于操作符&
//        resultA1 =00000000 00000000 00000000 00000001
//        resultA4 =00000000 00000000 00000000 00001000
//        resultA3 =00000000 00000000 00000000 00000000
//        所以要提取某个标志位,然后判断是否存在就使用&操作符

image.png

3 删除标志

//删除标志
        //有的时候我们会把某个标志从mask里面删除,该怎么操作呢?
        flag_mask &= ~a1;
        flag_mask &= ~a4;

        Log.i("zhangqing", "删除后的结果flag_mask:" + Integer.toBinaryString(flag_mask));
//        分析:
//        flag_mask=00000000 00000000 00000000 00001001  int是4字节,32位的
//        ~a1      =11111111 11111111 11111111 11111110  按位取反的结果
//        ~a4      =11111111 11111111 11111111 11110111  按位取反的结果
//        按位与&
//        flag_mask=00000000 00000000 00000000 00001000
//        flag_mask=00000000 00000000 00000000 00000000
//        最终结果把a1和a4都删除了

image.png

结果转为十六进制0x00000000

系统的源代码就是最好的老师,我们经常熟悉android源码,可以取其精华。