Thread.UncaughtExceptionHandler

UncaughtExceptionHandler(未捕获异常处理器)是Thread类的静态内部接口,用来处理用户没有try…caught的异常。也就是系统运行出错throw出来的异常。

UncaughtExceptionHandler里面只有一个方法:

void uncaughtException(Thread thread, Throwable ex);

实现原理

用户调用Thread的静态方法 setDefaultUncaughtExceptionHandler,将自己实现的未捕获异常处理类 设置到Thread私有的静态成员属性defaultUncaughtHandler,也就是简单的set过程。

private static UncaughtExceptionHandler defaultUncaughtHandler;public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {        Thread.defaultUncaughtHandler = handler;    }

如果有用户未捕获的异常信息抛出,那么Thread就会调用其成员属性defaultUncaughtHandler的方法uncaughtException 并传入发生异常的thread和ex异常事件。

So what

那这货有什么用呢?
作为一个用户体验友好的app,应该在未知异常发生时给予用户一定的提示,或者主页面跳转。而不是直接直接奔溃闪退。再者,当我们把app上架到应用市场后,应具备奔溃日志收集功能,这样就可以在查看各个不同设备发生异常的情况,并在下一版本中改善这些情况。
好,那看代码就能知道怎个过程的始末了。

code

/** * Created by cchao on 2016/9/2. * E-mail:   cchao1024@163.com * Description:奔溃日志收集 */public class CrashCatchHandler implements Thread.UncaughtExceptionHandler {        public static final String TAG = "CrashCatchHandler";        //log保存路径        public static String LOG_PATH;        private Context mContext;        //CrashCatchHandler单例        private static CrashCatchHandler INSTANCE = new CrashCatchHandler ( );        //存储设备信息和异常信息        private Map< String, String > mInfoMap;        private SimpleDateFormat mDateFormat;        private CrashCatchHandler ( ) {                mInfoMap = new LinkedHashMap<> ( );                mDateFormat = new SimpleDateFormat ( "yyyy-MM-dd-HH-mm-ss" );        }        /**         * 获取CrashCatchHandler实例 ,单例模式         */        public static CrashCatchHandler getInstance ( ) { return INSTANCE; }        /**         * 初始化         *         * @param context         */        public void init ( Context context ) {                mContext = context;                //设置该CrashCatchHandler为程序的默认未捕获异常处理器                Thread.setDefaultUncaughtExceptionHandler ( this );                //如果外存卡可以读写,放在外部存储器,否则放在内部存储器上                if ( Environment.getExternalStorageState ( ).equals ( Environment.MEDIA_MOUNTED ) ) {                        LOG_PATH = mContext.getExternalFilesDir ( "CARCH_LOG" ).getPath ( );                } else {                        LOG_PATH = mContext.getFilesDir ( ).getPath ( );                }        }        /**         * 当UncaughtException发生时会转入该函数来处理         */        @Override        public void uncaughtException ( Thread thread, Throwable ex ) {                Toast.makeText ( mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG ).show ( );                //收集设备参数信息                collectDeviceInfo ( mContext );                //保存日志文件至本地                postService ( saveCrashLog ( ex ) );        }        /**         * 发送错误日志至服务端         *         * @param fileName log路径         */        private void postService ( String fileName ) {                if ( fileName != null ) {                        //发送奔溃日志 至服务器                        // TODO: 2016/9/2                }        }        /**         * 收集奔溃设备参数信息         */        public void collectDeviceInfo ( Context context ) {                try {                        PackageManager pm = context.getPackageManager ( );                        PackageInfo packageInfo = pm.getPackageInfo ( context.getPackageName ( ), PackageManager.GET_ACTIVITIES );                        if ( packageInfo != null ) {                                String appName = packageInfo.applicationInfo.packageName;                                String versionName = packageInfo.versionName + "";                                String versionCode = packageInfo.versionCode + "";                                mInfoMap.put ( "包名", appName );                                mInfoMap.put ( "版本名", versionName );                                mInfoMap.put ( "版本号", versionCode );                        }                } catch ( PackageManager.NameNotFoundException e ) {                        Log.e ( TAG, "收集设备信息出错", e );                }                Field[] fields = Build.class.getDeclaredFields ( );                for ( Field field : fields ) {                        try {                                field.setAccessible ( true );                                mInfoMap.put ( field.getName ( ), field.get ( null ).toString ( ) );                        } catch ( Exception e ) {                                Log.e ( TAG, "收集奔溃日志出错", e );                        }                }        }        /**         * 保存错误信息到文件中         *         * @param ex         * @return 返回文件名称         */        private String saveCrashLog ( Throwable ex ) {                StringBuilder stringBuilder = new StringBuilder ( );                for ( Map.Entry< String, String > entry : mInfoMap.entrySet ( ) ) {                        String key = entry.getKey ( );                        String value = entry.getValue ( );                        stringBuilder.append ( key + " = " + value + "\n" );                }                //异常写入stringBuilder                Writer writer = new StringWriter ( );                PrintWriter printWriter = new PrintWriter ( writer );                ex.printStackTrace ( printWriter );                //异常原因写入stringBuilder                Throwable cause = ex.getCause ( );                if ( cause != null ) {                        cause.printStackTrace ( printWriter );                }                printWriter.close ( );                String result = writer.toString ( );                stringBuilder.append ( result );                try {                        String time = mDateFormat.format ( new Date ( System.currentTimeMillis ( ) ) );                        String fileName = time + ".txt";                        File dir = new File ( LOG_PATH );                        if ( ! dir.exists ( ) ) {                                dir.mkdirs ( );                        }                        FileOutputStream fos = new FileOutputStream ( dir.getAbsolutePath ( ) + File.separator + fileName );                        fos.write ( stringBuilder.toString ( ).getBytes ( ) );                        fos.close ( );                        return fileName;                } catch ( Exception e ) {                        Log.e ( TAG, "写入文件异常", e );                }                return null;        }}

异常保存的本地路径是:Android/data/包名/files/CARCH_LOG/时间+.txt
在Application中去调用我们自定义的UncaughtExceptionHandler

public class BaseApplication extends Application {        @Override        public void onCreate ( ) {                super.onCreate ( );                CrashCatchHandler.getInstance().init(getApplicationContext ());        }}

更多相关文章

  1. Android(安卓)Dialog 应用
  2. Android跟踪NDK崩溃信息
  3. Android(安卓)FragmentManage FragmentTransaction介绍
  4. 【Android】获取手机通讯录中的联系人信息
  5. Android(安卓)显示网络信息 ConnectivityManager用法
  6. Android(安卓)用户偏好设置,SharedPreference
  7. Android真机调试不打印日志解决
  8. Android(安卓)GPS
  9. Android(安卓)UI日志

随机推荐

  1. Android05
  2. Android常用三栏式滑动/滚动视图(View)的
  3. 服务端和Android客户端利用Socket传输JSO
  4. android Listview中button 和Listview可
  5. Android中使用【microlog4】进行日志存储
  6. Android实现TextView部分文本监听单击事
  7. Android实现微信右上角弹出的菜单
  8. Android底部导航 BottomNavigationBar(Goo
  9. Android(安卓)获取手机号码
  10. Android(安卓)frameworks添加资源后编译