通用Dialog避免IllegalArgumentException
来源:互联网 发布:java 北京尚学堂视频 编辑:程序博客网 时间:2024/06/05 02:01
NewDialog.java
避免IllegalArgumentException
关于错误分析在下面
package com.youpinwallet.ypw.view;import android.app.Activity;import android.app.Dialog;import android.content.Context;import android.view.Gravity;import android.view.WindowManager;import com.youpinwallet.ypw.R;/* * 白色背景,垂直居中 * @author Administrator * */public class NewDialog extends Dialog { Activity mParentActivity; public NewDialog(Context context, int theme) { super(context, theme); mParentActivity= (Activity) context; } public NewDialog(Context context) { super(context); } /** * 弹出自定义ProgressDialog * * @param context 上下文 * @param cancelable 是否按返回键取消 * @param cancelListener 按下返回键监听 * @return */ public static NewDialog create(Context context, boolean cancelable, OnCancelListener cancelListener) { NewDialog dialog = new NewDialog(context, R.style.Custom_Progress); dialog.setContentView(R.layout.progress_layout); // 按返回键是否取消 dialog.setCancelable(cancelable); // 监听返回键处理 dialog.setOnCancelListener(cancelListener); // 设置居中 dialog.getWindow().getAttributes().gravity = Gravity.CENTER; WindowManager.LayoutParams lp = dialog.getWindow().getAttributes(); // 设置背景层透明度 lp.dimAmount = 0.2f; dialog.getWindow().setAttributes(lp);// dialog.show(); return dialog; } @Override public void dismiss() { // 避免依附界面销毁跑出的异常java.lang.IllegalArgumentException: View=com.android.internal.policy.PhoneWindow$DecorView if (mParentActivity != null && !mParentActivity.isFinishing()) { super.dismiss(); //调用超类对应方法 } }}
NewDialogUtils.java
package com.qunarjie.qnj.utils;import android.content.Context;import com.qunarjie.qnj.view.NewDialog;//请稍等通用public class NewDialogUtils { private static NewDialog dialog = null; public static void setNewDialog(Context context) { if (context != null) { if (dialog != null) { dialog.dismiss(); dialog = null; } if (dialog == null) { dialog = NewDialog.create(context, true, null); } dialog.show(); } } public static void dismissNewDialog() { if (dialog != null && dialog.isShowing()) { dialog.dismiss(); dialog = null; } }}
R.style.Custom_Progress
styles.xml
<!-- 自定义Progress --><style name="Custom_Progress" parent="@android:style/Theme.Dialog"> <item name="android:windowFrame">@null</item> <item name="android:windowIsFloating">true</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowCloseOnTouchOutside">false</item> <item name="android:windowNoTitle">true</item></style>
progress_layout.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@drawable/shape_dialog_white" android:gravity="center_horizontal" android:orientation="vertical" android:paddingBottom="20dp" android:paddingLeft="30dp" android:paddingRight="30dp" android:paddingTop="20dp"> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminateDrawable="@drawable/progressbar" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/mdp_15" android:text="请稍等..." android:textColor="@color/color_text_dark" android:textSize="@dimen/msp_14" /></LinearLayout>
shape_dialog_white.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="5dp" /> <solid android:color="@color/white" /></shape>
progressbar.xml
<?xml version="1.0" encoding="utf-8"?><animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="3600"> <shape android:innerRadiusRatio="3" android:shape="ring" android:thicknessRatio="8" android:useLevel="false"> <gradient android:centerY="0.50" android:endColor="#12b7f5" android:startColor="#038fef" android:type="sweep" android:useLevel="false" /> </shape></animated-rotate>
今天遇到一个很奇特的问题,当用户设置了PIN码,在锁屏界面正常解锁PIN码后,进入Launcher时显示com.Android.phone 已停止运行。一开始猜想会不会是解锁PIN码的时候处理导致了Phone进程报错,通过log分析找到了问题的大概原因:
通过分析PIN码的解锁流程知道,并不是PIN码解释时的dialog导致的问题。PIN码解锁流程另用文档说明。
仔细查看log后发现有:
这是开机识别到SIM卡之后弹出的STK对话框。那为什么会报com.android.phone已停止运行呢?经过以上分析,我们可以大致猜测是因为STK引起的问题,既然是STK的问题那为什么会报phone的错误呢?如果是phone的错误那么从log中应该可以检索到phone相关的问题,为什么没有呢?那么我们接下来一一解答这些问题。
(1). 为什么报错com.android.phone已停止运行?
通过查看STK的源码(单卡MTK的代码在/mediatec/packages/app/stk1),在其AndroidManifest.xml可以发现:
android:sharedUserId="android.uid.phone"
也就是STK和Phon在一个进程中,因此在报错的表现上来讲就会是com.andorid.phone。
(2). 为什么会报View not attached to window manager错误?
这个错误的意思是说我们所操作的View没有被纳入window manager的管理。
我们知道所有的窗口创建和管理都是依附于window manager的,因此Dialog的创建也不例外。Dialog的创建流程通过查看源码可以知道,在Dialog的构造函数中,创建了一个Window对象,但我们知道Window对象并不是用于显示的,真正用于显示的是View对象。因此通过Dialog的show方法构造了一个mDecor的View对象,并最终通过WindowManager的addView()方法显示Dialog。
通过查看log信息我们可以看到com.android.stk.StkDialogActivity$4.onClick(StkDialogActivity.java:188)
查看对应的StkDialogActivity代码后发现,在188行处代码为dialog.dismiss();
在网络上搜索后发现,多数情况下出现这种错误,都是在dismiss Dialog时,发现创建该Dialog的Activity存在而导致的。
比如在界面上显示一个Dialog,当任务处理结束后再Dismiss Dialog。如果在Dialog显示期间,该Activity因为某种原因被杀掉且又重新启动了,那么当任务结束时,Dismiss Dialog的时候WindowManager检查,就会发现该Dialog所属的Activity已经不存在了(重新启动了一次,是一个新的Activity),所以会报IllegalArgumentException: View not attached to window manager.
通过以上分析我们可以知道在STK Dialog在执行dismiss方法时,发现启动它的Activity已经不见了,被杀掉了(现在这个是重新启动的),所以才报错出现异常。
(3). 为什么STKDialogActivity会被"杀掉"?
通过跟踪查看异常log我们可以看到StkDialogActivity的生命周期打印log如下:
到这里后就出现了异常错误……
通过log我们可以很清楚的看到该Activity启动了两次。在log中我们也看到了onSaveInstanceState方法。
对于onSaveInstanceState方法,在Android SDK里面有这样的描述:
Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key)
也就说当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
注意这里的容易二字,当前Activity并没有被销毁,只是系统觉得它有可能会被销毁因此会执行该方法。在该方法中我们可以保存Activity中的各种数据信息,如果该Activity真的被杀掉而又重新启动后,可以使用onRestoreInstanceState方法在重新启动该Activity时,还原我们之前保存的数据信息。onSaveInstanceState方法的调用遵循一个重要原则,即当系统“未经你许可”销毁了你的Activity时,onSaveInstanceState就会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然如果你自己不保存,那就没法恢复了)。
因此通过以上分析我们可以看到STKDialogActivity的确被杀掉后再次启动了,但为什么会被杀掉,通过log并没有找到答案。
(4). 在STKDialogActivity被杀掉时,Dialog存在么?
可能大家会有疑问,Dialog都没有看到,就出现错误了,怎么能确定该Dialog当时一定是显示的呢?继续在log中搜索我们可以发现:
这里的WindowManager报错是什么意思呢?这段log是WindowManager抛出的error错误,当我们的Dialog还没有dismiss时,如果此时该Activity被销毁了,那么就会出现以上错误,提示窗口泄漏(leaked window)。这里自己也做了一个实验,写一个demo,在Activity的onCreate方法中显示一个Dialog,然后直接调用finish方法。代码大致如下:
直接将此程序run到模拟器或者真机上,查看log我们就能看到leaked window的报错信息。因此这也证明了前面我们的假设,即StkActivity在被销毁时,其所依附的Dialog是存在的。
(5). 如何解决这个问题呢?
通过以上分析之后我们知道了问题出现的原因,那么如何解决呢?可以通过以下两个方面来解决:
1. 使用Activity自带的Dialog控制方法
在Activity中需要使用对话框,可以使用Activity自带的回调,比如onCreateDialog(),showDialog(),dimissDialog(),removeDialog()等等。毕竟这些都是Activity自带的方法,所以用起来更方便,也不用显示创建和操控Dialog对象,一切都由框架操控,相对来说比较安全。
2. 限制Dialog的生命周期
让创建的Dialog对象的存活周期跟Activity的生命周期一致,也就是说Dialog的生命周期被限定在Activity的onCreate()和onDestroy()方法之间。
阅读全文
0 0
- 通用Dialog避免IllegalArgumentException
- 通用dialog
- 关于dialog引起的IllegalArgumentException
- 通用的Dialog
- 通用对话框Dialog
- android通用的Dialog
- 简单的通用dialog
- Android Dialog通用显示
- Android 通用Dialog的写法
- 自定义Dialog通用提示框
- 底部dialog通用弹窗
- 避免dialog按下返回键消失
- IllegalArgumentException
- IllegalArgumentException
- IllegalArgumentException
- IllegalArgumentException
- illegalArgumentException
- HwLauncher﹕ Launcher dialog dismiss failed : java.lang.IllegalArgumentException: no dialog with id 1
- 【数据库】基于日志系统的恢复机制
- No1031.Campus
- 购物车模块系统的开发
- 获取微信openid
- Openssl 之大数运算函数 BN
- 通用Dialog避免IllegalArgumentException
- C++学习(30)
- python27,anaconda2 安装网络绘图工具igraph及cairo
- 关于zookeeper错误KeeperErrorCode = ConnectionLoss的问题
- vs自带查看动态库dll信息的工具
- ios 遮罩层 全屏显示(有的时候导航栏会遮挡) 引导 --新手笔记
- 【Linux】解决用vi修改文件,保存文件时,提示“readonly option is set”
- plsql的注释
- sysfs方式控制GPIO