Android开发Android开发经验谈Android开发

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

2019-07-05  本文已影响14人  奶盖ww

嗨,你终于来啦 ~ 等你好久啦~ 喜欢的小伙伴欢迎关注,我会定期分享Android知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿。

前言

很高兴见到你!

上上周我在掘金碰巧遇到了一篇 用设计模式管理状态 的文章,一时兴奋不已,在评论区安利了,一直以来我司在封装商业级 SDK 时,使用的十六进制状态管理机制。

原以为会无人对此感兴趣,没想到,留言很快就收到文章作者的回复,并且在评论区耐心地和我探讨了设计模式的 独占式状态机 和十六进制的 复合状态管理 在使用场景上的区别。

遗憾的是,通过评论区的只言片语,并不能让人体会到 十六进制状态管理 的真正魅力。

于是作为回馈,我特地分享了这一篇:当我们封装商业级 SDK 时,我们是怎么使用十六进制来完成状态管理。

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

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

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

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

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

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

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

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

@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
        // We're already in this state, assume our ancestors are too
        return;
    }
    if (disallowIntercept) {
        mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
    } else {
        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
    }
    // Pass it up to our parent
    if (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 变量来管理,那么状态的存储和读取怎么办呢?

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

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

十六进制可以做到:

十六进制的运作机制

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

首先,在编程中,利用开头 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
public static boolean isStatusEnabled(int statuses, int status) {
   return (statuses & status) != 0;
}
STATUSES = MODE_A;

如此,复杂度从 m * n 骤减为 m + n,随着日后模式和状态的增多,十六进制的优势将指数级增长!

是不是超简洁?再也不需要定义和修改各种 “setModeXXX” 方法了。

而且这还只是一半。另一半是关于十六进制状态的存取。

十六进制的状态存取实战

由于状态集是 int 类型,因而我们最少只需一个字段,即可存储状态集:

insert into tableXXX TITLE,DATE,STATUS values ('xxx','20190703',32)

读取也十分简单,读取后直接赋值给 STATUSES 即可。

除此之外,你还可以直接在 SQL 中通过按位计算来查询!例如查询包含状态 0x0004 的记录:

select * from tableXXX where STATUS & 4 != 0

综上

在没有十六进制的日子里,状态管理是个繁琐的、极易出错的操作。

有了十六进制后:

这样说,你理解了吗?

如果您想第一时间看我的后期文章,可以关注一下,不定期推送Android技术文章。如果觉得文章还不错,记得点赞~

本文原作者:KunMinX
原文链接

上一篇下一篇

猜你喜欢

热点阅读