“我正在参加「启航计划」”

背景

最近需求完成一个状况办理类:

  1. 在多种场景下,操控一系列的按钮是否可操作。
  2. 不同场景下,在按钮不行操作的时分,点击弹出对应的Toast。
  3. 跟着场景数量的添加,这个办理类的完成,就或许会越来越复杂。

刚好看到大佬的文章,顺便学习和实践一下。
参考学习:就算不去火星种马铃薯,也请必须把握的 Android 状况办理最佳实践

示例

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”。

完成思路

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 进行存储映射联系。
  1. key 为对应状况+禁用标志位的 或运算 成果。这样的计算成果,是可以确保key是仅有的,不会出现重复的情况。
  2. value 为对应的 Toast 案牍。
  3. 只需求一个 HashMap 就可以完成一切的装备联系。
  4. 从代码阅读性来说,运用这样的代码进行装备,看起来也比较通俗易懂。
    比方 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

十六进制

Android 十六进制状态管理实战

  • 16进制多状况办理本质上是二进制办理,即‘1’所处的位数。
  • 比方上面界说的各种变量,都是通过1左移n位数之后的成果。
  • 这样可以确保,多个不同变量的与运算、或运算成果,可所以仅有的。比方上面,用这个特性,用来做一层 Toast 案牍的映射联系。

总结

  • 的确,像类似的场景,跟着业务迭代场景数添加,在没有运用十六进制之前,整体的代码或许是会比较复杂的。
  • 运用十六进制之后,或许需求多花一点时间,去理解一下十六进制相关的知识,但是在代码完成上的确简略了很多。