使用CrashHandler来获取应用的Crash信息
2016-03-17 09:24
459 查看
在我们的实际开发中,我们都避免不了遇到我们程序crash直接崩掉的情况,这对用户来说是很不友好的 ,当然也是我们开发者不想看到的。所以我们希望当我们的程序发生异常crash的时候,我们能够得治用户的crash信息,我们也可以在程序crash的时候弹出一个对话框告诉用户程序crash了。然后再退出,这样比闪退会好一些。
在安卓中我们可以利用CrashHandler来监视我们应用的crash信息。这里也将CrashHander引入到我们的框架中去。
[java] view
plain copy
package com.nsu.library.utils.log;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import java.io.*;
import java.util.Calendar;
import java.util.Locale;
/**
* Create By Anthony on 2016/1/16
* 当前类注释:异常处理类,将我们的异常信息保存到本地SD卡上面或者上传到服务器
*/
public class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final boolean DEBUG =true;
private static final String TAG ="UncaughtExceptionHandler";
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
public UncaughtExceptionHandler(Context context, Thread.UncaughtExceptionHandler defaultHandler){
this.mDefaultHandler = defaultHandler;
this.mContext = context;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Log.e("Crash", "Application crash", ex);
writeFile(thread, ex);//将异常信息保存到SD卡上面
//TODO 在这里写方法将异常信息上传到服务器
mDefaultHandler.uncaughtException(thread, ex);
}
private void writeFile(final Thread thread, final Throwable ex){
//如果SD卡不存在则无法写入
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
if(DEBUG){
Log.w(TAG,"SDCard unmounted, skip write exception to file");
return ;
}
}
try {
OutputStream os = getLogStream();
os.write(getExceptionInformation(thread, ex).getBytes("utf-8"));
os.flush();
os.close();
android.os.Process.killProcess(android.os.Process.myPid());
}
catch(Exception e){
e.printStackTrace();
}
}
private OutputStream getLogStream() throws IOException {
//crash_log_pkgname.log
String fileName = String.format("crash_%s.log", mContext.getPackageName());
File file = new File(Environment.getExternalStorageDirectory(), fileName);
if(!file.exists()){
file.createNewFile();
}
OutputStream os = new FileOutputStream(file, true);
return os;
}
private String getExceptionInformation(Thread thread, Throwable ex){
long current = System.currentTimeMillis();
StringBuilder sb = new StringBuilder().append('\n');
sb.append("THREAD: ").append(thread).append('\n');
sb.append("BOARD: ").append(Build.BOARD).append('\n');
sb.append("BOOTLOADER: ").append(Build.BOOTLOADER).append('\n');
sb.append("BRAND: ").append(Build.BRAND).append('\n');
sb.append("CPU_ABI: ").append(Build.CPU_ABI).append('\n');
sb.append("CPU_ABI2: ").append(Build.CPU_ABI2).append('\n');
sb.append("DEVICE: ").append(Build.DEVICE).append('\n');
sb.append("DISPLAY: ").append(Build.DISPLAY).append('\n');
sb.append("FINGERPRINT: ").append(Build.FINGERPRINT).append('\n');
sb.append("HARDWARE: ").append(Build.HARDWARE).append('\n');
sb.append("HOST: ").append(Build.HOST).append('\n');
sb.append("ID: ").append(Build.ID).append('\n');
sb.append("MANUFACTURER: ").append(Build.MANUFACTURER).append('\n');
sb.append("MODEL: ").append(Build.MODEL).append('\n');
sb.append("PRODUCT: ").append(Build.PRODUCT).append('\n');
sb.append("SERIAL: ").append(Build.SERIAL).append('\n');
sb.append("TAGS: ").append(Build.TAGS).append('\n');
sb.append("TIME: ").append(Build.TIME).append(' ').append(toDateString(Build.TIME)).append('\n');
sb.append("TYPE: ").append(Build.TYPE).append('\n');
sb.append("USER: ").append(Build.USER).append('\n');
sb.append("VERSION.CODENAME: ").append(Build.VERSION.CODENAME).append('\n');
sb.append("VERSION.INCREMENTAL: ").append(Build.VERSION.INCREMENTAL).append('\n');
sb.append("VERSION.RELEASE: ").append(Build.VERSION.RELEASE).append('\n');
sb.append("VERSION.SDK_INT: ").append(Build.VERSION.SDK_INT).append('\n');
sb.append("LANG: ").append(mContext.getResources().getConfiguration().locale.getLanguage()).append('\n');
sb.append("APP.VERSION.NAME: ").append(getVersionName()).append('\n');
sb.append("APP.VERSION.CODE: ").append(getVersionCode()).append('\n');
sb.append("CURRENT: ").append(current).append(' ').append(toDateString(current)).append('\n');
sb.append(getErrorInformation(ex));
return sb.toString();
}
private String getVersionName(){
PackageManager packageManager = mContext.getPackageManager();
PackageInfo packInfo = null;
try {
packInfo = packageManager.getPackageInfo(mContext.getPackageName(),0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
String version = packInfo.versionName;
return version;
}
private int getVersionCode(){
PackageManager packageManager = mContext.getPackageManager();
PackageInfo packInfo = null;
try {
packInfo = packageManager.getPackageInfo(mContext.getPackageName(),0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
int version = packInfo.versionCode;
return version;
}
private String getErrorInformation(Throwable t){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter writter = new PrintWriter(baos);
t.printStackTrace(writter);
writter.flush();
String result = new String(baos.toByteArray());
writter.close();
return result;
}
private String toDateString(long timeMilli){
Calendar calc = Calendar.getInstance();
calc.setTimeInMillis(timeMilli);
return String.format(Locale.CHINESE, "%04d.%02d.%02d %02d:%02d:%02d:%03d",
calc.get(Calendar.YEAR), calc.get(Calendar.MONTH) + 1, calc.get(Calendar.DAY_OF_MONTH),
calc.get(Calendar.HOUR_OF_DAY), calc.get(Calendar.MINUTE), calc.get(Calendar.SECOND), calc.get(Calendar.MILLISECOND));
}
}
在这里我们只需要在我们的Application中调用:
[java] view
plain copy
package com.nsu.library.app;
import android.app.Application;
import com.nsu.library.utils.log.UncaughtExceptionHandler;
/**
* Create By Anthony on 2016/1/15
* 当前类注释:Application的子类,本项目中的Application将继承本类。
* 当前功能:单例模式,异常捕获,由子类实现的获取url
*/
public abstract class AbsApplication extends Application {
private static AbsApplication sInstance;
public static AbsApplication app(){
return sInstance;
}
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler(this,
Thread.getDefaultUncaughtExceptionHandler()));
}
/***************** About URL ***********************/
public static enum SourceType{
JSON, XML,SOAP
}
abstract public String getApplicationConfigUrl();
abstract public SourceType getSourceType();
abstract public String getFirstClassUrl();
}
以后在我们的程序出现异常崩溃的时候我们都可以将我们的错误信息写入到我们的SD卡上。后期实现还可以将错误信息上报服务器,有利于软件的二次维护。
这里在以前的项目开发中也用到过另外一种情况,我们直接告诉用户我们的程序异常退出了,需不需要重启:
[java] view
plain copy
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import com.trs.xizang.voice.activity.VtibetSplashActivity;
import com.trs.xizang.voice.view.VAlertDialog;
/**
* Created by Anthony on 2015/11/18.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static CrashHandler INSTANCE = new CrashHandler();
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private CrashHandler() {
}
public static CrashHandler getInstance() {
return INSTANCE;
}
public void init(Context ctx) {
mContext = ctx;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
ex.printStackTrace();
new Thread() {
@Override
public void run() {
Looper.prepare();
final AlertDialog dialog = new AlertDialog(mContext);
dialog.setMessage("程序异常退出,是否需要重新启动应用?"));
dialog.setPositiveListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
Intent intent = new Intent(mContext.getApplicationContext(), VtibetSplashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
System.exit(0);
}
});
dialog.setNegativeListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
System.exit(0);
}
});
dialog.show();
Looper.loop();
}
}.start();
}
}
上面这个处理的CrashHandler里面直接调用了Thread.setDefaultUncaughtExceptionHandler(this),然而在我们开始介绍的那个CrashHanler里面是在Application里面调用的。 所以使用上面这个CrashHandler的方式是在Application的onCreate里面调用:
okay!!!
java异常处理机制博客:http://blog.csdn.net/hguisu/article/details/6155636
在安卓中我们可以利用CrashHandler来监视我们应用的crash信息。这里也将CrashHander引入到我们的框架中去。
[java] view
plain copy
package com.nsu.library.utils.log;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import java.io.*;
import java.util.Calendar;
import java.util.Locale;
/**
* Create By Anthony on 2016/1/16
* 当前类注释:异常处理类,将我们的异常信息保存到本地SD卡上面或者上传到服务器
*/
public class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final boolean DEBUG =true;
private static final String TAG ="UncaughtExceptionHandler";
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
public UncaughtExceptionHandler(Context context, Thread.UncaughtExceptionHandler defaultHandler){
this.mDefaultHandler = defaultHandler;
this.mContext = context;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Log.e("Crash", "Application crash", ex);
writeFile(thread, ex);//将异常信息保存到SD卡上面
//TODO 在这里写方法将异常信息上传到服务器
mDefaultHandler.uncaughtException(thread, ex);
}
private void writeFile(final Thread thread, final Throwable ex){
//如果SD卡不存在则无法写入
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
if(DEBUG){
Log.w(TAG,"SDCard unmounted, skip write exception to file");
return ;
}
}
try {
OutputStream os = getLogStream();
os.write(getExceptionInformation(thread, ex).getBytes("utf-8"));
os.flush();
os.close();
android.os.Process.killProcess(android.os.Process.myPid());
}
catch(Exception e){
e.printStackTrace();
}
}
private OutputStream getLogStream() throws IOException {
//crash_log_pkgname.log
String fileName = String.format("crash_%s.log", mContext.getPackageName());
File file = new File(Environment.getExternalStorageDirectory(), fileName);
if(!file.exists()){
file.createNewFile();
}
OutputStream os = new FileOutputStream(file, true);
return os;
}
private String getExceptionInformation(Thread thread, Throwable ex){
long current = System.currentTimeMillis();
StringBuilder sb = new StringBuilder().append('\n');
sb.append("THREAD: ").append(thread).append('\n');
sb.append("BOARD: ").append(Build.BOARD).append('\n');
sb.append("BOOTLOADER: ").append(Build.BOOTLOADER).append('\n');
sb.append("BRAND: ").append(Build.BRAND).append('\n');
sb.append("CPU_ABI: ").append(Build.CPU_ABI).append('\n');
sb.append("CPU_ABI2: ").append(Build.CPU_ABI2).append('\n');
sb.append("DEVICE: ").append(Build.DEVICE).append('\n');
sb.append("DISPLAY: ").append(Build.DISPLAY).append('\n');
sb.append("FINGERPRINT: ").append(Build.FINGERPRINT).append('\n');
sb.append("HARDWARE: ").append(Build.HARDWARE).append('\n');
sb.append("HOST: ").append(Build.HOST).append('\n');
sb.append("ID: ").append(Build.ID).append('\n');
sb.append("MANUFACTURER: ").append(Build.MANUFACTURER).append('\n');
sb.append("MODEL: ").append(Build.MODEL).append('\n');
sb.append("PRODUCT: ").append(Build.PRODUCT).append('\n');
sb.append("SERIAL: ").append(Build.SERIAL).append('\n');
sb.append("TAGS: ").append(Build.TAGS).append('\n');
sb.append("TIME: ").append(Build.TIME).append(' ').append(toDateString(Build.TIME)).append('\n');
sb.append("TYPE: ").append(Build.TYPE).append('\n');
sb.append("USER: ").append(Build.USER).append('\n');
sb.append("VERSION.CODENAME: ").append(Build.VERSION.CODENAME).append('\n');
sb.append("VERSION.INCREMENTAL: ").append(Build.VERSION.INCREMENTAL).append('\n');
sb.append("VERSION.RELEASE: ").append(Build.VERSION.RELEASE).append('\n');
sb.append("VERSION.SDK_INT: ").append(Build.VERSION.SDK_INT).append('\n');
sb.append("LANG: ").append(mContext.getResources().getConfiguration().locale.getLanguage()).append('\n');
sb.append("APP.VERSION.NAME: ").append(getVersionName()).append('\n');
sb.append("APP.VERSION.CODE: ").append(getVersionCode()).append('\n');
sb.append("CURRENT: ").append(current).append(' ').append(toDateString(current)).append('\n');
sb.append(getErrorInformation(ex));
return sb.toString();
}
private String getVersionName(){
PackageManager packageManager = mContext.getPackageManager();
PackageInfo packInfo = null;
try {
packInfo = packageManager.getPackageInfo(mContext.getPackageName(),0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
String version = packInfo.versionName;
return version;
}
private int getVersionCode(){
PackageManager packageManager = mContext.getPackageManager();
PackageInfo packInfo = null;
try {
packInfo = packageManager.getPackageInfo(mContext.getPackageName(),0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
int version = packInfo.versionCode;
return version;
}
private String getErrorInformation(Throwable t){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter writter = new PrintWriter(baos);
t.printStackTrace(writter);
writter.flush();
String result = new String(baos.toByteArray());
writter.close();
return result;
}
private String toDateString(long timeMilli){
Calendar calc = Calendar.getInstance();
calc.setTimeInMillis(timeMilli);
return String.format(Locale.CHINESE, "%04d.%02d.%02d %02d:%02d:%02d:%03d",
calc.get(Calendar.YEAR), calc.get(Calendar.MONTH) + 1, calc.get(Calendar.DAY_OF_MONTH),
calc.get(Calendar.HOUR_OF_DAY), calc.get(Calendar.MINUTE), calc.get(Calendar.SECOND), calc.get(Calendar.MILLISECOND));
}
}
在这里我们只需要在我们的Application中调用:
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler(this, Thread.getDefaultUncaughtExceptionHandler()));
[java] view
plain copy
package com.nsu.library.app;
import android.app.Application;
import com.nsu.library.utils.log.UncaughtExceptionHandler;
/**
* Create By Anthony on 2016/1/15
* 当前类注释:Application的子类,本项目中的Application将继承本类。
* 当前功能:单例模式,异常捕获,由子类实现的获取url
*/
public abstract class AbsApplication extends Application {
private static AbsApplication sInstance;
public static AbsApplication app(){
return sInstance;
}
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler(this,
Thread.getDefaultUncaughtExceptionHandler()));
}
/***************** About URL ***********************/
public static enum SourceType{
JSON, XML,SOAP
}
abstract public String getApplicationConfigUrl();
abstract public SourceType getSourceType();
abstract public String getFirstClassUrl();
}
以后在我们的程序出现异常崩溃的时候我们都可以将我们的错误信息写入到我们的SD卡上。后期实现还可以将错误信息上报服务器,有利于软件的二次维护。
这里在以前的项目开发中也用到过另外一种情况,我们直接告诉用户我们的程序异常退出了,需不需要重启:
[java] view
plain copy
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import com.trs.xizang.voice.activity.VtibetSplashActivity;
import com.trs.xizang.voice.view.VAlertDialog;
/**
* Created by Anthony on 2015/11/18.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static CrashHandler INSTANCE = new CrashHandler();
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private CrashHandler() {
}
public static CrashHandler getInstance() {
return INSTANCE;
}
public void init(Context ctx) {
mContext = ctx;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
ex.printStackTrace();
new Thread() {
@Override
public void run() {
Looper.prepare();
final AlertDialog dialog = new AlertDialog(mContext);
dialog.setMessage("程序异常退出,是否需要重新启动应用?"));
dialog.setPositiveListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
Intent intent = new Intent(mContext.getApplicationContext(), VtibetSplashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
System.exit(0);
}
});
dialog.setNegativeListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
System.exit(0);
}
});
dialog.show();
Looper.loop();
}
}.start();
}
}
上面这个处理的CrashHandler里面直接调用了Thread.setDefaultUncaughtExceptionHandler(this),然而在我们开始介绍的那个CrashHanler里面是在Application里面调用的。 所以使用上面这个CrashHandler的方式是在Application的onCreate里面调用:
CrashHandler.getInstance().init(this);
okay!!!
java异常处理机制博客:http://blog.csdn.net/hguisu/article/details/6155636
相关文章推荐
- 第三周项目4年龄几何
- Java垃圾收集学习笔记
- 位运算
- MySQL 源码安装
- linux内存cached释放
- 第三周项目三输出三角
- Struts2中 Result类型配置详解
- gitlab 版本控制系统 github的开源实现
- JVM性能优化入门指南
- 使用Tcl脚本分配FPGA管脚
- .Net Core CLI windows安装
- Qt打印调试信息输出到android logcat中
- Fullpage.js固定导航栏-实现定位导航栏
- 蓝牙协议规范(射频、基带链路控制、链路管理)
- [Songqw.Net 基础]WPF插件化中同步Style
- 编程小练习10
- 深入浅出--iOS的TCP/IP协议族剖析&&Socket
- linux】利用logger,logrotate处理脚本日志
- Struts2-result类型
- java 为什么序列化?为什么不是所有的类序列化?