Android异常处理框架
2014-12-01 09:47
120 查看
Android系统的“程序异常退出”,给应用的用户体验造成不良影响。为了捕获应用运行时异常并给出友好提示,便可继承UncaughtExceptionHandler类来处理。
思路:
1.此类主要完成一下几个任务
1.1 提示友好的错误信息
1.1.1网络异常,错误码:%d
1.1.2网络异常,请求超时
1.1.3网络异常,读取数据超时
1.1.4网络连接失败,请检查网络设置
1.1.5数据解析异常
1.1.6数据解析异常
1.1.7文件流异常
1.1.8应用程序运行时异常
1.2 保存异常日志
1.2.1判断是否挂载了SD卡
1.2.2没有挂载SD卡,无法写文件,直接return
1.2.3将异常写入文件
1.3 自定义异常处理:收集错误信息&发送错误报告
现在来研究一下 开源中国 异常处理框架。
使用:
1.在Application子类,注册App异常崩溃处理器。
application是用来保存全局变量的,并且是在package创建的时候就跟着存在了。
Thread.setDefaultUncaughtExceptionHandler()方法将异常处理类设置到线程上。
2. 例:检查更新版本
UpdateManager.java
3.普通异常处理
4.发送toast消息
((AppException)msg.obj).makeToast(QuestionPub.this);
msg.obj为Exception ,强制转换到AppException,得到异常类型,Toast.
思路:
1.此类主要完成一下几个任务
1.1 提示友好的错误信息
1.1.1网络异常,错误码:%d
1.1.2网络异常,请求超时
1.1.3网络异常,读取数据超时
1.1.4网络连接失败,请检查网络设置
1.1.5数据解析异常
1.1.6数据解析异常
1.1.7文件流异常
1.1.8应用程序运行时异常
1.2 保存异常日志
1.2.1判断是否挂载了SD卡
1.2.2没有挂载SD卡,无法写文件,直接return
1.2.3将异常写入文件
1.3 自定义异常处理:收集错误信息&发送错误报告
现在来研究一下 开源中国 异常处理框架。
/** * 应用程序异常类:用于捕获异常和提示错误信息 * @author liux (http://my.oschina.net/liux) * @version 1.0 * @created 2012-3-21 */ public class AppException extends Exception implements UncaughtExceptionHandler{ private final static boolean Debug = false;//是否保存错误日志 /** 定义异常类型 */ public final static byte TYPE_NETWORK = 0x01; public final static byte TYPE_SOCKET = 0x02; public final static byte TYPE_HTTP_CODE = 0x03; public final static byte TYPE_HTTP_ERROR= 0x04; public final static byte TYPE_XML = 0x05; public final static byte TYPE_IO = 0x06; public final static byte TYPE_RUN = 0x07; public final static byte TYPE_JSON = 0x08; private byte type; private int code; /** 系统默认的UncaughtException处理类 */ private Thread.UncaughtExceptionHandler mDefaultHandler; private AppException(){ this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); } private AppException(byte type, int code, Exception excp) { super(excp); this.type = type; this.code = code; if(Debug){ this.saveErrorLog(excp); } } public int getCode() { return this.code; } public int getType() { return this.type; } /** * 提示友好的错误信息 * @param ctx */ public void makeToast(Context ctx){ switch(this.getType()){ case TYPE_HTTP_CODE: String err = ctx.getString(R.string.http_status_code_error, this.getCode()); Toast.makeText(ctx, err, Toast.LENGTH_SHORT).show(); break; case TYPE_HTTP_ERROR: Toast.makeText(ctx, R.string.http_exception_error, Toast.LENGTH_SHORT).show(); break; case TYPE_SOCKET: Toast.makeText(ctx, R.string.socket_exception_error, Toast.LENGTH_SHORT).show(); break; case TYPE_NETWORK: Toast.makeText(ctx, R.string.network_not_connected, Toast.LENGTH_SHORT).show(); break; case TYPE_XML: Toast.makeText(ctx, R.string.xml_parser_failed, Toast.LENGTH_SHORT).show(); break; case TYPE_JSON: Toast.makeText(ctx, R.string.xml_parser_failed, Toast.LENGTH_SHORT).show(); break; case TYPE_IO: Toast.makeText(ctx, R.string.io_exception_error, Toast.LENGTH_SHORT).show(); break; case TYPE_RUN: Toast.makeText(ctx, R.string.app_run_code_error, Toast.LENGTH_SHORT).show(); break; } } /** * 保存异常日志 * @param excp */ public void saveErrorLog(Exception excp) { String errorlog = "errorlog.txt"; String savePath = ""; String logFilePath = ""; FileWriter fw = null; PrintWriter pw = null; try { //判断是否挂载了SD卡 String storageState = Environment.getExternalStorageState(); if(storageState.equals(Environment.MEDIA_MOUNTED)){ savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSChina/Log/"; File file = new File(savePath); if(!file.exists()){ file.mkdirs(); } logFilePath = savePath + errorlog; } //没有挂载SD卡,无法写文件 if(logFilePath == ""){ return; } File logFile = new File(logFilePath); if (!logFile.exists()) { logFile.createNewFile(); } fw = new FileWriter(logFile,true); pw = new PrintWriter(fw); pw.println("--------------------"+(new Date().toLocaleString())+"---------------------"); excp.printStackTrace(pw); pw.close(); fw.close(); } catch (Exception e) { e.printStackTrace(); }finally{ if(pw != null){ pw.close(); } if(fw != null){ try { fw.close(); } catch (IOException e) { }} } } public static AppException http(int code) { return new AppException(TYPE_HTTP_CODE, code, null); } public static AppException http(Exception e) { return new AppException(TYPE_HTTP_ERROR, 0 ,e); } public static AppException socket(Exception e) { return new AppException(TYPE_SOCKET, 0 ,e); } public static AppException io(Exception e) { if(e instanceof UnknownHostException || e instanceof ConnectException){ return new AppException(TYPE_NETWORK, 0, e); } else if(e instanceof IOException){ return new AppException(TYPE_IO, 0 ,e); } return run(e); } public static AppException xml(Exception e) { return new AppException(TYPE_XML, 0, e); } public static AppException json(Exception e) { return new AppException(TYPE_JSON, 0, e); } public static AppException network(Exception e) { if(e instanceof UnknownHostException || e instanceof ConnectException){ return new AppException(TYPE_NETWORK, 0, e); } else if(e instanceof HttpException){ return http(e); } else if(e instanceof SocketException){ return socket(e); } return http(e); } public static AppException run(Exception e) { return new AppException(TYPE_RUN, 0, e); } /** * 获取APP异常崩溃处理对象 * @param context * @return */ public static AppException getAppExceptionHandler(){ return new AppException(); } @Override public void uncaughtException(Thread thread, Throwable ex) { if(!handleException(ex) && mDefaultHandler != null) { mDefaultHandler.uncaughtException(thread, ex); } } /** * 自定义异常处理:收集错误信息&发送错误报告 * @param ex * @return true:处理了该异常信息;否则返回false */ private boolean handleException(Throwable ex) { if(ex == null) { return false; } final Context context = AppManager.getAppManager().currentActivity(); if(context == null) { return false; } final String crashReport = getCrashReport(context, ex); //显示异常信息&发送报告 new Thread() { public void run() { Looper.prepare(); UIHelper.sendAppCrashReport(context, crashReport); Looper.loop(); } }.start(); return true; } /** * 获取APP崩溃异常报告 * @param ex * @return */ private String getCrashReport(Context context, Throwable ex) { PackageInfo pinfo = ((AppContext)context.getApplicationContext()).getPackageInfo(); StringBuffer exceptionStr = new StringBuffer(); exceptionStr.append("Version: "+pinfo.versionName+"("+pinfo.versionCode+")\n"); exceptionStr.append("Android: "+android.os.Build.VERSION.RELEASE+"("+android.os.Build.MODEL+")\n"); exceptionStr.append("Exception: "+ex.getMessage()+"\n"); StackTraceElement[] elements = ex.getStackTrace(); for (int i = 0; i < elements.length; i++) { exceptionStr.append(elements[i].toString()+"\n"); } return exceptionStr.toString(); } }
使用:
1.在Application子类,注册App异常崩溃处理器。
application是用来保存全局变量的,并且是在package创建的时候就跟着存在了。
Thread.setDefaultUncaughtExceptionHandler()方法将异常处理类设置到线程上。
@Override public void onCreate() { super.onCreate(); Thread.setDefaultUncaughtExceptionHandler(AppException.getAppExceptionHandler()); }
2. 例:检查更新版本
/** * 检查版本更新 * @param url * @return */ public static Update checkVersion(AppContext appContext) throws AppException { try{ return Update.parse(http_get(appContext, URLs.UPDATE_VERSION)); }catch(Exception e){ if(e instanceof AppException) throw (AppException)e; throw AppException.network(e); } }
public static Update parse(InputStream inputStream) throws IOException, AppException { Update update = null; try { //....... } catch (XmlPullParserException e) { throw AppException.xml(e); } finally { inputStream.close(); } return update; }
UpdateManager.java
new Thread(){ public void run() { Message msg = new Message(); try { Update update = ApiClient.checkVersion((AppContext)mContext.getApplicationContext()); msg.what = 1; msg.obj = update; } catch (AppException e) { e.printStackTrace(); } handler.sendMessage(msg); } }.start();
3.普通异常处理
/** * 下载图片-可指定显示图片的高宽 * @param url * @param width * @param height */ private Bitmap downloadBitmap(String url, int width, int height) { Bitmap bitmap = null; try { //http加载图片 bitmap = ApiClient.getNetBitmap(url); if(width > 0 && height > 0) { //指定显示图片的高宽 bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true); } //放入缓存 cache.put(url, new SoftReference<Bitmap>(bitmap)); } catch (AppException e) { e.printStackTrace(); } return bitmap; }
4.发送toast消息
final Handler handler = new Handler(){ public void handleMessage(Message msg) { if(mProgress!=null)mProgress.dismiss(); if(msg.what == 1){ Result res = (Result)msg.obj; UIHelper.ToastMessage(QuestionPub.this, res.getErrorMessage()); if(res.OK()){ //发送通知广播 if(res.getNotice() != null){ UIHelper.sendBroadCast(QuestionPub.this, res.getNotice()); } //清除之前保存的编辑内容 ac.removeProperty(AppConfig.TEMP_POST_TITLE,AppConfig.TEMP_POST_CATALOG,AppConfig.TEMP_POST_CONTENT); //跳转到文章详情 finish(); } } else { ((AppException)msg.obj).makeToast(QuestionPub.this); } } }; new Thread(){ public void run() { Message msg = new Message(); try { Result res = ac.pubPost(post); msg.what = 1; msg.obj = res; } catch (AppException e) { e.printStackTrace(); msg.what = -1; msg.obj = e; } handler.sendMessage(msg); } }.start();
((AppException)msg.obj).makeToast(QuestionPub.this);
msg.obj为Exception ,强制转换到AppException,得到异常类型,Toast.
/** * 发送App异常崩溃报告 * * @param cont * @param crashReport */ public static void sendAppCrashReport(final Context cont, final String crashReport) { AlertDialog.Builder builder = new AlertDialog.Builder(cont); builder.setIcon(android.R.drawable.ic_dialog_info); builder.setTitle(R.string.app_error); builder.setMessage(R.string.app_error_message); builder.setPositiveButton(R.string.submit_report, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // 发送异常报告 Intent i = new Intent(Intent.ACTION_SEND); // i.setType("text/plain"); //模拟器 i.setType("message/rfc822"); // 真机 i.putExtra(Intent.EXTRA_EMAIL, new String[] { "zhangdeyi@oschina.net" }); i.putExtra(Intent.EXTRA_SUBJECT, "开源中国Android客户端 - 错误报告"); i.putExtra(Intent.EXTRA_TEXT, crashReport); cont.startActivity(Intent.createChooser(i, "发送错误报告")); // 退出 AppManager.getAppManager().AppExit(cont); } }); builder.setNegativeButton(R.string.sure, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // 退出 AppManager.getAppManager().AppExit(cont); } }); builder.show(); }
相关文章推荐
- Android程序崩溃异常处理框架
- Android程序崩溃异常处理框架
- 一个用于J2EE应用程序的异常处理框架
- EJB 最佳实践: 构建更好的异常处理框架
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[上篇]
- Struts的校验框架与异常处理框架
- [转]设计一个高效合理的异常处理框架
- 构建更好的异常处理框架
- ubuntu下android开发环境搭建(及错误异常处理)
- 处理Android UI的栈溢出异常
- 关于Struts处理异常框架的小例子
- Java异常处理框架JEHA发布1.0版本
- Java异常处理框架
- 一个用于J2EE应用程序的异常处理框架
- J2EE应用程序异常处理框架
- 设计一个高效合理的异常处理框架
- ICE框架之Sclice2CSharp映射---异常的处理
- J2EE应用程序异常处理框架
- 关于Struts处理异常框架的小例子
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]