写点什么

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

作者:嘟嘟侠客
  • 2021 年 11 月 28 日
  • 本文字数:2839 字

    阅读完需:约 9 分钟

此外,是只有封装 SDK 这种大动作,才值得使用十六进制吗?不是的,恰恰相反,正因为 十六进制状态管理是如此地普适,乃至于连封装 SDK 都优先使用这种方式。


考虑到部分读者可能对十六进制本身不太了解,本文会连同十六进制一起介绍。


所以如果阅读完这篇文章,你对 十六进制的状态管理 有了感性的认识,那我的愿望也就达到了。

我和十六进制的 “三次握手”

最开始对十六进制产生了兴趣,或者说,知道了它在什么时候能派上用场,是在 2015 年观看《火星救援》这部电影时发现的。



为了和 “远在 4 亿公里外、电磁波需要 40 分钟才能完成一次完整的请求响应的” 地球通信,孑然一身的主角 Mark 想到了一个办法,就是通过十六进制和 ACSII 码表:


将字符转换成字母 ,这样地球上的人就可以通过控制 “Mark 从沙漠中掏来的、1997 年服役的” 探路者号(PathFinder)的摄像头偏移角度,来指明一连串的字符,从而 Mark 可以将它们转译成英文。



第二次接触十六进制是在 2016 年,当我阅读 View/ViewGroup 源码时,发现一些状态标记都是通过十六进制状态管理,但当时因为不知道为何这么使用、这样使用究竟有什么好处,也就没大注意。


@Overridepublic void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {// We're already in this state, assume our ancestors are tooreturn;}if (disallowIntercept) {mGroupFlags |= FLAG_DISALLOW_INTERCEPT;} else {mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;}// Pass it up to our parentif (mParent != null) {mParent.requestDisallowInterceptTouchEvent(disallowIntercept);}}


直到 2017 年的夏天,我在和一位彼时 3 年经验的同事,联手完成当年扛鼎项目的核心功能时,因同事提出使用十六进制管理状态,而亲眼见证了十六进制在状态管理方面的绝佳优势。


为了纪念同事的这一分享,此后每当有新同事入职,我提供的培训课程必包含十六进制状态管理。


使用十六进制前的混沌世界

该项目有个需求:当指定图形编辑的模式时,图形工具栏的按钮状态要随之发生配套性地变化。


例如,存在 3 种图形编辑模式,和 8 个图形编辑按钮。


模式 A 下,要求 按钮 1、按钮 2、按钮 3 可用,其他按钮禁用。


模式 B 下,要求 按钮 1、按钮 4、按钮 5、按钮 6 可用,其他按钮禁用。


模式 C 下,要求 按钮 1、按钮 7、按钮 8 可用,其他按钮禁用。



如果是传统方式编写,我们势必会在类中为 3 个模式定义 boolean 变量,为 8 个按钮状态定义 boolean 变量。


那么在模式切换时,就需要将每个按钮状态的变量都 “清洗” 一遍。例如:


public void setModeA() {status1 = true;status2 = true;status3 = true;status4 = false;status5 = false;status6 = false;status7 = false;status8 = false;}


public void setModeB() {status1 = true;status2 = false;status3 = false;status4 = true;status5 = true;status6 = true;status7 = false;status8 = false;}


public void setModeC() {...}


那要是日后模式变多、按钮状态变多,类中就会满是这种 setMode 的方法,看起来很蠢,而且密密麻麻的 true、false,极容易出错。


这是一点。


另一点就是,如果按钮状态是用 boolean 变量来管理,那么状态的存储和读取怎么办呢?


  • 每个 boolean 变量都要转换成 int 类型的 0 或 1 存储在数据库中。

  • 数据库需要为每个状态准备一个字段。

  • 读取的时候又要负责将每个状态转译回 boolean。


这工作量也太大了!而且日后每添加或修改一个状态,数据库都要新增或修改字段,这非常低效和不安全!

十六进制能很好地解决这些问题

十六进制可以做到:



    《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

    【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享


    通过状态集的注入,一行代码即可完成模式的切换。


    • 无论再多的状态,都只需要一个字段来存储。状态被存放在 int 类型的状态集中,可以直接向数据库写入或读取。

    十六进制的运作机制

    在具体了解十六进制是怎么做到状态管理最佳实践之前,我们先简单过一遍十六进制本身的运作机制。


    首先,在编程中,利用开头 0x 表示十六进制数。


    例如 0x0001,0x0002。


    然后,十六进制的计算,我们可以借助二进制的 “按位计算” 方式来理解。


    二进制存在 与、或、异或、取反 等操作:


    a & b,a | b,a ^ b,~a


    例如,十六进制数 0x0004 | 0x0008,可以理解为:

    0100|1000

    1100


    十六进制 (0x0004 | 0x0008) & 0x0004 可以得到:

    1100&0100

    0100


    也即状态集中包含某状态时,再与上该状态,就会得到非 0 的结果。


    于是,我们就可以利用这个特性来完成状态管理:

    十六进制的状态管理实战

    • 首先我们定义一个状态集变量,用来存放当前模式的状态集,例如:


    private int STATUSES;


    • 然后我们定义十六进制状态常量,和模式状态集,例如:


    private final int STATUS_1 = 0x0001;private final int STATUS_2 = 0x0002;private final int STATUS_3 = 0x0004;private final int STATUS_4 = 0x0008;private final int STATUS_5 = 0x0010;private final int STATUS_6 = 0x0020;private final int STATUS_7 = 0x0040;private final int STATUS_8 = 0x0080;


    private final int MODE_A = STATUS_1 | STATUS_2 | STATUS_3;private final int MODE_B = STATUS_1 | STATUS_4 | STATUS_5 | STATUS_6;private final int MODE_C = STATUS_1 | STATUS_7 | STATUS_8;


    • 当我们需要往状态集中添加状态时,就通过或运算。例如:


    STATUSES | STATUS_1


    • 当我们需要从状态集中移除状态时,就通过取反运算。例如:


    STATUSES & ~ STATUS_1


    • 当我们需要判断状态集中是否包含某状态时,就通过与运算。结果为 0 即代表无,反之有。


    public static boolean isStatusEnabled(int statuses, int status) {return (statuses & status) != 0;}

    要如何成为 Android 架构师?

    搭建自己的知识框架,全面提升自己的技术体系,并且往底层源码方向深入钻研。大多数技术人喜欢用思维脑图来构建自己的知识体系,一目了然。这里给大家分享一份大厂主流的 Android 架构师技术体系,可以用来搭建自己的知识框架,或者查漏补缺;



    对应这份技术大纲,我也整理了一套 Android 高级架构师完整系列的视频教程,主要针对 3-5 年 Android 开发经验以上,需要往高级架构师层次学习提升的同学,希望能帮你突破瓶颈,跳槽进大厂;


    最后我必须强调几点:


    1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识 3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。


    你只需要按照在这个大的框架去填充自己,年薪 40W 一定不是终点,技术无止境


    本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

    用户头像

    嘟嘟侠客

    关注

    还未添加个人签名 2021.03.19 加入

    还未添加个人简介

    评论

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