其他分享
首页 > 其他分享> > 【随记】Dialog dismiss无法正常关闭问题

【随记】Dialog dismiss无法正常关闭问题

作者:互联网

【记】Dialog dismiss无法正常关闭问题

问题描述

弹出框正常show后在界面正常展示,但调用dismiss操作无法进行关闭。

并且设置 setCancelable(true) 也无法点击弹出框外部进行关闭,也就是弹出框显示后无论如何操作均无法正常关闭。

问题复现

首先创建弹出框

mDialog = new Dialog(context);
mDialog.setContentView(rootLayout, rootLP);
mDialog.setCancelable(false);
mDialog.show();

相关关闭调用

mContentView.findViewById(R.id.dialog_teach_rate_up_layout).setOnClickListener(v -> {
    dismiss();
});

dismiss 内部则是调用的mDialog.dismiss(),调试代码可以触发路径正常,也正常进入系统dialog内部dismiss方法中。

问题猜测

触发路径异常

这个经过调试,整个链路正常,也触发了dismiss操作,但手机界面无反应。

mDialog变量被覆盖

这个猜测是觉得mDialog变量被反复创建,当我们调用dismiss时不是调用的正在显示的dialog;有时候可能会因为历史逻辑或粗心导致该情况。

也是一样调试发现创建过程仅触发一次,其hash与dismiss时hash一致;排除该情况。

在子线程中创建

怀疑过该情况,但实际运行中并未触发crash。在弹出框内部有持有Handler。
在这里插入图片描述
其内部有判断不合法则会Crash
在这里插入图片描述

在子线程中dismiss

该情况也有怀疑,但实际代码排查不存在该问题;排除。

到此时问题似乎难解了,基本上该排查的都排查了,甚至还怀疑是不是刚刚dismiss又立刻进行了show显示的情况,但均不是。

问题解决

问题没找到那就肯定是排查的还不够仔细,就在我进一步调试dismiss时,发现了这些信息:

在这里插入图片描述

图中我加上了是否是UI-Thread的调试判断,以及当前的Looper输出。

从图中可以看出:

  1. 是UI-Thread中调用的dismiss
  2. mDialog内部的Handler所持有的Looper与当前的Main Looper 并不相同

那么到这里,答案似乎呼之欲出了。

首先弹出框内部dismiss会进行looper判断,那么按我们的情况会进入到handler post message 的流程。

在这里插入图片描述

其链路为:

Handler.post -> Handler.sendMessageDelayed -> Handler.sendMessageAtTime -> Handler.enqueueMessage -> MessageQueue.enqueueMessage

看起来似乎与Looper没有关系,但Handler中的mQueue = mLooper.mQueue;

猜测:当Looper状态不正常时,其对应的mQueue消息将得不到处理。

其不正常状态一般为:

  1. 对应的线程处于阻塞状态,也就无法处理消息
  2. Looper本身quit了

而前面怀疑 “在子线程创建” 这一步放过了,因其判断依据仅仅为是否有looper存在,而没细考虑到子线程也会有Looper的情况。

最后验证猜想

在这里插入图片描述

在创建时刻加上断点,并查看当前链路与looper判断;可以看见其调度流程其实是播放器线程调度过来的,并且此时也的确不是主线程的Looper,而在本次调用后,播放器其实阻断停止了;所以也就导致了后续的dismiss的消息无法正常消费的问题。

最后

本次算是一次踩坑经历,遂记录之。

标签:正常,mDialog,dismiss,Handler,线程,Looper,Dialog,随记
来源: https://blog.csdn.net/qiujuer/article/details/121238845