Android捕获异常时候的log信息

来源:互联网 发布:淘宝关键词排列顺序 编辑:程序博客网 时间:2024/05/20 10:14
我们在开发android应用的时候经常有这样一个情景:程序用着用着在某个地方崩溃了,每次的情况都不尽相同,这时候我们没有在电脑旁边,有电脑的时候去看代码的时候总是觉着哪儿都不可能出错。这时候我们就想如果我们能得到异常退出时候的log信息就好了。
这时候下面这一段代码就可能相当有用了:
package com.test.application;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
importandroid.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import com.duole.fm.utils.Constants;

public class CrashHandler implements UncaughtExceptionHandler{

    //系统默认的UncaughtException处理类
    privateThread.UncaughtExceptionHandler mDefaultHandler;
    // CrashHandler实例
    private staticCrashHandler instance;
    // 程序的Context对象
    private ContextmContext;
    // 用来存储设备信息和异常信息
    private Map infos = newHashMap();

    //用于格式化日期,作为日志文件名的一部分
    private DateFormatformatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");

   
    private CrashHandler(){
    }

   
    public staticCrashHandler getInstance() {
       if (instance == null)
           instance =new CrashHandler();
       return instance;
    }

   
    public void init(Contextcontext) {
       mContext = context;
       Log.e(Constants.TAG, "error : ");
       // 获取系统默认的UncaughtException处理器
       mDefaultHandler =Thread.getDefaultUncaughtExceptionHandler();
       // 设置该CrashHandler为程序的默认处理器
      Thread.setDefaultUncaughtExceptionHandler(this);
    }

   
    @Override
    public voiduncaughtException(Thread thread, Throwable ex) {
       if (!handleException(ex) &&mDefaultHandler != null) {
           //如果用户没有处理则让系统默认的异常处理器来处理
          mDefaultHandler.uncaughtException(thread, ex);
       } else {
           try{
              Thread.sleep(3000);
           } catch(InterruptedException e) {
              Log.e(Constants.TAG, "error :", e);
           }
           //退出程序
          android.os.Process.killProcess(android.os.Process.myPid());
          System.exit(1);
       }
    }

   
    private booleanhandleException(Throwable ex) {
       if (ex == null) {
           returnfalse;
       }
       // 收集设备参数信息
       collectDeviceInfo(mContext);

       // 使用Toast来显示异常信息
       new Thread() {
          @Override
           publicvoid run() {
              Looper.prepare();
              Toast.makeText(mContext,"很抱歉,程序出现异常,即将退出.", Toast.LENGTH_SHORT).show();
              Looper.loop();
           }
       }.start();
       // 保存日志文件
       try {
          saveCatchInfo2File(ex);
       } catch (Exception e) {
          e.printStackTrace();
       }
       return true;
    }

   
    public voidcollectDeviceInfo(Context ctx) {
       try {
          PackageManager pm = ctx.getPackageManager();
          PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),PackageManager.GET_ACTIVITIES);
           if (pi !=null) {
              String versionName =pi.versionName == null ? "null" : pi.versionName;
              String versionCode =pi.versionCode + "";
              infos.put("versionName",versionName);
              infos.put("versionCode",versionCode);
           }
       } catch (NameNotFoundException e) {
          Log.e(Constants.TAG, "an error occured when collect package info",e);
       }
       Field[] fields =Build.class.getDeclaredFields();
       for (Field field : fields) {
           try{
             field.setAccessible(true);
              infos.put(field.getName(),field.get(null).toString());
              Log.d(Constants.TAG,field.getName() + " : " + field.get(null));
           } catch(Exception e) {
              Log.e(Constants.TAG, "anerror occured when collect crash info", e);
           }
       }
    }

   
    private StringsaveCatchInfo2File(Throwable ex) {

       StringBuffer sb = new StringBuffer();
       for (Map.Entry entry : infos.entrySet()) {
           String key= entry.getKey();
           Stringvalue = entry.getValue();
          sb.append(key + "=" + value + "\n");
       }

       Writer writer = new StringWriter();
       PrintWriter printWriter = newPrintWriter(writer);
       ex.printStackTrace(printWriter);
       Throwable cause = ex.getCause();
       while (cause != null) {
          cause.printStackTrace(printWriter);
           cause =cause.getCause();
       }
       printWriter.close();
       String result = writer.toString();
       sb.append(result);
       try {
           longtimestamp = System.currentTimeMillis();
           Stringtime = formatter.format(new Date());
           StringfileName = "crash-" + time + "-" + timestamp + ".log";
           if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
              String path =Constants.SDPATH + "/crash/";
              File dir = newFile(path);
              if (!dir.exists()) {
                 dir.mkdirs();
              }
              FileOutputStream fos = newFileOutputStream(path + fileName);
             fos.write(sb.toString().getBytes());
              // 发送给开发人员
              sendCrashLog2PM(path +fileName);
              fos.close();
           }
           returnfileName;
       } catch (Exception e) {
          Log.e(Constants.TAG, "an error occured while writing file...",e);
       }
       return null;
    }

   
    private voidsendCrashLog2PM(String fileName) {
       if (!new File(fileName).exists()) {
          Toast.makeText(mContext, "日志文件不存在!",Toast.LENGTH_SHORT).show();
          return;
       }
       FileInputStream fis = null;
       BufferedReader reader = null;
       String s = null;
       try {
           fis = newFileInputStream(fileName);
           reader =new BufferedReader(new InputStreamReader(fis, "GBK"));
           while(true) {
              s = reader.readLine();
              if (s == null)
                 break;
              //由于目前尚未确定以何种方式发送,所以先打出log日志。
              Log.i("info",s.toString());
           }
       } catch (FileNotFoundException e) {
          e.printStackTrace();
       } catch (IOException e) {
          e.printStackTrace();
       } finally { // 关闭流
           try{
              reader.close();
              fis.close();
           } catch(IOException e) {
              e.printStackTrace();
           }
       }
    }
}

在Application里面加上下面这句:
        CrashHandler catchHandler =CrashHandler.getInstance();
       catchHandler.init(getApplicationContext());

这样就可以随时得到crash时候的log信息了
0 0