您的位置:首页 > 移动开发 > Android开发

Android Exception&Throwable 常见异常和解决方法 奔溃日志上报 monkey异常修改

2017-07-28 16:59 239 查看
java将所有的错误封装为一个对象,其根本父类为Throwable, Throwable有两个子类:Error和Exception。注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。Error: 这种异常被设计成不被捕获,因为这种异常产生于JVM自身。Runtime Exception: 运行时异常往往与环境有关,编译时无法检查,并且可能发生的情况太广泛,所以系统会去处理,程序不需要捕获。Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。       运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。      运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。       非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。问题:内存溢出不能捕获的原因:
首先,你得明白,内存溢出不是异常,是Error,Java中的异常分为受查异常和不受查异常。不受查异常时无法获取之后用程序处理的。
OutOfMemory是不受查异常,它是由于java虚拟机运行时无法再分配到内存引起的,这时java虚拟机已经无法正常工作了,只能停止,所以就不能再捕获
二,异常的捕获方法:try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。catch 块:用于处理try捕获到的异常。finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:1)在finally语句块中发生了异常。2)在前面的代码中用了System.exit()退出程序。3)程序所在的线程死亡。4)关闭CPU。

 try、catch、finally语句块的执行顺序:

1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;三,常见异常和处理方法

runtimeException子类:

1 .java.lang.NullPointerException2. java.lang.IllegalArgumentException:n must be positive3.集合变化java.util.ConcurrentModificationException,Caused by: java.lang.ArrayIndexOutOfBoundsException4.动画里面的算术java.lang.NumberFormatException: Invalid double: ""java.lang.ArithmeticException: divide by zero5.java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState
奇葩的问题:1.图片。类,找不到,混淆问题:android.content.res.Resources$NotFoundException:File res/drawable-xhdpi-v4/abnormal_purple_beg.png from drawable resource ID #0x7f0200082.没有方法,可能是API低版本的不支持,java.lang.NoSuchMethodError3.java.util.concurrent.TimeoutException:4.java.lang.SecurityException:Not allowed to start activity Intent5.Causedby: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died6.java.lang.RuntimeException:Could not read input channel file descriptors from parcel.
7.java.lang.reflect.InvocationTargetException

IOException

1.数据库的IO异常   android.database.sqlite.SQLiteDiskIOException:2.文件没有找到3.android.database.sqlite.SQLiteException: cannot commit - no transaction is activeatandroid.database.sqlite.SQLiteStatement.native_executeSql(Native Method)at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:93)at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1900)at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1839)atandroid.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:714)at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:276)at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:99)at android.database.sqlite.SQLiteDatabase.delete(SQLiteDatabase.java:1741)atcom.cx.module.data.apk.b$a.f(Unknown Source)at com.cx.module.data.apk.b$a.a(Unknown Source)at com.cx.module.data.apk.g.a(Unknown Source)at com.cx.module.data.center.b$1.run(Unknown Source)at java.lang.Thread.run(Thread.java:856)Error:Error:内存溢出:java.lang.OutOfMemoryError:Failed to allocate a 1868981625 byte allocation with 991781 free bytes and 509MB until OOMAndroid 中出现的1.有相同的ID java.lang.IllegalArgumentException: Wrong state class, expecting View State but received class android.widget.ProgressBar$SavedState instead. This usually happens when two views of different type have the same id in the same hierarchy. This view's id is id/progressBar. Make sure other views do not use the same id.  2.大致意思是说我使用的 commit方法是在Activity的onSaveInstanceState()之后调用的,这样会出错,因为 onSaveInstanceState方法是在该Activity即将被销毁前调用,来保存Activity数据的,如果在保存玩状态后再给它添加Fragment就会出错。解决办法就是把commit()方法替换成 commitAllowingStateLoss()就行解决IllegalStateException: Can not perform this action after onSaveInstanceState3.Fragmentjava.lang.IllegalStateException: Fragment already added:4.   Java.lang.IllegalStateException:The specified child already has a parent. You must call removeView() on the child's parent first.出现在Fragment或者是Adatper中! 分析mInflater.inflate(R.layout.eg_refresh_message, this, false);5.清理   TidyShowActivity back建和onsaveinstance, 不调用父类的方法就可以5.listview中list和adapter不同步的问题6. NetWorkOnMainThreadException     不能在主线程联网7.使用Fragment时遇到Binary

XMLfile line #9: Error inflating class fragment

解决方法:fragment加入的Activity 应该继承于 FragmentActivity8.java.net.SocketException:Noroute原因:wifi未打开,无路由解决方法:wifi未打开,重新打开9. Can't create handler inside thread thathas not called Looper.prepare()原因:不能在线程中操作主线程,比如在线程中创建dialog,更新UI等都是不可以的解决方法:在主线程中创建handler,通过handler.sendmessage()来更新UI,因为在主线程中创建的handler属于主线程,起10.Android.view.WindowManager$BadTokenException:Unable to add window -- token null is not for an application解决方案:将getApplication改成xxxx.this全局捕获异常并上报:比如第三方的友盟、蒲公英等,腾讯BuglyUncaughtExceptionHandler:在程序异常的时候,默认是把进程杀死,有们自己先上报然后手动再杀死进程!在Android开发中,常常会出现uncheched Exception 导致程序的crash,为了提供良好的用户体验,并对出错的信息进行收集,以便对程序进行改进,提高程序的健壮性。因此,常使用Thread.UncaughtExceptionHandler来进行处理。
/**
* 奔溃日志收集类
* @author rongweixin
* @version 2017/2/15 11:26
* @email rongweixin@17renren.com
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {

//系统默认的UncaughtException处理类
private Thread.UncaughtExceptionHandler mDefaultHandler;
//CrashHandler实例
private static CrashHandler instance = new CrashHandler();
//程序的Context对象
private Context mContext;
private static final String TAG=CrashHandler.class.getSimpleName();
/** 崩溃应用包名KEY */
private final String KEY_PKG = "key_pkg";
/** APP版本号KEY */
private final String KEY_VER = "key_ver";
/** APP渠道号KEY */
private final String KEY_CXHZCHANNEL = "key_cxhzchannel";
/** 厂商 */
private final String KEY_BRAND = "key_brand";
/** 机型 */
private final String KEY_MODEL = "key_model";
/** 系统版本KEY */
private final String KEY_OS_VER = "key_os_ver";
/** 崩溃时间KEY */
private final String KEY_TIME = "key_time";
//用来存储设备信息和异常信息 系统崩溃日志
private Map<String, String> infos;
//用于格式化日期,作为日志文件名的一部分
private DateFormat formatter;

/** 保证只有一个CrashHandler实例 */
private CrashHandler() {
infos = new HashMap<String, String>();
formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.CHINA);
}

/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance() {
return instance;
}

/**
* 初始化
* @param context
*/
public void init(final Context context) {
mContext = context;
//获取系统默认的UncaughtException处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
//设置该CrashHandler为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
new Thread(new Runnable() {
@Override
public void run() {
String pkg = CXPackageManagerUtil.getCurProcessName(context);
for(int i=0;i<3;i++){
if(pkg.contains(context.getPackageName())){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
pkg = CXPackageManagerUtil.getCurProcessName(context);
}else{
break;
}
}
infos.put(KEY_PKG, pkg);
if(pkg.contains(context.getPackageName())){
infos.put(KEY_VER, String.valueOf(CXPackageManagerUtil.getPackageVersionCode(context)));
infos.put(KEY_CXHZCHANNEL, CXPackageManagerUtil.getChannel(context));
}else{
infos.put(KEY_VER, String.valueOf(CXPackageManagerUtil.getVersionCode(mContext, mContext.getPackageName())));
infos.put(KEY_CXHZCHANNEL, "");
}
infos.put(KEY_BRAND, Build.BRAND);
infos.put(KEY_MODEL, Build.MODEL);
infos.put(KEY_OS_VER, Build.VERSION.RELEASE);
CXLog.i(TAG, infos.toString());
}
}).start();
}

/**
* 初始化数据
* @param pkg
*/
public void init(String pkg){
if(pkg != null){
infos.put(KEY_PKG, pkg);
infos.put(KEY_VER, String.valueOf(CXPackageManagerUtil.getVersionCode(mContext, mContext.getPackageName())));
infos.put(KEY_CXHZCHANNEL, CXPackageManagerUtil.getChannel(mContext));
infos.put(KEY_BRAND, Build.BRAND);
infos.put(KEY_MODEL, Build.MODEL);
infos.put(KEY_OS_VER, Build.VERSION.RELEASE);
CXLog.i(TAG, infos.toString());
}
}

/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false.
*/
private boolean handleException(Throwable ex) {
boolean handled = false;
if(ex != null){
// 上传奔溃日志
postCrash(getCrashInfo(ex));
// 保存奔溃日志
CXLog.e(TAG, infos.toString());
CXLog.e(TAG, getCrashInfo(ex));
//            writeCrashInfo(ex);
//使用Toast来显示异常信息
if(infos.get(KEY_PKG).equals(mContext.getPackageName())){
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "程序发生异常,正在退出……", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
}
handled = true;
}
return handled;
}
java将所有的错误封装为一个对象,其根本父类为Throwable, Throwable有两个子类:Error和Exception。注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。Error: 这种异常被设计成不被捕获,因为这种异常产生于JVM自身。Runtime Exception: 运行时异常往往与环境有关,编译时无法检查,并且可能发生的情况太广泛,所以系统会去处理,程序不需要捕获。Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。       运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。      运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。       非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。问题:内存溢出不能捕获的原因:
首先,你得明白,内存溢出不是异常,是Error,Java中的异常分为受查异常和不受查异常。不受查异常时无法获取之后用程序处理的。
OutOfMemory是不受查异常,它是由于java虚拟机运行时无法再分配到内存引起的,这时java虚拟机已经无法正常工作了,只能停止,所以就不能再捕获
二,异常的捕获方法:try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。catch 块:用于处理try捕获到的异常。finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:1)在finally语句块中发生了异常。2)在前面的代码中用了System.exit()退出程序。3)程序所在的线程死亡。4)关闭CPU。

 try、catch、finally语句块的执行顺序:

1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;三,常见异常和处理方法

runtimeException子类:

1 .java.lang.NullPointerException2. java.lang.IllegalArgumentException:n must be positive3.集合变化java.util.ConcurrentModificationException,Caused by: java.lang.ArrayIndexOutOfBoundsException4.动画里面的算术java.lang.NumberFormatException: Invalid double: ""java.lang.ArithmeticException: divide by zero5.java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState
奇葩的问题:1.图片。类,找不到,混淆问题:android.content.res.Resources$NotFoundException:File res/drawable-xhdpi-v4/abnormal_purple_beg.png from drawable resource ID #0x7f0200082.没有方法,可能是API低版本的不支持,java.lang.NoSuchMethodError3.java.util.concurrent.TimeoutException:4.java.lang.SecurityException:Not allowed to start activity Intent5.Causedby: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died6.java.lang.RuntimeException:Could not read input channel file descriptors from parcel.
7.java.lang.reflect.InvocationTargetException

IOException

1.数据库的IO异常   android.database.sqlite.SQLiteDiskIOException:2.文件没有找到3.android.database.sqlite.SQLiteException: cannot commit - no transaction is activeatandroid.database.sqlite.SQLiteStatement.native_executeSql(Native Method)at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:93)at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1900)at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1839)atandroid.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:714)at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:276)at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:99)at android.database.sqlite.SQLiteDatabase.delete(SQLiteDatabase.java:1741)atcom.cx.module.data.apk.b$a.f(Unknown Source)at com.cx.module.data.apk.b$a.a(Unknown Source)at com.cx.module.data.apk.g.a(Unknown Source)at com.cx.module.data.center.b$1.run(Unknown Source)at java.lang.Thread.run(Thread.java:856)Error:Error:内存溢出:java.lang.OutOfMemoryError:Failed to allocate a 1868981625 byte allocation with 991781 free bytes and 509MB until OOMAndroid 中出现的1.有相同的ID java.lang.IllegalArgumentException: Wrong state class, expecting View State but received class android.widget.ProgressBar$SavedState instead. This usually happens when two views of different type have the same id in the same hierarchy. This view's id is id/progressBar. Make sure other views do not use the same id.  2.大致意思是说我使用的 commit方法是在Activity的onSaveInstanceState()之后调用的,这样会出错,因为 onSaveInstanceState方法是在该Activity即将被销毁前调用,来保存Activity数据的,如果在保存玩状态后再给它添加Fragment就会出错。解决办法就是把commit()方法替换成 commitAllowingStateLoss()就行解决IllegalStateException: Can not perform this action after onSaveInstanceState3.Fragmentjava.lang.IllegalStateException: Fragment already added:4.   Java.lang.IllegalStateException:The specified child already has a parent. You must call removeView() on the child's parent first.出现在Fragment或者是Adatper中! 分析mInflater.inflate(R.layout.eg_refresh_message, this, false);5.清理   TidyShowActivity back建和onsaveinstance, 不调用父类的方法就可以5.listview中list和adapter不同步的问题6. NetWorkOnMainThreadException     不能在主线程联网7.使用Fragment时遇到Binary

XMLfile line #9: Error inflating class fragment

解决方法:fragment加入的Activity 应该继承于 FragmentActivity8.java.net.SocketException:Noroute原因:wifi未打开,无路由解决方法:wifi未打开,重新打开9. Can't create handler inside threadthat has not called Looper.prepare()原因:不能在线程中操作主线程,比如在线程中创建dialog,更新UI等都是不可以的解决方法:在主线程中创建handler,通过handler.sendmessage()来更新UI,因为在主线程中创建的handler属于主线程,起10.Android.view.WindowManager$BadTokenException:Unable to add window -- token null is not for an application解决方案:将getApplication改成xxxx.this全局捕获异常并上报:比如第三方的友盟、蒲公英等,腾讯BuglyUncaughtExceptionHandler:在程序异常的时候,默认是把进程杀死,有们自己先上报然后手动再杀死进程!在Android开发中,常常会出现uncheched Exception 导致程序的crash,为了提供良好的用户体验,并对出错的信息进行收集,以便对程序进行改进,提高程序的健壮性。因此,常使用Thread.UncaughtExceptionHandler来进行处理。
/*** 奔溃日志收集类* @author rongweixin* @version 2017/2/15 11:26* @email rongweixin@17renren.com*/public class CrashHandler implements Thread.UncaughtExceptionHandler {//系统默认的UncaughtException处理类private Thread.UncaughtExceptionHandler mDefaultHandler;//CrashHandler实例private static CrashHandler instance = new CrashHandler();//程序的Context对象private Context mContext;private static final String TAG=CrashHandler.class.getSimpleName();/** 崩溃应用包名KEY */private final String KEY_PKG = "key_pkg";/** APP版本号KEY */private final String KEY_VER = "key_ver";/** APP渠道号KEY */private final String KEY_CXHZCHANNEL = "key_cxhzchannel";/** 厂商 */private final String KEY_BRAND = "key_brand";/** 机型 */private final String KEY_MODEL = "key_model";/** 系统版本KEY */private final String KEY_OS_VER = "key_os_ver";/** 崩溃时间KEY */private final String KEY_TIME = "key_time";//用来存储设备信息和异常信息 系统崩溃日志private Map<String, String> infos;//用于格式化日期,作为日志文件名的一部分private DateFormat formatter;/** 保证只有一个CrashHandler实例 */private CrashHandler() {infos = new HashMap<String, String>();formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.CHINA);}/** 获取CrashHandler实例 ,单例模式 */public static CrashHandler getInstance() {return instance;}/*** 初始化* @param context*/public void init(final Context context) {mContext = context;//获取系统默认的UncaughtException处理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();//设置该CrashHandler为程序的默认处理器Thread.setDefaultUncaughtExceptionHandler(this);new Thread(new Runnable() {@Overridepublic void run() {String pkg = CXPackageManagerUtil.getCurProcessName(context);for(int i=0;i<3;i++){if(pkg.contains(context.getPackageName())){try {Thread.sleep(1000);}catch (Exception e){e.printStackTrace();}pkg = CXPackageManagerUtil.getCurProcessName(context);}else{break;}}infos.put(KEY_PKG, pkg);if(pkg.contains(context.getPackageName())){infos.put(KEY_VER, String.valueOf(CXPackageManagerUtil.getPackageVersionCode(context)));infos.put(KEY_CXHZCHANNEL, CXPackageManagerUtil.getChannel(context));}else{infos.put(KEY_VER, String.valueOf(CXPackageManagerUtil.getVersionCode(mContext, mContext.getPackageName())));infos.put(KEY_CXHZCHANNEL, "");}infos.put(KEY_BRAND, Build.BRAND);infos.put(KEY_MODEL, Build.MODEL);infos.put(KEY_OS_VER, Build.VERSION.RELEASE);CXLog.i(TAG, infos.toString());}}).start();}/*** 初始化数据* @param pkg*/public void init(String pkg){if(pkg != null){infos.put(KEY_PKG, pkg);infos.put(KEY_VER, String.valueOf(CXPackageManagerUtil.getVersionCode(mContext, mContext.getPackageName())));infos.put(KEY_CXHZCHANNEL, CXPackageManagerUtil.getChannel(mContext));infos.put(KEY_BRAND, Build.BRAND);infos.put(KEY_MODEL, Build.MODEL);infos.put(KEY_OS_VER, Build.VERSION.RELEASE);CXLog.i(TAG, infos.toString());}}/*** 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.** @param ex* @return true:如果处理了该异常信息;否则返回false.*/private boolean handleException(Throwable ex) {boolean handled = false;if(ex != null){// 上传奔溃日志postCrash(getCrashInfo(ex));// 保存奔溃日志CXLog.e(TAG, infos.toString());CXLog.e(TAG, getCrashInfo(ex));//            writeCrashInfo(ex);//使用Toast来显示异常信息if(infos.get(KEY_PKG).equals(mContext.getPackageName())){new Thread() {@Overridepublic void run() {Looper.prepare();Toast.makeText(mContext, "程序发生异常,正在退出……", Toast.LENGTH_LONG).show();Looper.loop();}}.start();}handled = true;}return handled;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: