您的位置:首页 > 其它

使用CrashHandler来获取应用的Crash信息

2016-03-17 09:24 405 查看
在我们的实际开发中,我们都避免不了遇到我们程序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中调用:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: