无悬浮窗权限实现全局Dialog

有些场景下需要显示一些提示弹窗,但把握不好弹出时机容易先弹出弹窗然后界面马上被杀掉进而看不到提示内容,例如强制下线:客户端退回登录界面并弹出提示弹窗。

作者:Abin
链接:https://juejin.cn/post/7295576843653087266

如果是直接拿的栈顶activity去弹出,没有将弹窗逻辑写到具体activity中,或不好确定activty的变化就容易出现这种现象。

由于applicationContext没有AppWindowToken,所以dialog无法使用applicationContext创建,要么就使用windowManager配合WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY使用创建全局悬浮窗。但是这种做法需要申请权限。那么,在没有悬浮权限情况下如何做到让dialog不受栈顶activity变化的影响?

我的想法是通过application.registerActivityLifecycleCallbacks在activity变化时,关闭原来的弹窗,并重新创建一个一样的dialog并显示。

效果演示:

1. 栈顶界面被杀

67420cc4f8bc005c25b9baeaa05af127.jpeg

2. 有新界面弹出

dd604118cda14ea827837a997bdb3d75.jpeg

以下是代码实现:

/**
 * @Description 无需悬浮权限的全局弹窗,栈顶activity变化后通过反射重建,所以子类构造方法需无参
 */
open class BaseAppDialog<T : ViewModel>() : Dialog(topActivity!!.get()!!), ViewModelStoreOwner {


    companion object {
        private val TAG = BaseAppDialog::class.java.simpleName
        private var topActivity: WeakReference<Activity>? = null
        private val staticRestoreList = linkedMapOf<Class<*>, Boolean>()    //第二个参数:是否临时关闭
        private val staticViewModelStore: ViewModelStore = ViewModelStore()


        @JvmStatic
        fun init(application: Application) {
            application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
                override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                    topActivity = WeakReference(activity)
                }


                override fun onActivityStarted(activity: Activity) {


                }


                override fun onActivityResumed(activity: Activity) {
                    topActivity = WeakReference(activity)
                    val tempList = arrayListOf<BaseAppDialog<*>>()
                    val iterator = staticRestoreList.iterator()
                    while (iterator.hasNext()) {
                        val next = iterator.next()
                        val topName = (topActivity?.get() ?: "")::class.java.name
                        if (next.value == true) {  //避免onCreate创建的弹窗重复弹出
                            val newInstance = Class.forName(next.key.name).getConstructor().newInstance() as BaseAppDialog<*>
                            tempList.add(newInstance)
                            Log.e(TAG, "重新创建${next.key.name},于$topName")
                            iterator.remove()
                        }


                    }


                    tempList.forEach {
                        it.show()
                    }


                    if (staticRestoreList.size == 0) {
                        staticViewModelStore.clear()
                    }
                }


                override fun onActivityPaused(activity: Activity) {
                }


                override fun onActivityStopped(activity: Activity) {


                }


                override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
                }


                override fun onActivityDestroyed(activity: Activity) {
                }
            })
        }
    }




    var vm: T? = null


    init {
        val genericClass = getGenericClass()
        if (vm == null) {
            (genericClass as? Class<T>)?.let {
                vm = ViewModelProvider(this)[it]
            }
        }


        topActivity?.get()?.let {
            (it as LifecycleOwner).lifecycle.addObserver(object : DefaultLifecycleObserver {
                override fun onPause(owner: LifecycleOwner) {
                    super.onPause(owner)
                    dismissSilent()
                }
            })
        }
    }




    //用于栈顶变化时的关闭
    private fun dismissSilent() {
        super.dismiss()
        staticRestoreList.replace(this::class.java, true)
    }


    override fun show() {
        super.show()
        staticRestoreList.put(this::class.java, false)
    }


    override fun dismiss() {
        super.dismiss()
        staticRestoreList.remove(this::class.java)
    }




    //获取泛型实际类型
    private fun getGenericClass(): Class<*>? {
        val superclass = javaClass.genericSuperclass
        if (superclass is ParameterizedType) {
            val actualTypeArguments: Array<Type>? = superclass.actualTypeArguments
            if (!actualTypeArguments.isNullOrEmpty()) {
                val type: Type = actualTypeArguments[0]
                if (type is Class<*>) {
                    return type
                }
            }
        }
        return ViewModel::class.java
    }




    //自己管理viewModel以便恢复数据
    override fun getViewModelStore(): ViewModelStore {
        return staticViewModelStore
    }
}

参数传递的话,直接通过修改dialog的viewmodel变量或调用其方法来实现。

class TipDialogVm : ViewModel() {
    val content = MutableLiveData<String>("")
}




class TipDialog2 : BaseAppDialog<TipDialogVm>() {


    var binding : DialogTip2Binding? = null


    init {
        binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.dialog_tip2, null, false)
        binding?.lifecycleOwner = context as? LifecycleOwner
        binding?.vm = vm
        setContentView(binding!!.root)


    }
}

弹出弹窗

TipDialog2().apply {
    vm?.content?.value = "嗨嗨嗨"
}.show()

关注我获取更多知识或者投稿

36e3ecf4f867b5e61547113340a5b627.jpeg

82c1bdfac3c9dfabbf6c34d40af41971.jpeg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值