• [转]Android自定义捕获Application全局异常


    本文转自:http://gundumw100.iteye.com/blog/1182104

    参考:
    http://bigcat.easymorse.com/?p=1152

    Java代码 复制代码 收藏代码
    1. package qianlong.qlmobile.ui;   
    2.   
    3. import java.io.File;   
    4. import java.io.FileOutputStream;   
    5. import java.io.FilenameFilter;   
    6. import java.io.PrintWriter;   
    7. import java.io.StringWriter;   
    8. import java.io.Writer;   
    9. import java.lang.Thread.UncaughtExceptionHandler;   
    10. import java.lang.reflect.Field;   
    11. import java.util.Arrays;   
    12. import java.util.Properties;   
    13. import java.util.TreeSet;   
    14.   
    15. import android.content.Context;   
    16. import android.content.pm.PackageInfo;   
    17. import android.content.pm.PackageManager;   
    18. import android.content.pm.PackageManager.NameNotFoundException;   
    19. import android.os.Build;   
    20. import android.os.Looper;   
    21. import android.text.format.Time;   
    22. import android.util.Log;   
    23. import android.view.Gravity;   
    24. import android.widget.Toast;   
    25.   
    26. public class CrashHandler implements UncaughtExceptionHandler {   
    27.   
    28.     /** Debug Log tag*/    
    29.     public static final String TAG = "CrashHandler";    
    30.     /** 是否开启日志输出,在Debug状态下开启,   
    31.     * 在Release状态下关闭以提示程序性能   
    32.     * */    
    33.     public static final boolean DEBUG = false;    
    34.     /** 系统默认的UncaughtException处理类 */    
    35.     private Thread.UncaughtExceptionHandler mDefaultHandler;    
    36.     /** CrashHandler实例 */    
    37.     private static CrashHandler INSTANCE;    
    38.     /** 程序的Context对象 */    
    39.     private Context mContext;    
    40.     /** 使用Properties来保存设备的信息和错误堆栈信息*/    
    41.     private Properties mDeviceCrashInfo = new Properties();    
    42.     private static final String VERSION_NAME = "versionName";    
    43.     private static final String VERSION_CODE = "versionCode";    
    44.     private static final String STACK_TRACE = "STACK_TRACE";    
    45.     /** 错误报告文件的扩展名 */    
    46.     private static final String CRASH_REPORTER_EXTENSION = ".cr";    
    47.        
    48.     /** 保证只有一个CrashHandler实例 */    
    49.     private CrashHandler() {}    
    50.        
    51.     /** 获取CrashHandler实例 ,单例模式*/    
    52.     public static CrashHandler getInstance() {    
    53.         if (INSTANCE == null) {    
    54.             INSTANCE = new CrashHandler();    
    55.         }    
    56.         return INSTANCE;    
    57.     }    
    58.        
    59.     /**   
    60.     * 初始化,注册Context对象,   
    61.     * 获取系统默认的UncaughtException处理器,   
    62.     * 设置该CrashHandler为程序的默认处理器   
    63.     * @param ctx   
    64.     */    
    65.     public void init(Context ctx) {    
    66.         mContext = ctx;    
    67.         mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();    
    68.         Thread.setDefaultUncaughtExceptionHandler(this);    
    69.     }    
    70.        
    71.     /**   
    72.     * 当UncaughtException发生时会转入该函数来处理   
    73.     */    
    74.     @Override    
    75.     public void uncaughtException(Thread thread, Throwable ex) {    
    76.         if (!handleException(ex) && mDefaultHandler != null) {    
    77.             //如果用户没有处理则让系统默认的异常处理器来处理    
    78.             mDefaultHandler.uncaughtException(thread, ex);    
    79.         } else {    
    80.             //Sleep一会后结束程序    
    81.             try {    
    82.                 Thread.sleep(5000);    
    83.             } catch (InterruptedException e) {    
    84.                 Log.e(TAG, "Error : ", e);    
    85.             }    
    86.             android.os.Process.killProcess(android.os.Process.myPid());    
    87.             System.exit(10);    
    88.         }    
    89.     }    
    90.        
    91.     /**   
    92.     * 自定义错误处理,收集错误信息   
    93.     * 发送错误报告等操作均在此完成.   
    94.     * 开发者可以根据自己的情况来自定义异常处理逻辑   
    95.     * @param ex   
    96.     * @return true:如果处理了该异常信息;否则返回false   
    97.     */    
    98.     private boolean handleException(Throwable ex) {    
    99.         if (ex == null) {    
    100.             Log.w(TAG, "handleException --- ex==null");    
    101.             return true;    
    102.         }    
    103.         final String msg = ex.getLocalizedMessage();    
    104.         if(msg == null) {   
    105.             return false;   
    106.         }   
    107.         //使用Toast来显示异常信息    
    108.         new Thread() {    
    109.             @Override    
    110.             public void run() {    
    111.                 Looper.prepare();    
    112.                 Toast toast = Toast.makeText(mContext, "程序出错,即将退出:\r\n" + msg,   
    113.                         Toast.LENGTH_LONG);   
    114.                 toast.setGravity(Gravity.CENTER, 00);   
    115.                 toast.show();   
    116. //              MsgPrompt.showMsg(mContext, "程序出错啦", msg+"\n点确认退出");   
    117.                 Looper.loop();    
    118.             }    
    119.         }.start();    
    120.         //收集设备信息    
    121.         collectCrashDeviceInfo(mContext);    
    122.         //保存错误报告文件    
    123.         saveCrashInfoToFile(ex);    
    124.         //发送错误报告到服务器    
    125.         //sendCrashReportsToServer(mContext);    
    126.         return true;    
    127.     }    
    128.        
    129.     /**   
    130.     * 在程序启动时候, 可以调用该函数来发送以前没有发送的报告   
    131.     */    
    132.     public void sendPreviousReportsToServer() {    
    133.         sendCrashReportsToServer(mContext);    
    134.     }    
    135.     /**   
    136.     * 把错误报告发送给服务器,包含新产生的和以前没发送的.   
    137.     * @param ctx   
    138.     */    
    139.     private void sendCrashReportsToServer(Context ctx) {    
    140.         String[] crFiles = getCrashReportFiles(ctx);    
    141.         if (crFiles != null && crFiles.length > 0) {    
    142.         TreeSet<String> sortedFiles = new TreeSet<String>();    
    143.         sortedFiles.addAll(Arrays.asList(crFiles));    
    144.         for (String fileName : sortedFiles) {    
    145.         File cr = new File(ctx.getFilesDir(), fileName);    
    146.         postReport(cr);    
    147.         cr.delete();// 删除已发送的报告    
    148.         }    
    149.         }    
    150.     }    
    151.     private void postReport(File file) {    
    152.         // TODO 发送错误报告到服务器    
    153.     }    
    154.        
    155.     /**   
    156.     * 获取错误报告文件名   
    157.     * @param ctx   
    158.     * @return   
    159.     */    
    160.     private String[] getCrashReportFiles(Context ctx) {    
    161.         File filesDir = ctx.getFilesDir();    
    162.         FilenameFilter filter = new FilenameFilter() {    
    163.             public boolean accept(File dir, String name) {    
    164.                 return name.endsWith(CRASH_REPORTER_EXTENSION);    
    165.             }    
    166.         };    
    167.         return filesDir.list(filter);    
    168.     }    
    169.        
    170.     /**   
    171.     * 保存错误信息到文件中   
    172.     * @param ex   
    173.     * @return   
    174.     */    
    175.     private String saveCrashInfoToFile(Throwable ex) {    
    176.         Writer info = new StringWriter();    
    177.         PrintWriter printWriter = new PrintWriter(info);    
    178.         ex.printStackTrace(printWriter);    
    179.         Throwable cause = ex.getCause();    
    180.         while (cause != null) {    
    181.             cause.printStackTrace(printWriter);    
    182.             cause = cause.getCause();    
    183.         }    
    184.         String result = info.toString();    
    185.         printWriter.close();    
    186.         mDeviceCrashInfo.put("EXEPTION", ex.getLocalizedMessage());   
    187.         mDeviceCrashInfo.put(STACK_TRACE, result);    
    188.         try {    
    189.             //long timestamp = System.currentTimeMillis();    
    190.             Time t = new Time("GMT+8");    
    191.             t.setToNow(); // 取得系统时间   
    192.             int date = t.year * 10000 + t.month * 100 + t.monthDay;   
    193.             int time = t.hour * 10000 + t.minute * 100 + t.second;   
    194.             String fileName = "crash-" + date + "-" + time + CRASH_REPORTER_EXTENSION;    
    195.             FileOutputStream trace = mContext.openFileOutput(fileName,    
    196.                     Context.MODE_PRIVATE);    
    197.             mDeviceCrashInfo.store(trace, "");    
    198.             trace.flush();    
    199.             trace.close();    
    200.             return fileName;    
    201.         } catch (Exception e) {    
    202.             Log.e(TAG, "an error occured while writing report file...", e);    
    203.         }    
    204.         return null;    
    205.     }    
    206.   
    207.     /**   
    208.     * 收集程序崩溃的设备信息   
    209.     *   
    210.     * @param ctx   
    211.     */    
    212.     public void collectCrashDeviceInfo(Context ctx) {    
    213.         try {    
    214.             PackageManager pm = ctx.getPackageManager();    
    215.             PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),    
    216.                     PackageManager.GET_ACTIVITIES);    
    217.             if (pi != null) {    
    218.                 mDeviceCrashInfo.put(VERSION_NAME,    
    219.                         pi.versionName == null ? "not set" : pi.versionName);    
    220.                 mDeviceCrashInfo.put(VERSION_CODE, ""+pi.versionCode);    
    221.             }    
    222.         } catch (NameNotFoundException e) {    
    223.             Log.e(TAG, "Error while collect package info", e);    
    224.         }    
    225.         //使用反射来收集设备信息.在Build类中包含各种设备信息,    
    226.         //例如: 系统版本号,设备生产商 等帮助调试程序的有用信息    
    227.         //具体信息请参考后面的截图    
    228.         Field[] fields = Build.class.getDeclaredFields();    
    229.         for (Field field : fields) {    
    230.             try {    
    231.                 field.setAccessible(true);    
    232.                 mDeviceCrashInfo.put(field.getName(), ""+field.get(null));    
    233.                 if (DEBUG) {    
    234.                     Log.d(TAG, field.getName() + " : " + field.get(null));    
    235.                 }    
    236.             } catch (Exception e) {    
    237.                 Log.e(TAG, "Error while collect crash info", e);    
    238.             }    
    239.         }    
    240.     }    
    241.   
    242. }  


    Java代码 复制代码 收藏代码
    1. 用法:   
    2. //全局数据存储   
    3. public class App extends Application {   
    4. private final static float HEAP_UTILIZATION = 0.75f;   
    5. private final static int MIN_HEAP_SIZE = 610241024 ;   
    6.    @Override  
    7.    public void onCreate() {   
    8.     super.onCreate();   
    9.            
    10.     // 异常处理,不需要处理时注释掉这两句即可!   
    11.     CrashHandler crashHandler = CrashHandler.getInstance();    
    12.     // 注册crashHandler    
    13.     crashHandler.init(getApplicationContext());    
    14.            
    15.     // 优化内存,以下非必须!   
    16.     VMRuntime.getRuntime().setTargetHeapUtilization(HEAP_UTILIZATION);   
    17.     VMRuntime.getRuntime().setMinimumHeapSize(MIN_HEAP_SIZE);    
    18.         //changeMetrics(this);//修改屏幕Density   
    19.         ......   
    20.    }   
    21. }  

    异常时写入文件,下面是data/data中生成的文件:


    Java代码 复制代码 收藏代码
    1. //   
    2. private static final boolean DebugFlag = false;   
    3. //修改屏幕Density   
    4. public static void changeMetrics(Context context) {   
    5.         DisplayMetrics curMetrics = context.getResources().getDisplayMetrics();   
    6.         if(!DebugFlag) {   
    7.             if (curMetrics.densityDpi == DisplayMetrics.DENSITY_HIGH) {   
    8.                 DisplayMetrics metrics = new DisplayMetrics();   
    9.                 metrics.scaledDensity = 1.0f;   
    10.                 metrics.density = 1.0f;   
    11.                 metrics.densityDpi = DisplayMetrics.DENSITY_MEDIUM;   
    12.                 metrics.xdpi = DisplayMetrics.DENSITY_MEDIUM;   
    13.                 metrics.ydpi = DisplayMetrics.DENSITY_MEDIUM;   
    14.                 metrics.heightPixels = curMetrics.heightPixels;   
    15.                 metrics.widthPixels = curMetrics.widthPixels;   
    16.                 context.getResources().getDisplayMetrics().setTo(metrics);   
    17.             }   
    18.         } else {   
    19.             DisplayMetrics metrics = new DisplayMetrics();   
    20.             metrics.scaledDensity = (float)(130/160.0);   
    21.             metrics.density = (float)(130/160.0);   
    22.             metrics.densityDpi = 130;   
    23.             metrics.xdpi = 130;   
    24.             metrics.ydpi = 130;   
    25.             metrics.heightPixels = curMetrics.heightPixels;   
    26.             metrics.widthPixels = curMetrics.widthPixels;   
    27.             context.getResources().getDisplayMetrics().setTo(metrics);   
    28.         }   
    29. }  

  • 相关阅读:
    Select 多个表并且相关联转置
    Excel输入公式后只显示公式却不计算如何解决?
    Excel 下来公式 内容却一样
    MySQL数据迁移到SQL Server
    C# Excel 中设置文字对齐方式、方向和换行
    Response.write()弹出窗口的问题!
    ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务
    Hibernate中连接数据库的配置
    ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
    帝国cms的tags页面url伪静态的设置
  • 原文地址:https://www.cnblogs.com/freeliver54/p/2223729.html
Copyright © 2020-2023  润新知