一、背景
目前项目上使用自定制的AlertView,但弹窗缺乏管理,在处理某些业务场景时,往往需要额外的代码去处理,不够优雅。举一些的例子:
场景1:
当前App页面已经存在一个弹窗,用户没有理会,后台无操作一段时间后回到前台,会触发超时弹窗,点击弹窗按钮触发登录逻辑,此时期望清除掉原有页面的弹窗。
场景2:
登录成功后,根据用户的个人情况(如身份证过期)弹出一些弹窗,同时可能存在一些营销弹窗需要弹出。
二、需求分析
根据目前已知的场景,我们需要设计一个弹窗管理器来统一管理弹窗,其要具备以下能力:
- 优先级
- 可清理
- 弹窗与管理器解耦
因为需要对新弹窗进行排序(比较优先级),因此数据结构选择了堆,下面聊下基本思路:
展示:当创建一个item(待展示的弹框)后,将其入堆进行维护,比较其与当前展示的currentItem的优先级,若优先级高于currentItem,则currentItem所代表的item消失,展示item,同时currentItem = item。
删除:当点击currentItem 指向的弹窗的按钮后,删除堆中对应的item,并维护堆的正确性
三、设计
1.优先级
在创建待展示的弹窗时,我们可以为其配置一个权重值来确定展示的优先级,当权重值相同时,优先展示后入堆的,即:
优先级 = 综合权重值 = 权重值 + 序列值
2.可清理
依赖于堆的特性,我们可以很方便的清理堆中的元素,考虑到业务场景,我们可以为弹窗配置一个clearOther的选项,当点击该弹窗的按钮时,判断其clearOther,若为true,则清空堆。
3.弹窗与管理器解耦
在写demo时,使用了一个名为DAlertView的简洁的开源弹窗,考虑到在应用时,往往项目都有自己的弹窗样式,因此使用了一个桥接类来实现弹窗与管理器的解耦,避免在做兼容修改时,不小心改动了管理逻辑。
四、实现
本身利用堆的特性来做这个事情思路是比较清晰的,但在实践中,消耗时间最多的是处理线程问题,是的,没错,开发准则要求我们要在子线程处理数据,在主线程更新UI,那么就需要协调两个线程之间的关系,主要原则:
- 在子线程维护堆
- 在准备弹窗前挂起子线程,待弹窗展示完毕后,载恢复
- 弹窗准备消失前,阻塞主线程,维护堆,然后恢复主线程。这里牺牲了性能,但是目前没有想到更好的办法去处理快速点击时维护堆产生的错乱
五、Demo
由于思路比较清晰,无甚难度,故没有画程序流程图(偷懒)。demo见地址。