• Android 捕捉app系统中未处理的异常


    一:为什么要处理?

    其实我们都知道,在开发过程中,自己的app系统或许有许多隐藏的异常,自己没有捕捉到,那么关于异常的捕捉,这是相当重要的,如果系统发生崩溃,那么至少也可以让系统挂在系统之内,不会发现什么系统直接退了,或者是卡死,这样做,能够使得用户体验效果更加,自己也可以发现用户到底出现什么异常,便于自己以后好处理这个问题,优化处理自己的系统。

    二:如何解决

    在Android 开发中,自身其实带有一个系统默认的异常处理接口,UncaughtExceptionHandler,该接口呢,能够很好的处理程序中发生的异常,所以,往往开发者都喜欢使用它,而且它也是一个非常简单好用的东西。

    三:具体实现

    (1)实现UncaughtExceptionHandler接口的类

    package com.x1.tools;  
      
    import java.lang.Thread.UncaughtExceptionHandler;  
      
    import android.app.ActivityManager;  
    import android.content.ComponentName;  
    import android.content.Context;  
    import android.os.Looper;  
    import android.util.Log;  
      
    import com.x1.dao.SubmitConfigBugs;  
    import com.x1.ui.R;  
      
    /** 
     * 未捕获异常捕捉类 
     *  
     * @author zengtao 2015年5月6日 
     * 
     * 
     */  
    public class CrashHandlers implements UncaughtExceptionHandler {  
      
        public static final String TGA = "CrashHandlers";  
      
        // 系统默认的UncaughtException处理类  
        private Thread.UncaughtExceptionHandler mDefaultHandler;  
      
        // CrashHandler实例  
        private static CrashHandlers instance;  
        // 程序的Context对象  
        private Context mContext;  
      
        private GetPhoneInfo phone;  
      
        /** 保证只有一个CrashHandler实例 */  
        private CrashHandlers() {  
        }  
      
        /** 获取CrashHandler实例 ,单例模式 */  
        public synchronized static CrashHandlers getInstance() {  
            if (instance == null) {  
                instance = new CrashHandlers();  
            }  
            return instance;  
        }  
      
        /** 
         * 初始化 
         *  
         * @param context 
         */  
        public void init(Context context) {  
            mContext = context;  
            // 获取系统默认的UncaughtException处理器  
            mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  
            // 设置该CrashHandler为程序的默认处理器  
            Thread.setDefaultUncaughtExceptionHandler(this);  
            phone = new GetPhoneInfo(context);  
        }  
      
        /** 
         * 当UncaughtException发生时会转入该函数来处理 
         */  
        @Override  
        public void uncaughtException(Thread thread, Throwable ex) {  
            if (!handleException(thread, ex) && mDefaultHandler != null) {  
                // 如果用户没有处理则让系统默认的异常处理器来处理  
                mDefaultHandler.uncaughtException(thread, ex);  
            } else {  
                try {  
                    Thread.sleep(3000);  
                } catch (InterruptedException e) {  
                    Log.e(TGA, e.toString());  
                }  
                // 退出程序  
                android.os.Process.killProcess(android.os.Process.myPid());  
                System.exit(1);  
            }  
        }  
      
        /** 
         * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 
         *  
         * @param ex 
         * @return true:如果处理了该异常信息;否则返回false. 
         */  
        private boolean handleException(Thread thread, Throwable ex) {  
            if (ex == null) {  
                return false;  
            }  
            // 使用Toast来显示异常信息  
            new Thread() {  
                @Override  
                public void run() {  
                    Looper.prepare();  
                    ShowToast.show(mContext, "喵,很抱歉,程序出现异常,即将退出!",  
                            R.drawable.error_icon);  
                    Looper.loop();  
                }  
            }.start();  
            // 把异常信息和设备信息上传到服务器  
            subMitThreadAndDeviceInfo(mContext, thread, ex);  
            return true;  
        }  
      
        // 提交信息到服务器  
        public void subMitThreadAndDeviceInfo(Context ctx, Thread thread,  
                Throwable ex) {  
            // 当前用户的账号  
            String Account = null;  
            if (Config.getCachedAccount(ctx) != null) {  
                Account = Config.getCachedAccount(ctx);  
            } else {  
                Account = "当前无用户登录";  
            }  
            // 手机设备的信息  
            String PhoneModel = phone.PhoneModel;  
            String PhoneVersion = phone.PhoneVersion;  
            String PhoneResolution = phone.PhoneResolution;  
            String ZcmVersion = phone.ZcmVersion;  
            String AvailableRom = phone.AvailableRom;  
            // 获取当前显示在界面上的Activity的路径加类名  
            ActivityManager am = (ActivityManager) ctx  
                    .getSystemService(Context.ACTIVITY_SERVICE);  
            ComponentName cn = am.getRunningTasks(1).get(0).topActivity;  
            // 异常信息加异常所在类的绝对路径  
            final String content = "thread: " + thread + " , name: "  
                    + thread.getName() + ", id: " + thread.getId()  
                    + ", exception: " + ex + ", " + cn.getClassName();  
      
            // 执行接口,把异常信息提交到服务器  
            new SubmitConfigBugs(0, ctx, Account, PhoneModel, PhoneVersion,  
                    PhoneResolution, ZcmVersion, AvailableRom, content,  
                    new SubmitConfigBugs.SuccessCallback() {  
                        @Override  
                        public void onSuccess() {  
                            Log.e(TGA, content + "
    错误信息提交成功");  
                        }  
                    }, new SubmitConfigBugs.FailCallback() {  
      
                        @Override  
                        public void onFail() {  
                            Log.e(TGA, content + "
    错误信息提交失败");  
                        }  
                    });  
        }  
      
    }
    

    (2)实体类:手机信息

    package com.x1.tools;  
      
    import android.content.Context;  
    import android.content.pm.PackageInfo;  
    import android.content.pm.PackageManager;  
    import android.os.Environment;  
    import android.os.StatFs;  
    import android.text.TextUtils;  
    import android.view.Display;  
    import android.view.WindowManager;  
      
    /** 
     * 获取当前手机的设备信息和当前软件的版本 
     *  
     * @author zengtao 2015年5月6日 
     * 
     * 
     */  
    public class GetPhoneInfo {  
        private Context context;  
        public String PhoneModel;  
        public String PhoneVersion;  
        public String PhoneResolution;  
        public String ZcmVersion;  
        public String AvailableRom;  
      
        public GetPhoneInfo(Context context) {  
            this.context = context;  
            PhoneModel = android.os.Build.MODEL;  
            PhoneVersion = android.os.Build.VERSION.RELEASE;  
            PhoneResolution = getDisplayWAndH();  
            ZcmVersion = getAppVersionName(this.context);  
            AvailableRom = "ROM剩余存储空间: " + getAvailableInternalMemorySize() + "MB"  
                    + ",内置SDCard剩余存储空间: " + getAvailableExternalMemorySize() + "MB";  
        }  
      
        // 获取当前版本号  
        private String getAppVersionName(Context context) {  
            String versionName = "";  
            try {  
                PackageManager packageManager = context.getPackageManager();  
                PackageInfo packageInfo = packageManager.getPackageInfo(  
                        "com.x1.ui", 0);  
                versionName = packageInfo.versionName;  
                if (TextUtils.isEmpty(versionName)) {  
                    return "";  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return versionName;  
        }  
      
        // 获取屏幕分辨率  
        @SuppressWarnings("deprecation")  
        private String getDisplayWAndH() {  
            WindowManager wm = (WindowManager) context  
                    .getSystemService(Context.WINDOW_SERVICE);  
            Display display = wm.getDefaultDisplay();  
            String string = "屏幕分辨率: " + display.getWidth() + "x"  
                    + display.getHeight();  
            return string;  
        }  
      
        /** 
         *  
         * @return ROM存储路径 
         */  
        private String getInternalMemoryPath() {  
            return Environment.getDataDirectory().getPath();  
        }  
      
        /** 
         *  
         * @return 内置sd卡路径 
         */  
        private String getExternalMemoryPath() {  
            return Environment.getExternalStorageDirectory().getPath();  
        }  
      
        /** 
         *  
         * @param path 
         *            文件路径 
         * @return 文件路径的StatFs对象 
         * @throws Exception 
         *             路径为空或非法异常抛出 
         */  
        private StatFs getStatFs(String path) {  
            try {  
                return new StatFs(path);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return null;  
        }  
      
        /** 
         *  
         * @param stat 
         *            文件StatFs对象 
         * @return 剩余存储空间的MB数 
         *  
         */  
        @SuppressWarnings("deprecation")  
        private float calculateSizeInMB(StatFs stat) {  
            if (stat != null)  
                return stat.getAvailableBlocks()  
                        * (stat.getBlockSize() / (1024f * 1024f));  
            return 0.0f;  
        }  
      
        /** 
         *  
         * @return ROM剩余存储空间的MB数 
         */  
        private float getAvailableInternalMemorySize() {  
      
            String path = getInternalMemoryPath();// 获取数据目录  
            StatFs stat = getStatFs(path);  
            return calculateSizeInMB(stat);  
        }  
      
        /** 
         *  
         * @return 内置SDCard剩余存储空间MB数 
         */  
        private float getAvailableExternalMemorySize() {  
      
            String path = getExternalMemoryPath();// 获取数据目录  
            StatFs stat = getStatFs(path);  
            return calculateSizeInMB(stat);  
      
        }  
    } 
    

      

    1. package com.x1.tools;  
    2.   
    3. import java.lang.Thread.UncaughtExceptionHandler;  
    4.   
    5. import android.app.ActivityManager;  
    6. import android.content.ComponentName;  
    7. import android.content.Context;  
    8. import android.os.Looper;  
    9. import android.util.Log;  
    10.   
    11. import com.x1.dao.SubmitConfigBugs;  
    12. import com.x1.ui.R;  
    13.   
    14. /** 
    15.  * 未捕获异常捕捉类 
    16.  *  
    17.  * @author zengtao 2015年5月6日 
    18.  * 
    19.  * 
    20.  */  
    21. public class CrashHandlers implements UncaughtExceptionHandler {  
    22.   
    23.     public static final String TGA = "CrashHandlers";  
    24.   
    25.     // 系统默认的UncaughtException处理类  
    26.     private Thread.UncaughtExceptionHandler mDefaultHandler;  
    27.   
    28.     // CrashHandler实例  
    29.     private static CrashHandlers instance;  
    30.     // 程序的Context对象  
    31.     private Context mContext;  
    32.   
    33.     private GetPhoneInfo phone;  
    34.   
    35.     /** 保证只有一个CrashHandler实例 */  
    36.     private CrashHandlers() {  
    37.     }  
    38.   
    39.     /** 获取CrashHandler实例 ,单例模式 */  
    40.     public synchronized static CrashHandlers getInstance() {  
    41.         if (instance == null) {  
    42.             instance = new CrashHandlers();  
    43.         }  
    44.         return instance;  
    45.     }  
    46.   
    47.     /** 
    48.      * 初始化 
    49.      *  
    50.      * @param context 
    51.      */  
    52.     public void init(Context context) {  
    53.         mContext = context;  
    54.         // 获取系统默认的UncaughtException处理器  
    55.         mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  
    56.         // 设置该CrashHandler为程序的默认处理器  
    57.         Thread.setDefaultUncaughtExceptionHandler(this);  
    58.         phone = new GetPhoneInfo(context);  
    59.     }  
    60.   
    61.     /** 
    62.      * 当UncaughtException发生时会转入该函数来处理 
    63.      */  
    64.     @Override  
    65.     public void uncaughtException(Thread thread, Throwable ex) {  
    66.         if (!handleException(thread, ex) && mDefaultHandler != null) {  
    67.             // 如果用户没有处理则让系统默认的异常处理器来处理  
    68.             mDefaultHandler.uncaughtException(thread, ex);  
    69.         } else {  
    70.             try {  
    71.                 Thread.sleep(3000);  
    72.             } catch (InterruptedException e) {  
    73.                 Log.e(TGA, e.toString());  
    74.             }  
    75.             // 退出程序  
    76.             android.os.Process.killProcess(android.os.Process.myPid());  
    77.             System.exit(1);  
    78.         }  
    79.     }  
    80.   
    81.     /** 
    82.      * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 
    83.      *  
    84.      * @param ex 
    85.      * @return true:如果处理了该异常信息;否则返回false. 
    86.      */  
    87.     private boolean handleException(Thread thread, Throwable ex) {  
    88.         if (ex == null) {  
    89.             return false;  
    90.         }  
    91.         // 使用Toast来显示异常信息  
    92.         new Thread() {  
    93.             @Override  
    94.             public void run() {  
    95.                 Looper.prepare();  
    96.                 ShowToast.show(mContext, "喵,很抱歉,程序出现异常,即将退出!",  
    97.                         R.drawable.error_icon);  
    98.                 Looper.loop();  
    99.             }  
    100.         }.start();  
    101.         // 把异常信息和设备信息上传到服务器  
    102.         subMitThreadAndDeviceInfo(mContext, thread, ex);  
    103.         return true;  
    104.     }  
    105.   
    106.     // 提交信息到服务器  
    107.     public void subMitThreadAndDeviceInfo(Context ctx, Thread thread,  
    108.             Throwable ex) {  
    109.         // 当前用户的账号  
    110.         String Account = null;  
    111.         if (Config.getCachedAccount(ctx) != null) {  
    112.             Account = Config.getCachedAccount(ctx);  
    113.         } else {  
    114.             Account = "当前无用户登录";  
    115.         }  
    116.         // 手机设备的信息  
    117.         String PhoneModel = phone.PhoneModel;  
    118.         String PhoneVersion = phone.PhoneVersion;  
    119.         String PhoneResolution = phone.PhoneResolution;  
    120.         String ZcmVersion = phone.ZcmVersion;  
    121.         String AvailableRom = phone.AvailableRom;  
    122.         // 获取当前显示在界面上的Activity的路径加类名  
    123.         ActivityManager am = (ActivityManager) ctx  
    124.                 .getSystemService(Context.ACTIVITY_SERVICE);  
    125.         ComponentName cn = am.getRunningTasks(1).get(0).topActivity;  
    126.         // 异常信息加异常所在类的绝对路径  
    127.         final String content = "thread: " + thread + " , name: "  
    128.                 + thread.getName() + ", id: " + thread.getId()  
    129.                 + ", exception: " + ex + ", " + cn.getClassName();  
    130.   
    131.         // 执行接口,把异常信息提交到服务器  
    132.         new SubmitConfigBugs(0, ctx, Account, PhoneModel, PhoneVersion,  
    133.                 PhoneResolution, ZcmVersion, AvailableRom, content,  
    134.                 new SubmitConfigBugs.SuccessCallback() {  
    135.                     @Override  
    136.                     public void onSuccess() {  
    137.                         Log.e(TGA, content + " 错误信息提交成功");  
    138.                     }  
    139.                 }, new SubmitConfigBugs.FailCallback() {  
    140.   
    141.                     @Override  
    142.                     public void onFail() {  
    143.                         Log.e(TGA, content + " 错误信息提交失败");  
    144.                     }  
    145.                 });  
    146.     }  
    147.   
  • 相关阅读:
    组合模式
    C#+ArcEngine中com对象的释放问题
    备忘录模式
    C#中的DataSet添加DataTable问题
    jenkins从节点
    jenkins Publish over SSH
    jenkins凭据
    jenkins maven项目
    jenkins部署-docker
    zabbix api
  • 原文地址:https://www.cnblogs.com/foxy/p/7815753.html
Copyright © 2020-2023  润新知