文章

Bitmask

Bitmask

Android 中应用程序的状态表示

通过 int 值表示,通过 1 左移 n 位来表示不同的状态

int 值表示多种状态(最多 32 个状态)

1、Android 中应用程序的状态表示:一个 int 值有 32 位,Android 中用前 28 位,每一位代表一个功能 (一总状态)
0kobd

2、如:flags = 21

k685s

flags & FLAG_SYSTEM != 0 说明了第 0 位为 1,表示是系统应用,否则是非系统应用

3、再如

1
2
3
4
5
6
7
8
9
10
11
12
int flags = applicationInfo.flags;  
flags = 572998
转换成32位的二进制为0000 0000 0000 1000 1011 1110 0100 0110 
分析和定义好的常量进行&操作如果不为0表示该位为1
第0位为0第17位为0表示该应用不是系统应用没有安装在sd卡(安装在内置存储空间)
代码
if ((flags&ApplicationInfo.FLAG_EXTERNAL_STORAGE)!=0) {
    //表示应用安装在内部存储空间
}
if ((flags&ApplicationInfo.FLAG_SYSTEM)!=0) {
    //表示应用是系统应用
}

ApplicationInfo 中常见的状态

1
2
public static final int FLAG_SYSTEM = 1<<0;    //该位为1表示是系统应用
public static final int FLAG_EXTERNAL_STORAGE = 1<<18;  //该位为1表示应用安装在外部存储设备

应用:如果应用的状态过多,可以这样定义,如:一个电视频道的状态,游戏的状态机(满足很多条件才能做某件事)

qnv0d

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ApplicationInfo中定义的常量用一个int值来表示该应用的各种信息
ApplicationInfo applicationInfo = packageInfo.applicationInfo;  
public static final int FLAG_SYSTEM = 1<<0;  //if set, this application is installed in the * device's system image. 
public static final int FLAG_DEBUGGABLE = 1<<1; 
public static final int FLAG_HAS_CODE = 1<<2; 
......
public static final int FLAG_CANT_SAVE_STATE = 1<<28;     
int flags = packageInfo.applicationInfo.flags;  //Flags associated with the application.
flags是该应用程序信息的标识一个int来表示每一位代表一个信息
所以要想知道某一位是否设置了只需要将该flags和某一位进行与操作
如果为0说明该位没有设置否则表示该位设置了
(ApplicationInfo.FLAG_SYSTEM & flags) != 0  

应用如上面的手机频道项目一个频道有n多个属性该频道是否免费是否优惠是否在套餐中是否18岁以上才能看等10几个属性可以这样定义
private int isFree = 1<<0;
private int isFavorable 1<<1;
private int isInCombo 1<<2;
......
要想判断一个频道是否具备某些属性只需要将该频道的flag和某一个属性进行与操作
如果结果不等于0说明具备该属性

重要对于一些状态较多的可以借鉴这种方式定义状态

BitMask 之 int 表示 32 状态或 byte 表示 8 种状态

Bitmask 位操作,bit mask int bit int bit mask

在 Android 中,也大量地使用了 BitMask,比如 android.view.View 这个类。

位操作

1、NOT

1
2
3
4
int a = 1;
int b = ~a;

NOT 0000 0001 = 1111 1110

2、OR

1
2
3
int a = 1;
int b = 2;
int c = a | b;

3、AND

Bitmask

每一个 bit 可以有两种取值:0 或 1;

BitMask 采用一个数值来记录状态,使用这个数值的每一位来表达一个状态。 使用 BitMask 可用非常少的资源表达非常丰富的状态。更为重要的是,基于 BitMask 可 非常简单地进行组合状态查询

byte

在 Java 中,一个 byte 类型,有 8 位(bit),可以表达 8 个不同的状态,并且这些状态是互不影响的。

  • 设置状态
    设置状态即和 mask 值进行逻辑『或』
1
status |= mask;
  • 清除状态
    清除状态与 mask 的反码进行逻辑『与』运算。
  • 查询状态
    与 mask 进行逻辑『与』运行,判断是否为零即可

一个诗人的状态在喝酒还是在写作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public final class Poet {

    private byte mState;

    /**
     * 喝酒状态
     */
    // 0000 0010
    private static final byte STATE_BUSY_IN_WRITING = 0x01 << 1;

    /**
     * 写作状态
     */
    // 0000 0100
    private static final byte STATE_BUSY_IN_DRINKING = 0x01 << 2;

    /**
     * 边喝酒边写作状态
     */
    private static final byte STATE_BUSY_MASK = STATE_BUSY_IN_WRITING | STATE_BUSY_IN_DRINKING;


    /**
     * 设置是否在喝酒
     */
    public void setBusyInDrinking(boolean busy) {
        if (busy) {
            mState |= STATE_BUSY_IN_DRINKING;
        } else {
            mState &= ~STATE_BUSY_IN_DRINKING;
        }
    }

    /**
     * 设置是否在写作
     */
    public void setBusyInWriting(boolean busy) {
        if (busy) {
            mState |= STATE_BUSY_IN_WRITING;
        } else {
            mState &= ~STATE_BUSY_IN_WRITING;
        }
    }

    /**
     * 查询是否在喝酒
     */
    public boolean isBusyInDrinking() {
        return (mState & STATE_BUSY_IN_DRINKING) != 0;
    }

    /**
     * 查询是否在写作
     */
    public boolean isBusyInWriting() {
        return (mState & STATE_BUSY_IN_DRINKING) != 0;
    }

    /**
     * 是否处于忙碌状态
     */
    public boolean isBusy() {
        return (mState & STATE_BUSY_MASK) != 0;
    }
}

详细见 android-BitMaskSample

int

一个 int 类型,则有 32 位,可以表达 32 种状态。
一个 int 值 32 位,二进制数要转换为十六进制,就是以 4 位一段,分别转换为十六进制,如
0000 0000 , 1111 1101 , 1010 0101 , 1001 1011
0 0 , F D , A 5 , 9 B
十六进制表示就是:0x00FDA59B

Gson 中的 Modifier 大量用到

Reference

BitMask int 32 位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**
 * 64bit flag  <br/>
 * 1. 可根据按bit index add flag <br/>
 * 2. 也可以自定义flag位 <br/>
 */
public abstract class BitMaskLong {

    private static final long FLAG_UNKNOWN = 0x00;
    private static final long FLAG_BASE = 0x01;

    private long flags = FLAG_UNKNOWN;

    public BitMaskLong() {
        clearFlags();
    }

    public void addBitIndexFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex) {
        operateFlag(bitIndex, true);
    }

    public void clearBitIndexFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex) {
        operateFlag(bitIndex, false);
    }

    public boolean hasBitIndexFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex) {
        return hasFlag(FLAG_BASE << bitIndex);
    }

    // --------

    public void addFlag(long flag) {
        flags |= flag;
    }

    public boolean hasFlag(long flag) {
        return (flags & flag) != FLAG_UNKNOWN;
    }

    public void clearFlag(long flag) {
        flags &= ~flag;
    }

    // --------

    public BitMaskLong addAllFlags() {
        for (int i = 0; i < maxBitCount(); i++) {
            addBitIndexFlag(i);
        }
        return this;
    }

    public void clearFlags() {
        flags = FLAG_UNKNOWN;
    }

    public long getFlags() {
        return flags;
    }

    /**
     * set index位 flag
     *
     * @param bitIndex index bit位
     * @param isAdd    true设置flag,false清除flag
     */
    private void operateFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex, boolean isAdd) {
        if (bitIndex < 0 || bitIndex > maxBitCount() - 1) {
            throw new IllegalArgumentException("index must range 0~" + (maxBitCount() - 1) + " , current bitIndex is " + bitIndex);
        }
        if (isAdd) {
            addFlag(FLAG_BASE << bitIndex);
        } else {
            clearFlag(FLAG_BASE << bitIndex);
        }
    }

    // --------

    public int maxBitCount() {
        return Long.SIZE;
    }

    public String toBinaryString() {
        String binaryString = Long.toBinaryString(flags);

        while (maxBitCount() - binaryString.length() > 0) {
            binaryString = 0 + binaryString;
        }
        return binaryString;
    }

    public String toString() {
        int i = Long.bitCount(flags);
        StringBuilder sb = new StringBuilder();
        sb.append("[二进制位]");
        sb.append(toBinaryString());
        sb.append("[位数]");
        sb.append(i);
        return sb.toString();
    }
}

案例:控制新闻列表页的自动刷新逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public final class ListRefreshStateInt {

    public static class ArticleRefreshBitMaskInt extends BitMaskInt {
        private ArticleRefreshBitMaskInt() {
        }

        public static BitMaskInt newFlag() {
            return new ArticleRefreshBitMaskInt();
        }

        private static final int FLAG_BASE = 0x01;

        private static final int FLAG_SUBSCRIBE = FLAG_BASE << 0;
        private static final int FLAG_VIDEO = FLAG_BASE << 1;
        private static final int FLAG_TEXT = FLAG_BASE << 3;
        private static final int FLAG_IMAGE = FLAG_BASE << 5;


    }

    public static void main(String[] args) {
        test1();
//        test2();
    }

    // 自定义flag
    private static void test2() {
        BitMaskInt flags = ArticleRefreshBitMaskInt.newFlag();
        flags.addFlag(ArticleRefreshBitMaskInt.FLAG_TEXT | ArticleRefreshBitMaskInt.FLAG_VIDEO);
        System.out.println(flags.toString());
        flags.addFlag(ArticleRefreshBitMaskInt.FLAG_SUBSCRIBE | ArticleRefreshBitMaskInt.FLAG_IMAGE);
        System.out.println(flags.toString());
    }

    // 通过bit index 
    private static void test1() {
        BitMaskInt flags = ArticleRefreshBitMaskInt.newFlag();
//                .addFlags();
        flags.addBitIndexFlag(31);
        System.out.println(flags.toString());
    }

}

BitMask 应用

BitMask(long 64 bit) 实现列表各个列表刷新状态的控制

Long 版,支持最多 64 位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
 * 64bit flag  <br/>
 * 1. 可根据按bit index add flag <br/>
 * 2. 也可以自定义flag位 <br/>
 */
public abstract class BitMaskLong {

    private static final long FLAG_UNKNOWN = 0x00;
    private static final long FLAG_BASE = 0x01;

    private long flags = FLAG_UNKNOWN;

    public BitMaskLong() {
        clearFlags();
    }

    public void addBitIndexFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex) {
        operateFlag(bitIndex, true);
    }

    public void clearBitIndexFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex) {
        operateFlag(bitIndex, false);
    }

    public boolean hasBitIndexFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex) {
        return hasFlag(FLAG_BASE << bitIndex);
    }

    // --------

    public void addFlag(long flag) {
        flags |= flag;
    }

    public boolean hasFlag(long flag) {
        return (flags & flag) != FLAG_UNKNOWN;
    }

    public void clearFlag(long flag) {
        flags &= ~flag;
    }

    // --------

    public BitMaskLong addAllFlags() {
        for (int i = 0; i < maxBitCount(); i++) {
            addBitIndexFlag(i);
        }
        return this;
    }

    public void clearFlags() {
        flags = FLAG_UNKNOWN;
    }

    public long getFlags() {
        return flags;
    }

    /**
     * set index位 flag
     *
     * @param bitIndex index bit位
     * @param isAdd    true设置flag,false清除flag
     */
    private void operateFlag(@IntRange(from = 0, to = Long.SIZE - 1) int bitIndex, boolean isAdd) {
        if (bitIndex < 0 || bitIndex > maxBitCount() - 1) {
            throw new IllegalArgumentException("index must range 0~" + (maxBitCount() - 1) + " , current bitIndex is " + bitIndex);
        }
        if (isAdd) {
            addFlag(FLAG_BASE << bitIndex);
        } else {
            clearFlag(FLAG_BASE << bitIndex);
        }
    }

    // --------

    public int maxBitCount() {
        return Long.SIZE;
    }

    public String toBinaryString() {
        String binaryString = Long.toBinaryString(flags);

        while (maxBitCount() - binaryString.length() > 0) {
            binaryString = 0 + binaryString;
        }
        return binaryString;
    }

    public String toString() {
        int i = Long.bitCount(flags);
        StringBuilder sb = new StringBuilder();
        sb.append("[二进制位]");
        sb.append(toBinaryString());
        sb.append("[位数]");
        sb.append(i);
        return sb.toString();
    }

}

参考

  • Android 中 BitMask 的使用

http://wukongcode.com/2016-8-10-android-bitmask-md.html

本文由作者按照 CC BY 4.0 进行授权