学习和使用程序捕捉异常 CrashHandler以及ACRA
来源:互联网 发布:地质中学校花聂知 编辑:程序博客网 时间:2024/06/03 19:12
今天,我来回顾一下如何友好的处理程序异常。
目前,我学习两种方法去实现友好界面处理异常
方法一:CrashHandler(老的使用办法)
方法二:ACRA(Google推荐)
1.CrashHandler如何使用?
1.1CrashHandler类
import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.PrintWriter;import java.io.StringWriter;import java.io.Writer;import java.lang.Thread.UncaughtExceptionHandler;import java.lang.reflect.Field;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.LinkedList;import java.util.List;import java.util.Map;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.os.Build;import android.os.Environment;import android.util.Log;@SuppressLint("SimpleDateFormat")public class CrashHandler implements UncaughtExceptionHandler {public static final String TAG = "CrashHandler";List<String> filepath=new ArrayList<String>();// 系统默认的UncaughtException处理类private UncaughtExceptionHandler mDefaultHandler;// CrashHandler实例private static CrashHandler INSTANCE = new CrashHandler();// 程序的Context对象private Context mContext;// 用来存储设备信息和异常信息private Map<String, String> infos = new HashMap<String, String>();CrashLogUpload crashLogUpload = new CrashLogUpload();// 用于格式化日期,作为日志文件名的一部分private DateFormat formatter = new SimpleDateFormat("MMddHHmm");public static List<CrashLogUpload> crashLogUploadList=new ArrayList<CrashLogUpload>(); ;private List<Activity> activityList = new LinkedList<Activity>();/** 保证只有一个CrashHandler实例 */private CrashHandler() {}/** 获取CrashHandler实例 ,单例模式 */public static CrashHandler getInstance() {return INSTANCE;}/** * 初始化 * * @param context */public void init(Context context) {mContext = context;// 获取系统默认的UncaughtException处理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 设置该CrashHandler为程序的默认处理器Thread.setDefaultUncaughtExceptionHandler(this);} /** * 这个是最关键的函数,当程序中有未被捕获的异常,系统将会自动调用#uncaughtException方法 * thread为出现未捕获异常的线程,ex为未捕获的异常,有了这个ex,我们就可以得到异常信息。 */@Overridepublic void uncaughtException(Thread thread, Throwable ex) {if (!handleException(ex) && mDefaultHandler != null) {// 如果用户没有处理则让系统默认的异常处理器来处理mDefaultHandler.uncaughtException(thread, ex);} else {// 退出程序try {Thread.sleep(3000);} catch (InterruptedException e) {Log.e(TAG, "error : ", e);}exit();}}/** * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. * * @param ex * @return true:如果处理了该异常信息;否则返回false. */private boolean handleException(Throwable ex) {if (ex == null) {return false;}// 收集设备参数信息collectDeviceInfo(mContext);// 保存日志文件saveCrashInfo2File(ex);return true;}/** * 收集设备参数信息 * * @param ctx */public void collectDeviceInfo(Context ctx) {try {PackageManager pm = ctx.getPackageManager();PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),PackageManager.GET_ACTIVITIES);if (pi != null) {String versionName = pi.versionName == null ? "null": pi.versionName;String versionCode = pi.versionCode + "";infos.put("versionName", versionName);infos.put("versionCode", versionCode);}} catch (NameNotFoundException e) {Log.e(TAG, "an error occured when collect package info", e);}Field[] fields = Build.class.getDeclaredFields();for (Field field : fields) {try {field.setAccessible(true);infos.put(field.getName(), field.get(null).toString());Log.d(TAG, field.getName() + " : " + field.get(null));} catch (Exception e) {Log.e(TAG, "an error occured when collect crash info", e);}}}/** * 保存错误信息到文件中 * * @param ex * @return 返回文件名称,便于将文件传送到服务器 */private String saveCrashInfo2File(Throwable ex) {StringBuffer sb = new StringBuffer();for (Map.Entry<String, String> entry : infos.entrySet()) {String key = entry.getKey();String value = entry.getValue();sb.append(key + "=" + value + "\n");}Writer writer = new StringWriter();PrintWriter printWriter = new PrintWriter(writer);ex.printStackTrace(printWriter);Throwable cause = ex.getCause();while (cause != null) {cause.printStackTrace(printWriter);cause = cause.getCause();}printWriter.close();String result = writer.toString();sb.append(result);try {String time = formatter.format(new Date());String fileName = "crash" + time +".log";if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {String path = getOutputLoggerFileFloder();File dir = new File(path);if (!dir.exists()) {dir.mkdirs();}File file = new File(path + File.separator + fileName);FileWriter filerWriter = new FileWriter(file, true);// 后面这个参数代表是不是要接上文件中原来的数据,不进行覆盖BufferedWriter bufWriter = new BufferedWriter(filerWriter);bufWriter.write(sb.toString());bufWriter.newLine();bufWriter.close();filerWriter.close();}} catch (Exception e) {Log.e(TAG, "an error occured while writing file...", e);}return null;}private String getOutputLoggerFileFloder() {File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator + "app_log" + File.separator + "Loggers");if (!directory.exists()) {directory.mkdirs();}return directory.getPath();}public void addActivity(Activity activity) {activityList.add(activity);}// 遍历所有Activity并finishpublic void exit() {for (Activity activity : activityList) {activity.finish();}android.os.Process.killProcess(android.os.Process.myPid());System.exit(1);}}
1.2打印日志类
import java.util.Date;public class CrashLogUpload {private String id;private String fileName;private String filePath;private Date recordTime;private Boolean hasUpload;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}public String getFilePath() {return filePath;}public void setFilePath(String filePath) {this.filePath = filePath;}public Date getRecordTime() {return recordTime;}public void setRecordTime(Date recordTime) {this.recordTime = recordTime;}public Boolean getHasUpload() {return hasUpload;}public void setHasUpload(Boolean hasUpload) {this.hasUpload = hasUpload;} }
1.3在appliaction的oncrate()方法中初始化
//在这里为应用设置异常处理程序,然后我们的程序才能捕获未处理的异常 CrashHandler crashHandler = CrashHandler.getInstance(); crashHandler.init(getApplicationContext());
2.如何使用Acra捕捉异常
2.1下载Acra架包,as library
下载地址:http://pan.baidu.com/s/1kVydkjl,然后考入lib中,右击as library
2.1 application中初始化
ACRA.init(this);可根据自身需求设置
有弹出框提示,有保存本地提示,有上传信息到服务器,有吐司等
最基本的
@ReportsCrashes( formKey = "", // This is required for backward compatibility but not used formUri = "http://www.backendofyourchoice.com/reportpath" )
我们可以根据源码中和自己的需求来运用
ReportsCrashes源码:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.acra.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.acra.ReportField;import org.acra.ReportingInteractionMode;import org.acra.sender.HttpSender.Method;import org.acra.sender.HttpSender.Type;@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})@Inheritedpublic @interface ReportsCrashes { String formKey(); String formUri() default ""; ReportingInteractionMode mode() default ReportingInteractionMode.SILENT; int resDialogCommentPrompt() default 0; int resDialogEmailPrompt() default 0; int resDialogIcon() default 17301543; int resDialogOkToast() default 0; int resDialogText() default 0; int resDialogTitle() default 0; int resNotifIcon() default 17301624; int resNotifText() default 0; int resNotifTickerText() default 0; int resNotifTitle() default 0; int resToastText() default 0; String sharedPreferencesName() default ""; int sharedPreferencesMode() default 0; boolean includeDropBoxSystemTags() default false; String[] additionalDropBoxTags() default {}; int dropboxCollectionMinutes() default 5; String[] logcatArguments() default {"-t", "100", "-v", "time"}; String formUriBasicAuthLogin() default "ACRA-NULL-STRING"; String formUriBasicAuthPassword() default "ACRA-NULL-STRING"; ReportField[] customReportContent() default {}; String mailTo() default ""; boolean deleteUnapprovedReportsOnApplicationStart() default true; boolean deleteOldUnsentReportsOnApplicationStart() default true; int connectionTimeout() default 3000; int socketTimeout() default 5000; int maxNumberOfRequestRetries() default 3; boolean forceCloseDialogAfterToast() default false; String[] additionalSharedPreferences() default {}; boolean logcatFilterByPid() default false; boolean sendReportsInDevMode() default true; String[] excludeMatchingSharedPreferencesKeys() default {}; String[] excludeMatchingSettingsKeys() default {}; String applicationLogFile() default ""; int applicationLogFileLines() default 100; String googleFormUrlFormat() default "https://docs.google.com/spreadsheet/formResponse?formkey=%s&ifq"; boolean disableSSLCertValidation() default false; Method httpMethod() default Method.POST; Type reportType() default Type.FORM;}
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.acra;import android.app.Application;import android.content.SharedPreferences;import android.content.SharedPreferences.OnSharedPreferenceChangeListener;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.preference.PreferenceManager;import org.acra.ACRAConfiguration;import org.acra.ACRAConfigurationException;import org.acra.ErrorReporter;import org.acra.annotation.ReportsCrashes;import org.acra.log.ACRALog;import org.acra.log.AndroidLogDelegate;public class ACRA { public static final boolean DEV_LOGGING = false; public static final String LOG_TAG = ACRA.class.getSimpleName(); public static ACRALog log = new AndroidLogDelegate(); public static final String PREF_DISABLE_ACRA = "acra.disable"; public static final String PREF_ENABLE_ACRA = "acra.enable"; public static final String PREF_ENABLE_SYSTEM_LOGS = "acra.syslog.enable"; public static final String PREF_ENABLE_DEVICE_ID = "acra.deviceid.enable"; public static final String PREF_USER_EMAIL_ADDRESS = "acra.user.email"; public static final String PREF_ALWAYS_ACCEPT = "acra.alwaysaccept"; public static final String PREF_LAST_VERSION_NR = "acra.lastVersionNr"; private static Application mApplication; private static ReportsCrashes mReportsCrashes; private static ErrorReporter errorReporterSingleton; private static OnSharedPreferenceChangeListener mPrefListener; private static ACRAConfiguration configProxy; public ACRA() { } public static void <span style="color:#ff0000;">init</span>(Application app) { if(mApplication != null) { log.w(LOG_TAG, "ACRA#init called more than once. Won\'t do anything more."); } else { mApplication = app; mReportsCrashes = (ReportsCrashes)mApplication.getClass().getAnnotation(ReportsCrashes.class); if(mReportsCrashes == null) { log.e(LOG_TAG, "ACRA#init called but no ReportsCrashes annotation on Application " + mApplication.getPackageName()); } else { SharedPreferences prefs = getACRASharedPreferences(); try { checkCrashResources(); log.d(LOG_TAG, "ACRA is enabled for " + mApplication.getPackageName() + ", intializing..."); boolean e = !shouldDisableACRA(prefs); ErrorReporter errorReporter = new ErrorReporter(mApplication, prefs, e); errorReporter.setDefaultReportSenders(); errorReporterSingleton = errorReporter; } catch (ACRAConfigurationException var4) { log.w(LOG_TAG, "Error : ", var4); } mPrefListener = new OnSharedPreferenceChangeListener() { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if("acra.disable".equals(key) || "acra.enable".equals(key)) { boolean enableAcra = !ACRA.shouldDisableACRA(sharedPreferences); ACRA.getErrorReporter().setEnabled(enableAcra); } } }; prefs.registerOnSharedPreferenceChangeListener(mPrefListener); } } } public static ErrorReporter getErrorReporter() { if(errorReporterSingleton == null) { throw new IllegalStateException("Cannot access ErrorReporter before ACRA#init"); } else { return errorReporterSingleton; } } private static boolean shouldDisableACRA(SharedPreferences prefs) { boolean disableAcra = false; try { boolean e = prefs.getBoolean("acra.enable", true); disableAcra = prefs.getBoolean("acra.disable", !e); } catch (Exception var3) { ; } return disableAcra; } static void checkCrashResources() throws ACRAConfigurationException { ACRAConfiguration conf = getConfig(); switch(ACRA.SyntheticClass_1.$SwitchMap$org$acra$ReportingInteractionMode[conf.mode().ordinal()]) { case 1: if(conf.resToastText() == 0) { throw new ACRAConfigurationException("TOAST mode: you have to define the resToastText parameter in your application @ReportsCrashes() annotation."); } break; case 2: if(conf.resNotifTickerText() == 0 || conf.resNotifTitle() == 0 || conf.resNotifText() == 0 || conf.resDialogText() == 0) { throw new ACRAConfigurationException("NOTIFICATION mode: you have to define at least the resNotifTickerText, resNotifTitle, resNotifText, resDialogText parameters in your application @ReportsCrashes() annotation."); } break; case 3: if(conf.resDialogText() == 0) { throw new ACRAConfigurationException("DIALOG mode: you have to define at least the resDialogText parameters in your application @ReportsCrashes() annotation."); } } } public static SharedPreferences getACRASharedPreferences() { ACRAConfiguration conf = getConfig(); return !"".equals(conf.sharedPreferencesName())?mApplication.getSharedPreferences(conf.sharedPreferencesName(), conf.sharedPreferencesMode()):PreferenceManager.getDefaultSharedPreferences(mApplication); } public static ACRAConfiguration getConfig() { if(configProxy == null) { if(mApplication == null) { log.w(LOG_TAG, "Calling ACRA.getConfig() before ACRA.init() gives you an empty configuration instance. You might prefer calling ACRA.getNewDefaultConfig(Application) to get an instance with default values taken from a @ReportsCrashes annotation."); } configProxy = getNewDefaultConfig(mApplication); } return configProxy; } public static void setConfig(ACRAConfiguration conf) { configProxy = conf; } public static ACRAConfiguration getNewDefaultConfig(Application app) { return app != null?new ACRAConfiguration((ReportsCrashes)app.getClass().getAnnotation(ReportsCrashes.class)):new ACRAConfiguration((ReportsCrashes)null); } static boolean isDebuggable() { PackageManager pm = mApplication.getPackageManager(); try { return (pm.getApplicationInfo(mApplication.getPackageName(), 0).flags & 2) > 0; } catch (NameNotFoundException var2) { return false; } } static Application getApplication() { return mApplication; } public static void setLog(ACRALog log) { log = log; }}
同时,我们也可以自定义方法去实现实现显示的方式。
0 0
- 学习和使用程序捕捉异常 CrashHandler以及ACRA
- android异常捕捉处理-CrashHandler
- 使用CrashHandler来捕获Crash异常
- ACRA(异常处理)
- ACRA(异常处理)
- ACRA(异常处理)
- android 程序异常捕捉处理
- 捕获全局异常 CrashHandler
- CrashHandler捕获全局异常
- CrashHandler 异常事件处理
- 自定义异常捕获-CrashHandler
- struts2学习笔记异常捕捉
- 异常的捕捉和抛出
- ACRA 和自定义布局
- python 自定义异常和异常捕捉
- Android 对程序异常崩溃的捕捉
- android程序奔溃异常捕捉
- android程序奔溃异常捕捉
- Qt在Windows中,OpenGL禁用,使用d3d
- linux命令英文缩写的含义(方便记忆)
- Volley 源码解析
- Source命令
- Java mkdir() 导致的Bug
- 学习和使用程序捕捉异常 CrashHandler以及ACRA
- Ubuntu14.04配置OpenCL开发环境
- 安卓屏幕适配
- java反编译工具(JD-Eclipse) eclipse插件安装
- Android 4.4跟Android 5.0浸入式状态栏的实现
- hdu 1074 Doing Homework
- MySQL分库分表环境下全局ID生成方案
- SQL注入是什么?我们如何去玩转它
- [乙女向]NORN9(命运九重奏)乙女向PSP汉化版