Android 十六进制状态管理实例详解

目录
  • 背景
    • 示例
  • 实现思路
  • 代码测试
  • 十六进制
  • 总结

背景

最近需要实现一个状态管理类:

  • 在多种场景下,控制一系列的按钮是否可操作。
  • 不同场景下,在按钮不可操作的时候,点击弹出对应的Toast。
  • 随着场景数量的增加,这个管理类的实现,就可能会越来越复杂。

刚好看到大佬的文章,顺便学习和实践一下。
参考学习:就算不去火星种土豆,也请务必掌握的 Android 状态管理最佳实践

示例

还是用大佬那个例子。

例如,存在 3 种模式,和 3个按钮,按钮不可用的时候弹出对应的 Toast。

  • 模式 A 下,要求 按钮1、按钮2 可用,按钮3不可用。点击按钮3,Toast 提示“A3”。
  • 模式 B 下,要求 按钮2 可用,按钮1和按钮3不可用。点击按钮1,Toast 提示“B1”。点击按钮3,Toast 提示“B3”。
  • 模式 C 下,要求 按钮1 可用,按钮2和按钮3不可用。点击按钮2,Toast 提示“C2”。点击按钮3,Toast 提示“C3”。

实现思路

  • Kotlin中的位操作
shl(bits) – 左移位
shr(bits) – 右移位
and(bits) – 与
or(bits) – 或
  • 定义多个十六进制的状态常量,代表不同的状态。
    private const val STATE_IDIE = 1
    private const val STATUS_A = 1 shl 1
    private const val STATUS_B = 1 shl 2
    private const val STATUS_C = 1 shl 3
  • 定义一个变量,用于存放当前的状态。
  • 当状态发生变化,需要切换状态的时候,只需要去修改这个变量就行了。
    private var currentStatus = STATE_IDIE
    //测试代码
    private fun changeStateToA(){
            changeStateToA = STATUS_A
    }
  • 定义多个十六进制的标志常量,代表对应的禁用操作。
    比如 DISABLE_BTN_1,代表禁用按钮1。
    //定义不可操作的一些行为
    private const val DISABLE_BTN_1 = 1 shl 4
    private const val DISABLE_BTN_2 = 1 shl 5
    private const val DISABLE_BTN_3 = 1 shl 6
  • 定义模式状态集,由状态+多个禁用标志位组成。
    比如 MODE_A,就是在状态为 STATUS_A 的时候,按钮3禁用,那就将这两个数值进行或运算,结果就是 STATUS_A or DISABLE_BTN_3。
    private const val MODE_A = STATUS_A or DISABLE_BTN_3
    private const val MODE_B = STATUS_B or DISABLE_BTN_1 or DISABLE_BTN_3
    private const val MODE_C = STATUS_C or DISABLE_BTN_2 or DISABLE_BTN_3
    private val modeList = listOf(MODE_A, MODE_B, MODE_C)
  • 定义按钮不可点击时的Toast文案 ,使用 HashMap 进行存储映射关系。

key 为对应状态+禁用标志位的 或运算 结果。这样的计算结果,是可以保证key是唯一的,不会出现重复的情况。

value 为对应的 Toast 文案。

只需要一个 HashMap 就可以实现所有的配置关系。

从代码阅读性来说,使用这样的代码进行配置,看起来也比较通俗易懂。
比如 Pair(STATUS_A or DISABLE_BTN_3, "A3"),就是代表在状态A的时候,禁用按钮3,点击按钮的时候弹的Toast文案为 “A3”。

    private val toastMap = hashMapOf(
        Pair(STATUS_A or DISABLE_BTN_3, "A3"),
        Pair(STATUS_B or DISABLE_BTN_1, "B1"),
        Pair(STATUS_B or DISABLE_BTN_3, "B3"),
        Pair(STATUS_C or DISABLE_BTN_2, "C2"),
        Pair(STATUS_C or DISABLE_BTN_3, "C3")
    )
  • 核心逻辑:判断在当前模式下,按钮是否可用。
    是否可用的判断:判断当前所处的状态,是否包含对应定义的禁用操作。
currentStatus and action !=0

若可操作,返回 true。

若不可操作,通过 currentStatus or action 的运算结果作为key,通过上面配置的 HashMap 集合,拿到对应的 Toast 文案。

    /**
     * 判断当前某个行为是否可操作
     *
     * @return true 可操作;false,不可操作。
     */
    private fun checkEnable(action: Int): Boolean {
        val result = modeList.filter {
            (it and currentStatus) != 0
                    && (it and action) != 0
        }
        if (result.isNotEmpty()) {
            println("result is false, toast:${toastMap[currentStatus or action]}")
            return false
        }
        println("result is true")
        return true
    }
  • 完整代码
object SixTeenTest {
    //定义状态常量
    private const val STATE_IDIE = 1
    private const val STATUS_A = 1 shl 1
    private const val STATUS_B = 1 shl 2
    private const val STATUS_C = 1 shl 3
    //定义不可操作的一些行为
    private const val DISABLE_BTN_1 = 1 shl 4
    private const val DISABLE_BTN_2 = 1 shl 5
    private const val DISABLE_BTN_3 = 1 shl 6
    //定义模式状态集
    private const val MODE_A = STATUS_A or DISABLE_BTN_3
    private const val MODE_B = STATUS_B or DISABLE_BTN_1 or DISABLE_BTN_3
    private const val MODE_C = STATUS_C or DISABLE_BTN_2 or DISABLE_BTN_3
    private val modeList = listOf(MODE_A, MODE_B, MODE_C)
    //定义Toast映射关系
    private val toastMap = hashMapOf(
        Pair(STATUS_A or DISABLE_BTN_3, "A3"),
        Pair(STATUS_B or DISABLE_BTN_1, "B1"),
        Pair(STATUS_B or DISABLE_BTN_3, "B3"),
        Pair(STATUS_C or DISABLE_BTN_2, "C2"),
        Pair(STATUS_C or DISABLE_BTN_3, "C3")
    )
    //当前状态
    private var currentStatus = STATE_IDIE
    /**
    * 判断当前某个行为是否可操作
     *
     * @return true 可操作;false,不可操作。
     */
    private fun checkEnable(action: Int): Boolean {
        val result = modeList.filter {
            (it and currentStatus) != 0
                    && (it and action) != 0
        }
        if (result.isNotEmpty()) {
            println("result is false, toast:${toastMap[currentStatus or action]}")
            return false
        }
        println("result is true")
        return true
    }
}

代码测试

    fun main(args: Array<String>) {
        //测试代码
        currentStatus = STATUS_A
        println("STATUS_A")
        checkEnable(DISABLE_BTN_1)
        checkEnable(DISABLE_BTN_2)
        checkEnable(DISABLE_BTN_3)
        currentStatus = STATUS_B
        println("STATUS_B")
        checkEnable(DISABLE_BTN_1)
        checkEnable(DISABLE_BTN_2)
        checkEnable(DISABLE_BTN_3)
        currentStatus = STATUS_C
        println("STATUS_C")
        checkEnable(DISABLE_BTN_1)
        checkEnable(DISABLE_BTN_2)
        checkEnable(DISABLE_BTN_3)
    }

输出测试结果

STATUS_A
result is true
result is true
result is false, toast:A3
STATUS_B
result is false, toast:B1
result is true
result is false, toast:B3
STATUS_C
result is true
result is false, toast:C2
result is false, toast:C3

十六进制

  • 16进制多状态管理本质上是二进制管理,即‘1’所处的位数。
  • 比如上面定义的各种变量,都是通过1左移n位数之后的结果。
  • 这样能够保证,多个不同变量的与运算、或运算结果,可以是唯一的。比如上面,用这个特性,用来做一层 Toast 文案的映射关系。

总结

  • 确实,像类似的场景,随着业务迭代场景数增加,在没有使用十六进制之前,整体的代码可能是会比较复杂的。
  • 使用十六进制之后,可能需要多花一点时间,去理解一下十六进制相关的知识,但是在代码实现上确实简单了很多。

以上就是Android 十六进制状态管理实例详解的详细内容,更多关于Android 十六进制状态管理的资料请关注我们其它相关文章!

(0)

相关推荐

  • Andorid 状态管理之Lifecycle浅析

    目录 原理概述 构成 模型 源码 1. addObserver(observer) 2. sync() 3. setCurrentState.moveToState 监听 其他 1. Application.ActivityLifecycleCallbacks 总结 原理概述 Lifecycle主要用于Activity.Fragment这一类具有状态的组件的状态监听,最主要的一个作用就是将原先Activity.Fragment中的大量的生命周期相关的回调函数移出View层文件,从设计角度上来说,

  • Android源码使用16进制进行状态管理的方法

    前言 在Android源码中,对于"多状态"的管理总是通过16进制数字来表示,类似这种格式: //ViewGroup.java protected int mGroupFlags; static final int FLAG_CLIP_CHILDREN = 0x1; private static final int FLAG_CLIP_TO_PADDING = 0x2; static final int FLAG_INVALIDATE_REQUIRED = 0x4; private s

  • 务必掌握的Android十六进制状态管理最佳实践

    目录 前言 我和十六进制的 “三次握手” 使用十六进制前的混沌世界 十六进制能很好解决这些问题 十六进制运作机制 十六进制状态管理实战 十六进制状态存取实战 小结 作为额外附赠的答疑 前言 上周在掘金巧遇一篇 “用设计模式管理状态” 文章,作为补充,在评论区安利我司封装商业级 SDK 时常用的 “十六进制状态管理机制”. 原以为无人对此感兴趣,没想到留言很快便收到文章作者回复,且在评论区耐心和我探讨设计模式 独占式状态机 和十六进制 复合状态管理 使用场景区别. 遗憾的是,通过评论区只言片语,难

  • Android 十六进制状态管理实例详解

    目录 背景 示例 实现思路 代码测试 十六进制 总结 背景 最近需要实现一个状态管理类: 在多种场景下,控制一系列的按钮是否可操作. 不同场景下,在按钮不可操作的时候,点击弹出对应的Toast. 随着场景数量的增加,这个管理类的实现,就可能会越来越复杂. 刚好看到大佬的文章,顺便学习和实践一下.参考学习:就算不去火星种土豆,也请务必掌握的 Android 状态管理最佳实践 示例 还是用大佬那个例子. 例如,存在 3 种模式,和 3个按钮,按钮不可用的时候弹出对应的 Toast. 模式 A 下,要

  • Android音频焦点管理实例详解

    目录 音频焦点管理的意义 音频焦点管理的行为准则 版本兼容 在Android 8.0(API 26) 之前对音频焦点具体处理实现 8.0 之后实现 延迟获取焦点 自动降低音量 音频焦点请求方式 响应音频焦点更改 暂时性失去焦点 永久性失去焦点 附音频基础知识 总结 音频焦点管理的意义 两个或两个以上的 Android 应用可同时向同一输出流播放音频.系统会将所有音频流混合在一起.虽然这是一项出色的技术,但却会给用户带来很大的困扰.为了避免所有音乐应用同时播放,Android 引入了“音频焦点”的

  • Android 监听软键盘状态的实例详解

    Android 监听软键盘状态的实例详解 近日遇到要检测软键盘是否显示或隐藏的问题,搜了一下网上,最后找到一个很简单的,记录一下. activityRoot是activity的根view,就是xml里面的第一个view,给它设置一个id. final View activityRootView = findViewById(R.id.activityRoot); activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(ne

  • Android activity堆栈及管理实例详解

    本示例演示如何通过设置Intent对象的标记,来改变当前任务堆栈中既存的Activity的顺序. 1. Intent对象的Activity启动标记说明: FLAG_ACTIVITY_BROUGHT_TO_FRONT 应用程序代码中通常不设置这个标记,而是由系统给单任务启动模式的Activity的设置. FLAG_ACTIVITY_CLEAR_TASK 如果给Intent对象添加了这个标记,那么在Activity被启动之前,会导致跟这个Activity关联的任何既存的任务都被清除.也就是说新的Ac

  • Android的搜索框架实例详解

    基础知识 Android的搜索框架将代您管理的搜索对话框,您不需要自己去开发一个搜索框,不需要担心要把搜索框放什么位置,也不需要担心搜索框影响您当前的界面.所有的这些工作都由SearchManager类来为您处理(以下简称"搜索管理器"),它管理的Android搜索对话框的整个生命周期,并执行您的应用程序将发送的搜索请求,返回相应的搜索关键字. 当用户执行一个搜索,搜索管理器将使用一个专门的Intent把搜索查询的关键字传给您在配置文件中配置的处理搜索结果的Activity.从本质上讲

  • Android原生音量控制实例详解

    本文主要涉及AudioService.还是基于5.1.1版本的代码. AudioService.java文件位于/framework/base/media/java/android/media/下. 音量控制是AudioService最重要的功能之一.先总结一下: AudioService音量管理的核心是VolumeStreamState.它保存了一个流类型所有的音量信息. VolumeStreamState保存了运行时的音量信息,而音量的生效则是在底层AudioFlinger完成的.所以进行音

  • Android 中 ActivityLifecycleCallbacks的实例详解

    Android 中 ActivityLifecycleCallbacks的实例详解           以上就是使用ActivityLifecycleCallbacks的实例,代码注释写的很清楚大家可以参考下, MyApplication如下: package com.cc; import java.util.LinkedList; import android.app.Activity; import android.app.Application; import android.os.Bun

  • Android全局获取Context实例详解

    Android全局获取Context实例详解 在弹出Toast 启动活动 发送广播 操作数据库 使用通知等等时都需要Context 如果操作在活动中进行是很简单的,因为活动本身就是一个Context对象 但是当逻辑代码脱离了Activity类,此时使用Context就需要一些技巧了: 我们可以定制一个自己的Application类,以便管理程序内一些全局状态信息,比如全局Context 代码如下: public class MyApplication extends Application{ p

  • Android Fragment的用法实例详解

    碎片,它的出现是为了更好展示UI的设计,让程序更加得到充分的展示.Fragment的出现,如微信的额主界面包含多个Fragment,使得微信功能更加简洁明了. Fragment组件 Fragment是Android 3.0的时候被引入的,主要目的是为了给大屏幕(如平板电脑)添加动态和灵活的UI支持.利用Fragment实现更好的用户体验. Fragment加载 1.静态加载:添加Fragment到Activity布局中,以xml的形式. 2.动态加载: <LinearLayout android

  • Android 帧动画的实例详解

    Android 帧动画的实例详解 对于 Android 帧动画 大体上可以理解成 一张张图片 按一定顺序切换, 这样当连续几张图是一组动画时,就可以连起来了看成是一个小电影,你懂得 好得,比就装到这里,下面开始进入正题,由于产品需求 需要做一个 声音喇叭动态切换的样式,我特么第一就想到是帧动画切换,然后就百度了一些资料,发现 真的, 现在这个网上太多的资料是 copy粘贴过来的, 一错全错,对于这种情况我只想说,made,一群垃圾, 所以今天我将带你们走进Android 正确帧动画地址. 第一步

随机推荐