Android中多个弹窗的排队展示
在实际的开发中,我们会遇到多个弹窗的问题,又不能一次全部弹出,所以我们的代码就是 if else if else 循环嵌套。
例如我们在工作详情中申请一个工作,首先我们就要走一个校验接口,然后接口会告诉需要判断的对象。如下判断逻辑:
- 首先需要先判断是否是新用户,如果是新用户需要去参加线上培训(跳转页面)
- 判断用户是否完善了个人信息,如果没有需要去完善个人信息 (跳转页面)
- 判断个人用工状态是否是Approve,如果个人状态不对需要联系管理员 (拨打电话)
- 判断当前用户是否填写了每日新冠报告,如果没有需要填写新冠表单(跳转浏览器)
- 判断当前申请的工作是否需要押金,如果要押金弹框提示(弹框)
- 如果需要押金,你的钱包又恰好有钱,会提示是否把钱包的钱充值到押金(弹框)
- 如果改工作需要人脸信息,需要你采集人脸 (跳转页面)
- 如果是非直营的工作,会提示你非自营工作 (弹窗)
- 如果该工作需要what's app 会弹窗提示你输入账号 (弹框)
- 如果该工作是银行卡结算,你又没有银行卡信息,需要填写银行卡(新页面)
...
真实业务肯定不止10个条件了,这里就先写10个吧。来,键盘给你,你来写if else 。你写完了? 中间第5个后面再加一个判断 如果你没有填写技能 去新页面填写你的技能! 这么多if else 中你真的改的动吗?
什么?你业务中就是这么写的?你改的动?
就喜欢这种朴实无华的程序员,但是呢相信我,真的非常简单。毕竟偷懒才是程序员的第一生产力,所有的设计模式,框架,封装什么的,都是为了偷懒,让我们更轻松一点。来吧,看看我的实现!
一、拦截器模式的定义
真正的实现: 定义拦截器接口
interface Interceptor {
fun intercept(chain: InterceptChain)
}
定义一个拦截器的基类
abstract class BaseInterceptImpl : Interceptor {
protected var mChain: InterceptChain? = null
@CallSuper
override fun intercept(chain: InterceptChain) {
mChain = chain
}
}
具体的逻辑都在拦截链管理类中
class InterceptChain private constructor(
// 弹窗的时候可能需要Activity/Fragment环境。
val activity: FragmentActivity? = null,
val fragment: Fragment? = null,
private var interceptors: MutableList<Interceptor>?
) {
companion object {
@JvmStatic
fun create(count: Int = 0): Builder {
return Builder(count)
}
}
private var index: Int = 0
// 执行拦截器。
fun process() {
interceptors ?: return
when (index) {
in interceptors!!.indices -> {
val interceptor = interceptors!![index]
index++
interceptor.intercept(this)
}
interceptors!!.size -> {
clearAllInterceptors()
}
}
}
private fun clearAllInterceptors() {
interceptors?.clear()
interceptors = null
}
// 构建者模式。
open class Builder(private val count: Int = 0) {
private val interceptors by lazy(LazyThreadSafetyMode.NONE) {
ArrayList<Interceptor>(count)
}
private var activity: FragmentActivity? = null
private var fragment: Fragment? = null
// 添加一个拦截器。
fun addInterceptor(interceptor: Interceptor): Builder {
if (!interceptors.contains(interceptor)) {
interceptors.add(interceptor)
}
return this
}
// 关联Fragment。
fun attach(fragment: Fragment): Builder {
this.fragment = fragment
return this
}
// 关联Activity。
fun attach(activity: FragmentActivity): Builder {
this.activity = activity
return this
}
fun build(): InterceptChain {
return InterceptChain(activity, fragment, interceptors)
}
}
}
二、拦截器模式的使用
三个简单的文件就定义了一个拦截器链,我们看看上面的需求我们如何实现
具体到工作申请判断类
public class JobInterceptBean {
public boolean isNewMember;
public boolean isFillInfo;
public boolean isMemberApprove;
public boolean isNOCVUpload;
public boolean isNeedDepost;
public boolean isNeedFace;
public boolean isUnderCompany;
public boolean isNeedWhatApp;
public boolean isNeedBankInfo;
public boolean isNeedSkill;
...
}
具体的拦截器一,新用户的拦截。这里直接暴力的跳转页面
class InterceptNewMember(private val bean: JobInterceptBean) : BaseInterceptImpl() {
override fun intercept(chain: InterceptChain) {
super.intercept(chain)
if (bean.isNewMember) {
//拦截
//可以不弹窗,直接就暴力跳转新页面
Demo5Activity.startInstance()
} else {
//放行- 转交给下一个拦截器
chain.process()
}
}
//已经完成了培训-放行
fun resetNewMember() {
mChain?.process()
}
}
完善信息的拦截,这里使用弹窗判断
class InterceptFillInfo(private val bean: JobInterceptBean) : BaseInterceptImpl() {
override fun intercept(chain: InterceptChain) {
super.intercept(chain)
if (!bean.isFillInfo) {
//拦截
//跳转新页面
showDialogTips(chain)
} else {
//放行- 转交给下一个拦截器
chain.process()
}
}
private fun showDialogTips(chain: InterceptChain) {
FangIOSDialog(chain.activity).apply {
setTitle("完善信息")
setMessage("你没有完善信息,你要去完善信息")
setNegativeButton("跳过"){
dismiss()
chain.process()
}
setPositiveButton("去完善"){
Demo5Activity.startInstance()
}
show()
}
}
}
用户状态使用弹窗判断
class InterceptMemberApprove(private val bean: JobInterceptBean) : BaseInterceptImpl() {
override fun intercept(chain: InterceptChain) {
super.intercept(chain)
if (!bean.isMemberApprove) {
//拦截
showDialogTips(chain)
} else {
//放行- 转交给下一个拦截器
chain.process()
}
}
private fun showDialogTips(chain: InterceptChain) {
FangIOSDialog(chain.activity).apply {
setTitle("状态不对")
setMessage("你用户状态不对,联系管理员吗?")
setNegativeButton("跳过") {
dismiss()
chain.process()
}
setPositiveButton("联系") {
dismiss()
toast("去拨打电话,当你状态对了才能继续")
}
show()
}
}
}
技能的拦截-使用弹窗判断
class InterceptSkill(private val bean: JobInterceptBean) : BaseInterceptImpl() {
override fun intercept(chain: InterceptChain) {
super.intercept(chain)
if (bean.isNeedSkill) {
//拦截
//跳转新页面
showDialogTips(chain)
} else {
//放行- 转交给下一个拦截器
chain.process()
}
}
private fun showDialogTips(chain: InterceptChain) {
FangIOSDialog(chain.activity).apply {
setTitle("你没有填写技能")
setMessage("你要去填写技能吗?")
setNegativeButton("跳过") {
dismiss()
chain.process()
}
setPositiveButton("去填写") {
Demo5Activity.startInstance()
}
show()
}
}
}
内部可以使用 Dialog 或者 PopupWindow 或者第三方的弹窗库,都是可以的。具体的可以自行实现。下面看看如何使用
lateinit var newMemberIntercept: InterceptNewMember
fun navIntercept() {
//模拟网络请求
LoadingDialogManager.get().showLoading(this@Demo4Activity)
CommUtils.getHandler().postDelayed({
LoadingDialogManager.get().dismissLoading()
val bean = JobInterceptBean(true, false, false, false, true, true, true, true, true, true)
createIntercept(bean)
}, 1500)
}
//创建拦截弹窗
private fun createIntercept(bean: JobInterceptBean) {
newMemberIntercept = InterceptNewMember(bean)
val chain = InterceptChain.create(4)
.attach(this@Demo4Activity)
.addInterceptor(newMemberIntercept)
.addInterceptor(InterceptFillInfo(bean))
.addInterceptor(InterceptMemberApprove(bean))
.addInterceptor(InterceptSkill(bean))
.build()
//开始执行
chain.process()
}
我们把 NewMemberIntercept 单独提取出来作为成员变量是为了接受到完成培训的通知,对它做放行操作。
override fun startObserve() {
LiveEventBus.get("newMember",Boolean::class.java).observe(this){
//调用内部放行的方法
newMemberIntercept.resetNewMember()
}
}
看看效果,NewMemberIntercept 放行与不放行的区别
可以看到我们的第二个拦截器 InterceptFillInfo 它内部就没有定义放行的方法,如果一旦跳转到新页面,但是没有接收通知去放行的话就会卡在这里。
效果:
总结
这样就完成了一个拦截器链,我们可以自由的定义弹窗,打电话,跳转页面,跳转浏览器等自定义的功能。
我们的业务场景是调用接口获取到全部的校验数据,然后再创建 Chain 。当然我们也可以先创建 Chain 。然后把每一个拦截器都设置为成员变量,每一个拦截器可以调用不同的接口做校验,当数据返回的时候设置给拦截器暴露的方法,内部再判断数据类型,是否需要放行。
可以说这是一种非常灵活的拦截器链,内部使用了责任链模式,单例模式,建造者模式,工厂模式等。如果大家有需要可以使用起来。
具体的源码在此。如有错漏还请指出,如果有更好的方法也欢迎讨论。
如果觉得不错还请点赞
支持哦!
到此完结!