app运行中的crash崩溃异常日志收集

转载来源http://blog.csdn.net/qq_17387361/article/details/52688998

Android开发中,一个app在推广后。我们怎么才能知道这个app运行的如何,有没有出现崩溃等问题。这也就是app数据监控的一部分。下面的这个就是介绍关于crash日志的收集。这个就是核心代码:

  1. import java.io.File;  
  2. import java.io.FileOutputStream;  
  3. import java.io.PrintWriter;  
  4. import java.io.StringWriter;  
  5. import java.io.Writer;  
  6. import java.lang.Thread.UncaughtExceptionHandler;  
  7. import java.lang.reflect.Field;  
  8. import java.text.DateFormat;  
  9. import java.text.SimpleDateFormat;  
  10. import java.util.Date;  
  11. import java.util.HashMap;  
  12. import java.util.Map;  
  13.   
  14. import com.example.lianshou_test.MainActivity;  
  15. import com.example.lianshou_test.base.BaseActivity;  
  16.   
  17. import android.app.AlarmManager;  
  18. import android.app.PendingIntent;  
  19. import android.content.Context;  
  20. import android.content.Intent;  
  21. import android.content.pm.PackageInfo;  
  22. import android.content.pm.PackageManager;  
  23. import android.content.pm.PackageManager.NameNotFoundException;  
  24. import android.os.Build;  
  25. import android.os.Environment;  
  26. import android.os.Looper;  
  27. import android.util.Log;  
  28. import android.widget.Toast;  
  29.   
  30.   
  31. public class CrashHandler implements UncaughtExceptionHandler {  
  32.     public static final String TAG = "CrashHandler";  
  33.   
  34.     // 系统默认的UncaughtException处理类  
  35.     private Thread.UncaughtExceptionHandler mDefaultHandler;  
  36.     // CrashHandler实例  
  37.     private static CrashHandler INSTANCE = new CrashHandler();  
  38.     // 程序的Context对象  
  39.     private Context mContext;  
  40.     // 用来存储设备信息和异常信息  
  41.     private Map<String, String> infos = new HashMap<String, String>();  
  42.   
  43.     // 用于格式化日期,作为日志文件名的一部分  
  44.     private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");  
  45.   
  46.     /** 保证只有一个CrashHandler实例 */  
  47.     private CrashHandler() {  
  48.     }  
  49.   
  50.     /** 获取CrashHandler实例 ,单例模式 */  
  51.     public static CrashHandler getInstance() {  
  52.         return INSTANCE;  
  53.     }  
  54.   
  55.     /** 
  56.      * 初始化 
  57.      *  
  58.      * @param context 
  59.      */  
  60.     public void init(Context context) {  
  61.         mContext = context;  
  62.         // 获取系统默认的UncaughtException处理器  
  63.         mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  
  64.         // 设置该CrashHandler为程序的默认处理器  
  65.         Thread.setDefaultUncaughtExceptionHandler(this);  
  66.     }  
  67.   
  68.     /** 
  69.      * 当UncaughtException发生时会转入该函数来处理 
  70.      */  
  71.     @Override  
  72.     public void uncaughtException(Thread thread, Throwable ex) {  
  73.         if (ex != null && ex.getCause() != null  
  74.                 && ex.getCause().getMessage() != null  
  75.                 && ex.getCause().getMessage().contains("PDF file is corrupted")) {  
  76.             Log.e(TAG, "error : " + ex.getCause().getMessage());  
  77.             Looper.prepare();  
  78.             Toast.makeText(mContext, "该文件已经损坏,请检查!",  
  79.                     Toast.LENGTH_SHORT).show();  
  80.             Looper.loop();  
  81.             // 收集设备参数信息  
  82.             collectDeviceInfo(mContext);  
  83.             // 保存日志文件  
  84.             saveCrashInfo2File(ex);  
  85.         } else {  
  86.             if (!handleException(ex) && mDefaultHandler != null) {  
  87.                 // 如果用户没有处理则让系统默认的异常处理器来处理  
  88.                 mDefaultHandler.uncaughtException(thread, ex);  
  89.             } else {  
  90.                 try {  
  91.                     Thread.sleep(3000);  
  92.                 } catch (InterruptedException e) {  
  93.                     Log.e(TAG, "error : ", e);  
  94.                 }  
  95.                 Intent intent = new Intent(mContext.getApplicationContext(),  
  96.                         MainActivity.class);  
  97.                 PendingIntent restartIntent = PendingIntent.getActivity(  
  98.                         mContext.getApplicationContext(), 0, intent,  
  99.                         Intent.FLAG_ACTIVITY_NEW_TASK);  
  100.                 // 退出程序  
  101.                 AlarmManager mgr = (AlarmManager) mContext  
  102.                         .getSystemService(Context.ALARM_SERVICE);  
  103.                 mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,  
  104.                         restartIntent); // 1秒钟后重启应用  
  105.                 BaseActivity.getInstance().closeAll();  
  106.                 // 退出程序  
  107.                 android.os.Process.killProcess(android.os.Process.myPid());  
  108.                 System.exit(1);  
  109.             }  
  110.         }  
  111.     }  
  112.   
  113.     /** 
  114.      * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 
  115.      *  
  116.      * @param ex 
  117.      * @return true:如果处理了该异常信息;否则返回false. 
  118.      */  
  119.     private boolean handleException(Throwable ex) {  
  120.         if (ex == null) {  
  121.             return false;  
  122.         }  
  123.         // 使用Toast来显示异常信息  
  124.         new Thread() {  
  125.             @Override  
  126.             public void run() {  
  127.                 Looper.prepare();  
  128.                 Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.",  
  129.                         Toast.LENGTH_SHORT).show();  
  130.                 Looper.loop();  
  131.             }  
  132.         }.start();  
  133.         // 收集设备参数信息  
  134.         collectDeviceInfo(mContext);  
  135.         // 保存日志文件  
  136.         saveCrashInfo2File(ex);  
  137.         return true;  
  138.     }  
  139.   
  140.     /** 
  141.      * 收集设备参数信息 
  142.      *  
  143.      * @param ctx 
  144.      */  
  145.     public void collectDeviceInfo(Context ctx) {  
  146.         try {  
  147.             PackageManager pm = ctx.getPackageManager();  
  148.             PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),  
  149.                     PackageManager.GET_ACTIVITIES);  
  150.             if (pi != null) {  
  151.                 String versionName = pi.versionName == null ? "null"  
  152.                         : pi.versionName;  
  153.                 String versionCode = pi.versionCode + "";  
  154.                 infos.put("versionName", versionName);  
  155.                 infos.put("versionCode", versionCode);  
  156.             }  
  157.         } catch (NameNotFoundException e) {  
  158.             Log.e(TAG, "an error occured when collect package info", e);  
  159.         }  
  160.         Field[] fields = Build.class.getDeclaredFields();  
  161.         for (Field field : fields) {  
  162.             try {  
  163.                 field.setAccessible(true);  
  164.                 infos.put(field.getName(), field.get(null).toString());  
  165.                 Log.d(TAG, field.getName() + " : " + field.get(null));  
  166.             } catch (Exception e) {  
  167.                 Log.e(TAG, "an error occured when collect crash info", e);  
  168.             }  
  169.         }  
  170.     }  
  171.   
  172.     /** 
  173.      * 保存错误信息到文件中 
  174.      *  
  175.      * @param ex 
  176.      * @return 返回文件名称,便于将文件传送到服务器 
  177.      */  
  178.     private String saveCrashInfo2File(Throwable ex) {  
  179.   
  180.         StringBuffer sb = new StringBuffer();  
  181.         for (Map.Entry<String, String> entry : infos.entrySet()) {  
  182.             String key = entry.getKey();  
  183.             String value = entry.getValue();  
  184.             sb.append(key + "=" + value + "\n");  
  185.         }  
  186.   
  187.         Writer writer = new StringWriter();  
  188.         PrintWriter printWriter = new PrintWriter(writer);  
  189.         ex.printStackTrace(printWriter);  
  190.         Throwable cause = ex.getCause();  
  191.         while (cause != null) {  
  192.             cause.printStackTrace(printWriter);  
  193.             cause = cause.getCause();  
  194.         }  
  195.         printWriter.close();  
  196.         String result = writer.toString();  
  197.         sb.append(result);  
  198.         try {  
  199.             long timestamp = System.currentTimeMillis();  
  200.             String time = formatter.format(new Date());  
  201.             String fileName = "crash-" + time + "-" + timestamp + ".log";  
  202.             if (Environment.getExternalStorageState().equals(  
  203.                     Environment.MEDIA_MOUNTED)) {  
  204.                 String path = Environment  
  205.                         .getExternalStorageDirectory().getPath() + "/henry/crash" + "/";  
  206.                 File dir = new File(path);  
  207.                 if (!dir.exists()) {  
  208.                     dir.mkdirs();  
  209.                 }  
  210.                 FileOutputStream fos = new FileOutputStream(path + fileName);  
  211.                 fos.write(sb.toString().getBytes());  
  212.                 fos.close();  
  213.             }  
  214.             return fileName;  
  215.         } catch (Exception e) {  
  216.             Log.e(TAG, "an error occured while writing file...", e);  
  217.         }  
  218.         return null;  
  219.     }  
  220. }  


由于这个是在很多activity中会用到的。因此建议在appliction中进行初始化操作
  1. CrashHandler crashHandler = CrashHandler.getInstance();  
  2. crashHandler.init(getApplicationContext());  

最后。我们在测试时对app制造一点运行崩溃的错误。如图:

这样就可以了。最后部分就是将这个log文件上传到服务器就ok了(这个上传的过程大家就自己写写。很简单)。

注意一点就是记得在代码中写个定时器定时清理这些log日志文件。比如一周自动清理一次都可以。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过捕获全局异常来实现APP崩溃后的重新启动。具体实现步骤如下: 1. 创建一个自定义的Application类,并在onCreate()方法设置UncaughtExceptionHandler(全局异常处理器)。 ```java public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); } } ``` 2. 实现UncaughtExceptionHandler接口,重写uncaughtException()方法,在该方法处理异常信息并重启APP。 ```java public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { // 处理异常信息 Log.e("MyUncaughtExceptionHandler", "uncaughtException: " + e.getMessage()); // 重启APP Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); PendingIntent pendingIntent = PendingIntent.getActivity( getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1000, pendingIntent); // 结束进程 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } } ``` 在uncaughtException()方法,首先处理异常信息,然后通过AlarmManager和PendingIntent实现重启APP的功能,最后通过killProcess()和System.exit()方法结束进程。 3. 在AndroidManifest.xml文件注册自定义的Application类。 ```xml <application android:name=".MyApplication" ... </application> ``` 通过以上步骤,即可实现APP崩溃后的自动重启。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值