弹窗是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相关推荐

  1. android弹窗不能手动关闭_Android app(Service)如何在后台随时随地弹出/关闭悬浮窗?...

    需求 语音唤醒后在系统任意界面(应用)弹出悬浮窗(定制设备,非手机). 问题 进程在前台时没问题,悬浮窗可以开关,进程转到后台以后就不行,即栈顶是其他应用的时候,悬浮窗弹不出,回到自己 app 查看, ...

  2. elementUI的消息弹窗组件手动关闭和遮罩层关闭问题

    手动关闭MessageBox弹窗 使用this.$msgbox.close();官方给出的相关资料如下 2.移除掉DOM(慎用) var messageBox = document.querySele ...

  3. android弹窗不能手动关闭_3大类APP弹窗提醒方式总结

    一.概念简述 顾名思义,提醒方式,是指用户需要提醒的时候,在 APP 出现的一些提醒机制. 一般采用弹窗的形式进行提示,它的功能意义是: 对用户当前操作进行信息提醒并对其作出补充,或中断用户当前操作并 ...

  4. android弹窗不能手动关闭_vue3.0系列:Vue3自定义PC端弹窗组件V3Layer

    今天给大家分享的是Vue3系列之自定义桌面端对话框组件v3layer. V3Layer 基于vue3.0构建的多功能PC网页端弹窗组件.拥有超过10+种弹窗类型.30+种参数配置,支持拖拽(自定义拖拽 ...

  5. Android 天气APP(十三)仿微信弹窗(右上角加号点击弹窗效果)、自定义背景图片、UI优化调整

    上一篇:Android 天气APP(十二)空气质量.UI优化调整 天气预报详情,逐小时预报详情 新版------------------- 一.适配器点击监听 二.页面实现 三.天气预报详情弹窗 四. ...

  6. layer 关闭一个弹窗打不开新的的弹窗_人民日报批弹窗广告,教你几个屏蔽弹窗广告的小技巧...

    弹窗广告,对于经常上网的人来说,一定不陌生."不请自来"以及"赖着不走",可以说是弹窗广告的最大特征.天下网友苦弹窗广告久矣-- 近日,人民日报刊文<&q ...

  7. php程序layer,php 提交表单 关闭layer弹窗iframe的实例讲解

    介绍一款非常好用的前端弹窗插件: 根据官方的API:layer的iframe弹窗 //iframe层-父子操作 layer.open({ type: 2, area: ['700px', '530px ...

  8. Android:使用Activity制作中间弹窗

    使用Activity制作中间弹窗 前言 使用activity制作弹窗的好处就是,自由发挥的余地更大了.匆匆的用activity制作了中间弹窗的小demo,没有重写activity显示和消失的动画,圆角 ...

  9. layui admin 当前子页面 刷新 其他页面 layui 关闭 子弹窗

    layui admin 当前子页面 刷新 其他页面 var parent =parent.layui.jquery; var indexWindow = parent('iframe[lay-id=& ...

最新文章

  1. Go 学习笔记(71)— Go 接口 interface (接口定义、接口实现、接口调用、值接收者、指针接收者)
  2. 初识C语言---(1)
  3. 南京邮电考研计算机科学大纲,2019年南京邮电大学811数据结构考研大纲
  4. 943c语言,考研备战:华南理工大学943计算方法(含C语言)复试大纲_跨考网
  5. springDatasolr 排序
  6. Linux下查看txt文档
  7. android 混合开发 图片,混合开发的大趋势之一React Native之Image
  8. [原创] VPDN--PPTP Server
  9. 韩山师范计算机科学与技术,韩山师范学院计算机科学与技术专业
  10. 我的开源项目:AAC格式分析器
  11. Sql Server系列:数据类型转换函数
  12. Redis实现分布式session功能的共享
  13. 如何在CDSN打开Markdown编辑界面
  14. 易用宝项目记录day2-框架搭建
  15. android 圆形自定义进度条,Android 实现自定义圆形进度条的功能
  16. Python数据处理041:数据分析之时间序列
  17. 腾讯QQ邮箱、网易163邮箱配置客户端(Windows自带邮件)教程
  18. 国家一级建造师—工程经济—第一章—第四节
  19. springboot集成hadoop实战
  20. multi-view stereo教程

热门文章

  1. 最新 Molecular Operating Environment (MOE) Linux Windows
  2. 在 Windows 10 中查找 BitLocker 恢复密钥
  3. markdown如何修改为 微软雅黑 字体
  4. VMware16安装CentOS7.6虚拟机
  5. 【软件测试从入门到放弃】熟悉阶段:软件测试流程
  6. mysql 提示ssl问题
  7. 2018-2019-2 20165222《网络对抗技术》Exp9 Web安全基础
  8. 【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析
  9. python中自定义超时异常的几种方法
  10. javascript系列:NaN类型