Android笔记(三十五):用责任链模式封装一个App首页Dialog管理工具

背景

项目需要在首页弹一系列弹窗,每个弹窗是否弹出都有自己的策略,以及哪个优先弹出,哪个在上一个关闭后再弹出,为了更好管理,于是封装了一个Dialog管理工具

效果

在这里插入图片描述

  • 整体采用责任链模块设计,控制优先级及弹出策略

原理分析

  1. 每个弹窗都当做一个节点Node,抽象出一些公共接口
public interface Node {int getId();String getTag();void complete();void error(ChainException e);
}
  1. 定义弹窗的状态
    INIT:初始创建
    PROGRESS:开始弹出
    COMPLETE:完成弹出到关闭的流程
    ERROR:弹出错误
public interface Operation {State.INIT INIT = new State.INIT();State.PROGRESS PROGRESS = new State.PROGRESS();State.COMPLETE COMPLETE = new State.COMPLETE();abstract class State {State() {}public static final class INIT extends State {private INIT() {super();}@Override@NonNullpublic String toString() {return "INIT";}}public static final class PROGRESS extends State {private PROGRESS() {super();}@Override@NonNullpublic String toString() {return "PROGRESS";}}public static final class COMPLETE extends State {private COMPLETE() {super();}@Override@NonNullpublic String toString() {return "COMPLETE";}}public static final class ERROR extends State {private final Throwable mThrowable;public ERROR(@NonNull Throwable exception) {super();mThrowable = exception;}@NonNullpublic Throwable getThrowable() {return mThrowable;}@Override@NonNullpublic String toString() {return String.format("ERROR (%s)", mThrowable.getMessage());}}}
}
  1. 为Dialog节点定义具体的状态切换
public class DialogNode implements Node {private static final String TAG = "ChainNode";private int id;private String tag;private Operation.State state = Operation.INIT;private Executor executor;private CallBack callBack;private DialogNode(int id, String tag, Executor executor) {this.id = id;this.tag = tag;this.executor = executor;}public static DialogNode create(int id, Executor executor) {return create(id, TAG + id, executor);}public static DialogNode create(int id, String tag, Executor executor) {return new DialogNode(id, tag, executor);}@Overridepublic void complete() {setState(Operation.COMPLETE);if (callBack != null) {callBack.onComplete();}}@Overridepublic void error(ChainException e) {setState(Operation.COMPLETE);if (callBack != null) {callBack.onError(e);}}public void process(CallBack callBack) {this.callBack = callBack;if (executor != null) {executor.execute(this);}}public static String getTAG() {return TAG;}@Overridepublic int getId() {return id;}public void setId(int id) {this.id = id;}@Overridepublic String getTag() {return tag;}public void setTag(String tag) {this.tag = tag;}public Executor getExecutor() {return executor;}public void setExecutor(Executor executor) {this.executor = executor;}public CallBack getCallBack() {return callBack;}public void setCallBack(CallBack callBack) {this.callBack = callBack;}public Operation.State getState() {return state;}public void setState(Operation.State state) {this.state = state;}@Overridepublic String toString() {return "ChainNode{" +"id=" + id +", tag='" + tag + '\'' +", state=" + state +", executor=" + executor +", callBack=" + callBack +'}';}public interface CallBack {void onComplete();void onError(ChainException e);}
}
  1. 抽象DialogNode的构建工厂类,弹窗链上每个Dialog必须继承该类,并实现createDialog方法返回具体的业务Dialog;实现execute方法控制弹窗是否要弹出,以及通知工具什么时候完成弹出到关闭的流程
abstract class MDialogNodeCreator {protected var nodeDialog: Dialog? = nullfun build(context: Context, dialogId: Int): DialogNode? {nodeDialog = createDialog(context)val node = DialogNode.create(dialogId) { node ->execute(node)}return node}/*** 构造一个对话框*/abstract fun createDialog(context: Context): Dialog/*** 在此执行业务弹窗逻辑*/abstract fun execute(node: Node)
}
  1. ChainProcessor核心类,保存了每一个DialogNode,在调用start后开始从队列里面去头节点,当DialogNode回调onComplete后递归取下一个节点,直到队列尾部
public class ChainProcessor {private final SparseArray<DialogNode> nodeArrays;private final Builder builder;private ChainProcessor(SparseArray<DialogNode> nodeArrays, Builder builder) {this.nodeArrays = nodeArrays;this.builder = builder;}public void start() {if (nodeArrays == null || nodeArrays.size() <= 0) {Log.e("zbm111", "nodeArrays == null || nodeArrays.size <= 0");return;}startNode(nodeArrays.keyAt(0));}private void startNode(int nodeId) {int index = nodeArrays.indexOfKey(nodeId);DialogNode node = nodeArrays.valueAt(index);if (node != null && node.getState() == Operation.INIT) {node.setState(Operation.PROGRESS);node.process(new DialogNode.CallBack() {@Overridepublic void onComplete() {nextNode(index);}@Overridepublic void onError(ChainException e) {cancel();}});}}private void nextNode(int index) {//移除执行过的第一个removeNode(index);if (nodeArrays != null && nodeArrays.size() > 0) {startNode(nodeArrays.keyAt(0));}}private void removeNode(int index) {if (nodeArrays != null && nodeArrays.size() > 0) {nodeArrays.removeAt(index);}}private void cancel() {if (nodeArrays != null && nodeArrays.size() > 0) {nodeArrays.clear();}}public Builder getBuilder() {return builder;}public static class Builder {private final SparseArray<DialogNode> nodeArrays;private String tag;public Builder() {this.nodeArrays = new SparseArray<>();}public Builder addNode(DialogNode node) {if (node != null) {nodeArrays.append(node.getId(), node);if (TextUtils.isEmpty(tag)) {tag = UUID.randomUUID().toString();}node.setTag(tag);}return this;}public Builder addNodes(DialogNode... nodes) {if (nodes != null && nodes.length > 0) {for (DialogNode node : nodes) {addNode(node);}}return this;}public Builder addTag(String tag) {this.tag = tag;return this;}public ChainProcessor build() {checkTag();return new ChainProcessor(nodeArrays, this);}private void checkTag() {if (nodeArrays.size() > 0) {if (TextUtils.isEmpty(tag)) {tag = UUID.randomUUID().toString();}for (int i = 0; i < nodeArrays.size(); i++) {nodeArrays.get(nodeArrays.keyAt(i)).setTag(tag);}}}public String getTag() {return tag;}public SparseArray<DialogNode> getNodes() {return nodeArrays;}}
}
  1. 工具外部接口,主要是构建ChainProcessor,支持处理多个弹窗链
bject MDialogChainHelper {private val chainNodeMap = mutableMapOf<String, ChainProcessor>()private fun build(chainProcessor: ChainProcessor) {if (chainNodeMap.containsKey(chainProcessor.builder.tag)) {chainNodeMap.remove(chainProcessor.builder.tag)}chainNodeMap[chainProcessor.builder.tag] = chainProcessor}fun startDialogChain(tag: String) {chainNodeMap[tag]?.start()}private fun clearAllChain() {chainNodeMap.clear()}private fun clearDialogChain(tag: String): ChainProcessor? {return chainNodeMap.remove(tag)}fun addDialogChain(tag: String): ChainProcessor {val chainProcessor = ChainProcessor.Builder().addTag(tag).build()if (chainNodeMap.containsKey(chainProcessor.builder.tag)) {chainNodeMap.remove(chainProcessor.builder.tag)}chainNodeMap[chainProcessor.builder.tag] = chainProcessorreturn chainProcessor}fun getDialogChain(tag: String): ChainProcessor? {return chainNodeMap[tag]}}

Demo验证

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)MDialogChainHelper.run {addDialogChain("test_main").builder.addNode(OneDialogNode().build(this@MainActivity, 0)).addNode(TwoDialogNode().build(this@MainActivity, 1))startDialogChain("test_main"    )}}
}
class OneDialogNode: MDialogNodeCreator() {override fun createDialog(context: Context): Dialog {val dialog = Dialog(context)dialog.setContentView(R.layout.dialog_one)dialog.findViewById<View>(R.id.tv_title)?.setOnClickListener {dialog.dismiss()}dialog.window?.setLayout(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT)return dialog}override fun execute(node: Node) {nodeDialog?.setOnDismissListener {node.complete()nodeDialog = null}nodeDialog?.show()}
}
class TwoDialogNode: MDialogNodeCreator() {override fun createDialog(context: Context): Dialog {val dialog = Dialog(context)dialog.setContentView(R.layout.dialog_two)dialog.findViewById<View>(R.id.tv_title)?.setOnClickListener {dialog.dismiss()}dialog.window?.setLayout(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)return dialog}override fun execute(node: Node) {nodeDialog?.setOnDismissListener {node.complete()nodeDialog = null}nodeDialog?.show()}
}

完整代码点击下载

大家觉得不错的点个赞鼓励下哦,有任何建议欢迎留言,谢谢🌹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/9789.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【实战篇P2-5】手把手实现STM32+ESP8266+原子云服务器+手机APP应用——第五节-编写Android手机APP程序实现接入原子云服务器

使用的开发软件是Android studio Android SDK(运行环境 :最低版本 21(Android 5.0) 最高版本 29 (Android 9.0) Gradle 版本 :4.6 根据源码,可自定义修改界面,修改名称,根据需求自定义数据展示界面等,修改app图标及名称等。 目录 Android程序设计 Android…

2024双十一数码好物推荐?双十一超值数码好物汇总别错过!

随着2024年双十一购物狂欢节临近尾声&#xff0c;各大电商平台的促销活动已经进入了最后的冲刺阶段。在这场年度最大的购物盛宴中&#xff0c;数码产品无疑是消费者关注的焦点。无论是提升工作效率的电脑、平板&#xff0c;还是丰富娱乐生活的手机、耳机&#xff0c;各大品牌纷…

Android V 挂起线程超时导致system_server挂掉

问题背景 最近Android v的平台频繁爆monkey异常停止的问题,分析到根因不是频繁dump堆栈导致system_server挂掉就是三方应用进程内部死锁导致anr,然后system_server挂起线程超时,system_server就崩了。 解决方案 先来看看anr导致死锁的场景如何分析 从log来看确认为syste…

评估 机器学习 回归模型 的性能和准确度

回归 是一种常用的预测模型&#xff0c;用于预测一个连续因变量和一个或多个自变量之间的关系。 那么&#xff0c;最后评估 回归模型 的性能和准确度非常重要&#xff0c;可以帮助我们判断模型是否有效并进行改进。 接下来&#xff0c;和大家分享如何评估 回归模型 的性能和准…

图片循环轮播,悬停停止

可直接执行HTML 代码 template 代码在下面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Swip…

Transformer介绍(一)

Transformer是一种特殊的神经网络&#xff0c;一种机器学习模型。 谷歌在2017年推出的原版Transformer&#xff0c;论文《Attention Is All You Need》&#xff0c;专注于将一种语言的文本翻译成另一种。 而我们要关注的Transformer变种&#xff0c;即构建ChatGPT等工具的模型…

MySQL之索引(1)(索引概念与作用、红黑树、b树、b+树)(面试高频)

目录 一、索引的概念、作用。 &#xff08;1&#xff09;介绍。 &#xff08;2&#xff09;为啥索引能优化sql查询&#xff1f; 1、某张表(emp)结构以及数据如下。 2、假如执行的SQL语句为&#xff1a;select * from emp where empno7844; 3、对比与总结。 &#xff08;3&#…

pytest+request+allure接口自动化框架搭建分享

介绍分享一个接口自动化框架搭建方法 (pytestrequestallure)&#xff0c;这个方案是由 xpcs 同学在TesterHome社区网站的分享。 写在前面 去年11月被裁&#xff0c;到现在还没上岸&#xff0c;gap 半年了。上岸无望&#xff0c;专业技能不能落下&#xff0c;花了两三天时间&…

Linux之gdb的收尾部分

Linux之gdb的收尾部分 gbc常见指令的使用 gdb的调试

数据冒险-add x1, x1, x2 add x1, x1, x3 add x1, x1, x4

第一张图没有传递机制 竞争情况分析 读后写&#xff08;RAW&#xff09;竞争&#xff1a;当某条指令需要读取一个寄存器的值&#xff0c;而该寄存器的值尚未被前面的指令写入时&#xff0c;就会发生这种竞争。 指令2&#xff08;dadd r1, r1, r3&#xff09;依赖于指令1&#…

[产品管理-61]:马斯洛需求层次与产品的情感化设计

目录 一、概述 1、马斯洛需求层次理论概述 2、产品情感化设计与马斯洛需求层次的关系 3、产品情感化设计的实践案例 二、马斯洛需求层次与用户情感程度&#xff08;本能、行为、反思&#xff09;的关系 1、马斯洛需求层次与用户情感程度概述 2、马斯洛需求层次与用户情感…

浮动路由:实现出口线路的负载均衡冗余备份。

浮动路由 Tip&#xff1a;浮动路由指在多条默认路由基础上加入优先级参数&#xff0c;实现出口线路冗余备份。 ip routing-table //查看路由表命令 路由优先级参数&#xff1a;越小越优 本次实验测试两条默认路由&#xff0c;其中一条默认路由添加优先级参数&#xff0c;设置…

一阶 RC 低通滤波器实验方案

一阶 RC 低通滤波电路采用 RC 串联电路&#xff0c;把 R 或 C 做为负载端&#xff0c;对负载端与输入端的信 号做比较得到电路的特性曲线。图 1 所示 RC 串联电路构成一个双口网络&#xff0c; 根据图 1&#xff0c;其负载端开路时电容电压对输入电压的转移电压比为 这是一个…

华为私有接口类型hybrid

华为私有接口类型hybrid Tip&#xff1a;hybrid类型&#xff0c;简称混合型接口。 本次实验模拟2层网络下 vlan10 vlan20 不能互访&#xff0c;vlan10 vlan20 同时可以访问vlan100 sw1配置如下&#xff1a; <Huawei>sy [Huawei]sys sw1 [sw1]vl ba 10 20 100 [sw1]int…

006— 爬取第一考试网试题

import requests import logging import parsel import re import os#京东异步加载的反爬要求提供origin的信息 headers {user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0}lo…

【分布式】分布式锁设计与Redisson源码解析

分布式锁 分布式锁是一种在分布式计算环境中用于控制多个节点&#xff08;或多个进程&#xff09;对共享资源的访问的机制。在分布式系统中&#xff0c;多个节点可能需要协调对共享资源的访问&#xff0c;以防止数据的不一致性或冲突。分布式锁允许多个节点在竞争访问共享资源…

【架构设计常见技术】

EJB EJB是服务器端的组件模型&#xff0c;使开发者能够构建可扩展、分布式的业务逻辑组件。这些组件运行在EJB容器中&#xff0c;EJB将各功能模块封装成独立的组件&#xff0c;能够被不同的客户端应用程序调用&#xff0c;简化开发过程&#xff0c;支持分布式应用开发。 IOC …

万字长文深度解读Movie Gen技术原理(5部曲):图像视频联合生成模型 (2)

​引言 简介 图像和视频基础模型 时间自编码器(TAE) 训练目标 骨干架构 文本嵌入和视觉-文本生成 空间上采样 模型扩展和训练效率 预训练 预训练数据 训练 微调STF 微调数据集创建 监督微调&模型平均 推理 推理提示重写 提高推理效率 评估 评估维度 评估基准…

基于MATLAB的农业病虫害识别研究

matlab有处理语音信号的函数wavread&#xff0c;不过已经过时了&#xff0c;现在处理语音信号的函数名称是audioread选取4.wav进行处理&#xff08;只有4的通道数为1&#xff09; 利用hamming窗设计滤波器 Ham.m function [N,h,H,w] Ham(fp,fs,fc)wp 2*pi*fp/fc;ws 2*pi*…

KEIL编译后直接生成bin文件

KEIL编译后直接生成bin文件 fromelf --bin -o "$LL.bin" "$LL.axf"表示在“与axf相同的文件夹”下生成bin文件。