<Android>16进制妙用

3,409 阅读3分钟

前言

之前翻看View源码,浏览的过程中就看到过很多十六进制的常量,以及位运算。

// View.class源码
static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1;
static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2;
static final int PFLAG3_IS_LAID_OUT = 0x4;
static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8;
static final int PFLAG3_CALLED_SUPER = 0x10;
static final int PFLAG3_APPLYING_INSETS = 0x20;
static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40;
static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80;
static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100;
...
// intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)

但始终没有思考为什么要这样写。恰巧近日在掘金上发现一篇就算不去火星种土豆,也请务必掌握的 Android 状态管理最佳实践!,讲的就是Android利用16进制进行多状态管理。

思考

Q: 遇到多状态的情况,原来我是怎样处理的?
A: 通过字符串的拼接;采用容器如数组,list或map;
Q: 16进制如何进行多状态管理,有什么样优势?
A: 整理如下!

16进制与2进制

理论基础

  • 掌握16进制与2进制之间的转化,16进制每位对应4位2进制。
  • 掌握位运算
    • 与: 0x6 & 0x4 ==> 0110 & 0100 = 0100
    • 或: 0x2 | 0x4 ==> 0010 | 0100 = 0110
    • 取反: ~ 0x2 ==> ~ 0010 = 1101

实战演练

/**
 * 比如天气有多种状态:
 * snow :雪
 * rain :雨
 */
const val snow  = 0x1  //0001
const val rain  = 0x2  //0010
const val sun   = 0x4  //0100
const val cloud = 0x8  //1000
...
//当前天气是雨夹雪,就可以表示为: snow | rain
val weather = snow or rain  
//  0011    = 0001 |  0010
...
//过了一会儿,不下雨了: snow & ~rain
weather = weather and rain.inv()
// 0001  =  0011    &   ~ 0010   = 0011 & 1101
...
//判断当前是不是下雨 (weather & rain)
val isSnow = weather and rain
//  0000   =  0001    &  0010

注意注释,可以更好的辅助理解

用法与优势

上述简单的举例,用法总结:

  • 当需要增加状态 采用 按位或
  • 当需要移除状态 采用 取反后,按位与
  • 当需要判断状态 采用 按位与,判断结果是否为0,为0则不存在,反之存在
  • 重中之重

相较于原来的字符串拼接或是集合的方式,优势尤为明显:

  • 状态的增加或删除更容易,不需要字符串拆分或集合添加移除
  • 判断状态更方便,不需要集合遍历
  • 仅用int类型就可以完成状态的管理,对于存储更轻量

重中之重

16进制多状态管理本质上是二进制管理,即‘1’所处的位数。

  • 每种状态只能取单独位上为‘1’的二进制值,如下图所示 image.png

  • 之所以要这样,可以通过设置一个其他值验证下,就会知道只能按上述定义取值。

    const val snow = 0x3  //0011
    const val rain = 0x2  //0010
    ...
    //当前天气是雨夹雪,就可以表示为: snow | rain
    val weather = snow or rain  
    //  0011    = 0011 |  0010
    
    //这里可以看到,下雪状态设置成0x3,当状态增加时,或运算后,不足够表示雨夹雪状态。
    
  • 既然本质是二进制,那么用其他进制如十进制应该也是可以的。但之所以选16进制,可能是更容易转换,更直观吧。
    image.png

参考

就算不去火星种土豆,也请务必掌握的 Android 状态管理最佳实践!