首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Coding
V2EX  ›  Android

真香警告:就算不封装商业级 SDK,也请务必掌握的 Android 状态管理最佳实践!

  •  
  •   KunMinX · 164 天前 · 3426 次点击
    这是一个创建于 164 天前的主题,其中的信息可能已经有所发展或是发生改变。

    很高兴见到你!

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

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

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

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

    😉

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

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

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

    https://juejin.im/post/5d1a148e6fb9a07ea6488ba3

    38 回复  |  直到 2019-07-06 16:46:43 +08:00
        1
    also24   164 天前   ♥ 5
    你这明明是二进制状态管理,关十六进制什么事情……

    写成十六进制还不方便理解,要思考一下:
    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_1 = 1 << 0;
    private final int STATUS_2 = 1 << 1;
    private final int STATUS_3 = 1 << 2;
    private final int STATUS_4 = 1 << 3;


    或者干错手动补 0 也方便理解啊:
    private final int STATUS_1 = 0b1;
    private final int STATUS_2 = 0b10;
    private final int STATUS_3 = 0b100;
    private final int STATUS_4 = 0b1000;
        2
    whileFalse   164 天前   ♥ 11
    各位不用点进去了,就是把多个 bool 放到一个 int 里面。洋洋洒洒写了四千字。
        3
    busymilk   164 天前
    不是 flag 那一套么。。。
        4
    WebKit   164 天前 via Android
    这种文章写这么详细,应该比较适合刚入门什么都不会的。
        5
    KunMinX   164 天前
    @also24 @whileFalse @WebKit

    那你很棒哦
        6
    AndroidEngineer   164 天前
    来点高端的,比如 dex 热修,so 混淆加密,现在 Android 不往底层走等于菜鸡
        7
    ShangShanXiaShan   164 天前
    @AndroidEngineer "你很棒"警告
        8
    Lucups   164 天前
    感叹号结尾的文章标题一律不看
        9
    ys1992   164 天前   ♥ 1
    楼主分享思路不错,赞一个!一楼优化解释也很好,确实更通用且便于理解吧,本质都是通过位运算来解决多状态集合问题
        10
    ostholz   164 天前
    @also24 节约我时间, 没点进去。
        11
    agostop   164 天前
    之前在一个接口上用过类似的算法,和题主描述的场景差不多,不过是用的二进制……没看懂为什么非要用 16 进制?
        12
    ice000   164 天前
    标题党
        13
    zjiecode   164 天前
    感谢楼主,虽然很基础,但是还是很不错的,另外,权限之类的,也可以考虑这种思想。
    不过,要是状态超过了 32,就用 long,那超过 64 了呢?有没有啥好的解法呢?
        14
    KunMinX   164 天前
    @Lucups @ostholz @ice000

    那你很棒哦

    @ys1992 @mrjiejiejie

    感谢你的阅读!

    我司目前封装的 SDK,一个功能的状态一般不超过 12 个,所以就算 int 也足够。

    64 个状态的话,到底是什么功能才会存在这样的设计呢?
        15
    SuperNovaSonic   164 天前
    来自掘金:
        16
    SuperNovaSonic   164 天前   ♥ 1
    金 1998
    你应该没怎么玩过 C 语言
    21 分钟前
    KunMinXlv-3(作者)
    Android @ ViaBus-Architecture
    回复 金 1998: 那你很棒哦
    4 分钟前
        17
    KunMinX   164 天前
    @SuperNovaSonic

    有什么依据呢?
        18
    yusuzhan   164 天前
    这个东西在 Java 里很常用,叫做位掩码。
        19
    alextang95   164 天前
    @KunMinX 这种状态处理属于基本操作。
    C 语言用的更多,因为要用那么一点点内存作更多的事。
    另外这和十六进制没什么关系,就是二进制状态。
    状态的转移用位运算。

    @also24 @whileFalse 二位省了大家好多时间,感谢
        20
    lastpass   164 天前 via Android   ♥ 1
    楼主快坐下,快坐下。
    不过一些常规操作而已。
    快翻开你大学时候的计算机导论,
    c 语言基础,
    汇编基础的书的前两章温习一下。
        21
    cizeZSY   164 天前 via Android
    这不是很常见的东西吗。。。
        22
    quaack   164 天前
    哈哈哈哈营销鬼才,这不是最简单的位运算吗

    要是楼主知道各种 bit magic 可能会吹上天吧
        24
    maninfog   164 天前 via iPhone
    很棒的文章,支持一个。
        25
    Mithril   164 天前
    上古时代 Windows API 里的各种 HRESULT 不就是这么干的么。。。
        26
    xenme   164 天前
    @whileFalse 你这一句就把楼主打醒了。

    估计楼主又要写四千字反省下了。
        27
    alextang95   164 天前
    感觉我有点歪楼了,抓紧掰回来

    1. 给 LZ 的分享精神点赞
    2. 反应比较平淡的是见多了就不惊讶了
    3. 恰到好处地解决问题的感觉很爽
    4. 文章是有点啰嗦哈
    5. 1L 讲的是挺棒的啊……

    LZ 别 block 我……
        28
    lastpass   164 天前 via Android
    另外:我再补充一下。为何用二进制的形式存储状态被淘汰,除非是状态特别多,否则大家都不会使用的原因。
    因为现代级的 CPU 寄存器非常之多,还有大量的 l1,l2,l3 缓存,这些状态会大部分情况下会被缓存到 cpu 的寄存器。直接从寄存器取数据可比 cpu 从内存里面取快多了。而且,很多时候。我们通常都只需要某个状态。直接取值和算一遍再获得值,后者的效率明显会略低(虽然大部分情况下,这点速度差距可以忽略)
        29
    lastpass   164 天前 via Android
    当然,更重要的原因是,用二进制存储状态,太特喵不直观,代码阅读起来太费劲了。所以,大家都不愿意使用这个东西。
        30
    huijiewei   164 天前 via iPhone
    位运算非要强行扭成 16 进制,写技术文章最好多参考
        31
    KunMinX   164 天前
    @maninfog 感谢你的阅读!

    @lastpass 感谢你的补充!
        32
    no1xsyzy   163 天前
    @mrjiejiejie 编程珠玑里面不是有过了吗?状压存电话号码,何止 64 个状态,是 1,000,000 个以上的状态,全按位压缩。
        33
    no1xsyzy   163 天前
    《编程珠玑》( Programming Pearls )
    《算法心得:高效算法的奥秘》( Hacker's Delight )
    这些方法现在越来越少了,原因:
    1. 内存不缺了
    2. #28 缓存更快
    3. 影响可读性
    4. 现在编程语言常常提供 Set 类型,可以兼具高效和可读性

    老古董 Pascal 就支持 set of <enumerable>,可以当作位压编译期展开(可能需要看具体实现)。
    甚至可以定义 enum 类型然后做集合,不比你这直观得多?
    https://en.wikibooks.org/wiki/Pascal_Programming/Sets
        34
    no1xsyzy   163 天前
    另一方面,为何采用 8 个 status (无论是 bool 还是位压 int )标记按钮可用性是逻辑上错误的。
    不应该上游控制下游,而应该下游因变于上游。
    fn (ui:UI).setModeA(){
    ui.mode = A; ui.updateButtonsAvailability();
    }
    // same for modeB, modeC
    fn (ui:UI).updateButtonsAvailability(){
    for(button in ui.buttons){
    button.updateAvailability(mode=ui.mode)
    }}
    fn (button:Button).updateAvailability(mode:EnumMode){
    button.availability = mode in button.availableModes
    }
        35
    keymao   163 天前   ♥ 1
    还是那句话 有事儿说事儿,上来就是这也简单那也存在,人家就是分享点东西而已,有错误可以合理指出,不足之处补正,愿意讨论讨论,不愿意讨论看看关了就完了,来句不甜不咸的很简单书本里有,有啥意思么? 愁了。 讨论问题,能不能别像个小孩一样。
        36
    mmdsun   162 天前 via Android
    Mark。二进制状态?
        37
    nicoljiang   162 天前
    @keymao 可能是因为楼主没管理好读者的预期(标题起的太大)
        38
    karllynn   161 天前
    楼主你没学过 C 语言么…

    bit flag 是基本知识吧
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2145 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 42ms · UTC 15:30 · PVG 23:30 · LAX 07:30 · JFK 10:30
    ♥ Do have faith in what you're doing.