android弹窗不能手动关闭_Android弹窗的实现及相关bug
弹窗是APP用来与用户交互提醒的一种表现形式,就本人知道的实现方式有以下几种:
1)activity
2)fragment
3)popupwindow
4)dialog
5)DialogFragment
下面我们进行展开说明:
1、也许有人会问,activity如何实现弹窗的呢?其实可以的,只要你将activity设置为透明主题即可
2、fragment就不用说了,本来碎片的优点就是灵活可复用,实现弹窗不是问题,更何况后面要讲的DialogFragment本身就是继承Fragment的
3、popupwindow也没什么好说的,它与dialog最大的区别在于它是阻塞线程的,而dialog是非阻塞线程的
4、说起dialog,我们说一下有关的两个bug:
dialog的第一个bug:
WindowManager: android.view.WindowLeaked: Activity xxx.xxx.xxx.xxxActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{4ac945c4 V.E..... R.....ID 0,0-900,90} that was originally added here
所谓的“has leaked window”,就是窗口泄漏,我们都知道dialog是依赖于activity存在的,故创建dialog时的context必须是activity的context。而之所以会出现窗口泄露,一般情况是dialog正显示着,但activity却被销毁了,用代码重现大概是这样子的:
dialog.show();
finish();
换句话说,在activity被销毁前,没有调用dialog的dismiss方法,就会出现上面的窗口泄露bug
知道原因后,解决方案也非常简单:
1.主动销毁:在finish之前把dialog给dismiss掉就行了。
2.被动销毁:在activity的onDestroy中,或者根据自己项目具体情况,在activity生命周期覆写函数中把dialog 给dismiss掉。
dialog的第二个bug
java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{4b155550 V.E..... R.....I. 0,0-900,90} not attached to window manager
所谓“not attached to window manager”,就是说dialog没有可附加的窗口,一般情况是当activity被销毁后,调用dialog的show或dismiss方法就会出现该bug,用代码重现大概是这样子的:
finish();
handler.post(new Runnable() {
@Override
public void run() {
dialog.dismiss();
}
},1000)
如上代码,activity销毁,1秒后调用dialog的dismiss方法,一般的业务场景为:使用线程进行网络请求后要关掉对话框,但此时activity已被销毁(手速很快的返回或其它原因退出当前activity),就会出现该bug。
同样知道原因后,解决方案也非常简单:
我们只需在调用dialog的show和dismiss的方法前,判断activity是否已经被销毁。为了便于使用,建议在创建dialog时直接覆盖show和dismiss两个方法即可,代码如下:
Dialog dlg = new Dialog(activity){
@Override
public void show() {
if(!activity.isFinishing())
super.show();
}
@Override
public void dismiss() {
if(!activity.isFinishing())
super.dismiss();
}
};
5、DialogFragment是在android 3.0时被引入的,有些人会奇怪:为什么还要引入这么一个东东呢?
其实嘛,上面dialog的两个bug可不是白讲的!没错,如果使用DialogFragment的话,完全不存在着上面那样的窗口泄露问题。
因为就如上面所说的,DialogFragment是继承于Fragment的,所以,它拥有Fragment的生命周期,由FragmentManager进行管理,故此,其明显比dialog有更大的好处,举个最简单的例子:一个activity上正显示着一个dialog,如果此时旋转了屏幕方向,activity重建后,dialog却消失了,并且会出现上面dialog的第一个bug——窗口泄露,而如果使用DialogFragment的话,则完全不受影响,activity重建后,dialog依然能够正常显示,这得益于DialogFragment拥有完整的生命周期。
下面来说说本人使用DialogFragment遇到的问题:
如果你将DialogFragment进行复用的话,当你多次调用其show方法的话,会出现如下异常:
java.lang.IllegalStateException: Fragment already added: LoadDialogFragment{4ad202d4 #0 loading}
正常来说,如果show和dismiss配对调用的话,是不会出现该问题的,但是,有时确实很难保证配对调用,保不齐哪里的异步就出现多次调用show呢?所以,该问题还是得解决的!
其实,从这个bug字面上来说,不就是说Fragment已经被添加了吗?那么在调用show之前,我们进行一下判断不是OK了吗?将代码改为如下:
public void showLoading() {
if (loadingDialog == null) {
loadingDialog=new LoadDialogFragment();
}
if(!loadingDialog.isAdded()){
loadingDialog.show(getSupportFragmentManager(),"loading");
}
}
可惜结果还是不行,两次调用 showLoading(),程序还是崩溃!
打了断点,发现第一次调用show方法后,mAdded这个变量依然是false,这就奇了怪啦!难道isAdded()这个API是摆设的吗?不可能!本着“存在即是合理”的原则,我再次查看了show方法的源码:
public void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
如上源码,我们注意到最后一步事务提交: ft.commit(),其实这个commit并不是立即执行的, 它会被发送到主线程的任务队列当中去, 当主线程准备好执行它的时候执行。
也就是说,其实它是异步的,故此才导致mAdded变量刷新不及时,所以,解决方案为,使事务提交即时生效,只需要在commit之后加上executePendingTransactions(),这样就能将异步转为同步,故代码更改为:
public void showLoading() {
if (loadingDialog == null) {
loadingDialog=new LoadDialogFragment();
}
if(!loadingDialog.isAdded()){
loadingDialog.show(getSupportFragmentManager(),"loading");
getSupportFragmentManager().executePendingTransactions();//即时生效
}
}
经试验,原因如上述所说,该方案有效!
后继续查看源码,无意中发现DialogFragment除了show之外,还有showNow这个API,源码如下:
public void showNow(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitNow();
}
其实区别也在最后一步:ft.commit();变成了 ft.commitNow();
经查资料得知:之前用executePendingTransactions()会将所有在队列中还有你当前提交的transaction都执行了, 而commitNow()将只会执行你当前要提交的transaction. 所以commitNow()可以避免你不小心执行了那些你可能并不想执行的transactions。
同时,考虑到当activity被销毁后,getSupportFragmentManager()会出现空指针异常,故最终将代码更改为如下:
public void showLoading() {
if (loadingDialog == null) {
loadingDialog=new LoadDialogFragment();
}
if(!loadingDialog.isAdded() && !isFinishing()){
loadingDialog.showNow(getSupportFragmentManager(),"loading");
}
}
最后,如同官方所云:推荐使用DialogFragment来创建对话框,不推荐直接用Dialog创建对话框。
另外,如果弹窗是从底部出来的话,可考虑直接使用android.support.design.widget.BottomSheetDialogFragment哦,O(∩_∩)O
android弹窗不能手动关闭_Android弹窗的实现及相关bug相关推荐
- android弹窗不能手动关闭_Android app(Service)如何在后台随时随地弹出/关闭悬浮窗?...
需求 语音唤醒后在系统任意界面(应用)弹出悬浮窗(定制设备,非手机). 问题 进程在前台时没问题,悬浮窗可以开关,进程转到后台以后就不行,即栈顶是其他应用的时候,悬浮窗弹不出,回到自己 app 查看, ...
- elementUI的消息弹窗组件手动关闭和遮罩层关闭问题
手动关闭MessageBox弹窗 使用this.$msgbox.close();官方给出的相关资料如下 2.移除掉DOM(慎用) var messageBox = document.querySele ...
- android弹窗不能手动关闭_3大类APP弹窗提醒方式总结
一.概念简述 顾名思义,提醒方式,是指用户需要提醒的时候,在 APP 出现的一些提醒机制. 一般采用弹窗的形式进行提示,它的功能意义是: 对用户当前操作进行信息提醒并对其作出补充,或中断用户当前操作并 ...
- android弹窗不能手动关闭_vue3.0系列:Vue3自定义PC端弹窗组件V3Layer
今天给大家分享的是Vue3系列之自定义桌面端对话框组件v3layer. V3Layer 基于vue3.0构建的多功能PC网页端弹窗组件.拥有超过10+种弹窗类型.30+种参数配置,支持拖拽(自定义拖拽 ...
- Android 天气APP(十三)仿微信弹窗(右上角加号点击弹窗效果)、自定义背景图片、UI优化调整
上一篇:Android 天气APP(十二)空气质量.UI优化调整 天气预报详情,逐小时预报详情 新版------------------- 一.适配器点击监听 二.页面实现 三.天气预报详情弹窗 四. ...
- layer 关闭一个弹窗打不开新的的弹窗_人民日报批弹窗广告,教你几个屏蔽弹窗广告的小技巧...
弹窗广告,对于经常上网的人来说,一定不陌生."不请自来"以及"赖着不走",可以说是弹窗广告的最大特征.天下网友苦弹窗广告久矣-- 近日,人民日报刊文<&q ...
- php程序layer,php 提交表单 关闭layer弹窗iframe的实例讲解
介绍一款非常好用的前端弹窗插件: 根据官方的API:layer的iframe弹窗 //iframe层-父子操作 layer.open({ type: 2, area: ['700px', '530px ...
- Android:使用Activity制作中间弹窗
使用Activity制作中间弹窗 前言 使用activity制作弹窗的好处就是,自由发挥的余地更大了.匆匆的用activity制作了中间弹窗的小demo,没有重写activity显示和消失的动画,圆角 ...
- layui admin 当前子页面 刷新 其他页面 layui 关闭 子弹窗
layui admin 当前子页面 刷新 其他页面 var parent =parent.layui.jquery; var indexWindow = parent('iframe[lay-id=& ...
最新文章
- Go 学习笔记(71)— Go 接口 interface (接口定义、接口实现、接口调用、值接收者、指针接收者)
- 初识C语言---(1)
- 南京邮电考研计算机科学大纲,2019年南京邮电大学811数据结构考研大纲
- 943c语言,考研备战:华南理工大学943计算方法(含C语言)复试大纲_跨考网
- springDatasolr 排序
- Linux下查看txt文档
- android 混合开发 图片,混合开发的大趋势之一React Native之Image
- [原创] VPDN--PPTP Server
- 韩山师范计算机科学与技术,韩山师范学院计算机科学与技术专业
- 我的开源项目:AAC格式分析器
- Sql Server系列:数据类型转换函数
- Redis实现分布式session功能的共享
- 如何在CDSN打开Markdown编辑界面
- 易用宝项目记录day2-框架搭建
- android 圆形自定义进度条,Android 实现自定义圆形进度条的功能
- Python数据处理041:数据分析之时间序列
- 腾讯QQ邮箱、网易163邮箱配置客户端(Windows自带邮件)教程
- 国家一级建造师—工程经济—第一章—第四节
- springboot集成hadoop实战
- multi-view stereo教程
热门文章
- 最新 Molecular Operating Environment (MOE) Linux Windows
- 在 Windows 10 中查找 BitLocker 恢复密钥
- markdown如何修改为 微软雅黑 字体
- VMware16安装CentOS7.6虚拟机
- 【软件测试从入门到放弃】熟悉阶段:软件测试流程
- mysql 提示ssl问题
- 2018-2019-2 20165222《网络对抗技术》Exp9 Web安全基础
- 【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析
- python中自定义超时异常的几种方法
- javascript系列:NaN类型