文档章节

在Android手机上保存Crash Log

 小牛仔
发布于 2015/01/23 16:27
字数 802
阅读 71
收藏 0
  1. 定义CrashLog文件:如果有存储器,则将文件保存在存储器下。否则保存在data目录下。存储器不一定是SD卡,也可能是mount出来的一块存储空间(不是内存)。比如,小米3就没有SD卡。

    public class CrashLog {
     private static Context mContext;
     public static final String DIR_FOR_APP = "myApp";
     public static final String FILE_NAME_FOR_CRASH__LOG = "crash.txt";
     
     public static void setContext( Context aContext ) {
      mContext = aContext.getApplicationContext();
     }
     
     public static void writeLog(String log) throws Exception {
      File dir = createFileDir(DIR_FOR_APP);
      File file = new File(dir.getPath(), FILE_NAME_FOR_CRASH__LOG);
      if(!file.exists()){
       file.createNewFile();
      }
      StringBuffer orgStr = new StringBuffer();
      FileReader fr = new FileReader(file);
      int ch = 0;
      while((ch = fr.read()) != -1) {  
       orgStr.append((char)ch);
      }
      fr.close();
      
      Calendar c = Calendar.getInstance();
      String time = String.format("%2d:", c.get(Calendar.HOUR))+
      String.format("%2d:", c.get(Calendar.MINUTE))+
      String.format("%2d", c.get(Calendar.SECOND))+" ";
      String str = orgStr.toString() + "\r\n" + time + log + "\r\n";
      FileWriter fw = new FileWriter(file);
      fw.write(str);
      fw.close();
     }
     
     public static void clearLog(){
      String dirPath = getDirPath(DIR_FOR_APP);
      if( dirPath != null ) {
       File file = new File(FILE_NAME_FOR_CRASH__LOG);
       if(file.exists()){
        file.delete();
       }
      }
     }
     
      public static String getDirPath(String dirName){
       String filePath = null;
       String state = Environment.getExternalStorageState();
       if (state.equals(Environment.MEDIA_MOUNTED)) {
        // 如果有存储器,则返回存储器的路径
        filePath = Environment.getExternalStorageDirectory()
          + File.separator + dirName;
       } else {// 否则返回data目录的路径
        filePath = mContext.getCacheDir().getPath() + File.separator
          + dirName;
       }
       return filePath;
      }
         
      public static File createFileDir(String dirName) {
       String filePath = getDirPath(dirName);
       if( filePath == null ) {
        return null;
       }
       File destDir = new File(filePath);
       if (!destDir.exists()) {
        destDir.mkdirs();
       }
       return destDir;
      }
    }

    2. 定义CrashHandler异常捕获类:当程序抛出异常后,由CrashHandler先捕获。将异常堆栈信息和手机系统信息打印到手机制定位置的log文件后,退出。

public class CrashHandler implements UncaughtExceptionHandler {
    private Context mContext;
    private static CrashHandler mInstance = null;
    // 系统默认的异常处理(默认情况下,系统会终止当前的异常程序)
    private UncaughtExceptionHandler mDefaultCrashHandler;
 
    private CrashHandler(Context c) {
        // 获取系统默认的异常处理器
        mDefaultCrashHandler = Thread
                .getDefaultUncaughtExceptionHandler();
        // 将当前实例设为系统默认的异常处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
        // 获取Context,方便内部使用
        mContext = c.getApplicationContext();
    }
    public synchronized static CrashHandler create(Context cxt) {
        if (mInstance == null) {
            mInstance = new CrashHandler(cxt);
        }
        return mInstance;
    }
/**
 * 当UncaughtException发生时会回调该函数来处理
 */
 @Override
 public void uncaughtException(Thread thread, Throwable ex) {
      // TODO Auto-generated method stub
      StringBuffer logInfo = new StringBuffer();
      logInfo.append("Exception: ");
      logInfo.append(ex.getMessage());
      logInfo.append("\r\n");
      logInfo.append(getStackMsg(ex));
      logInfo.append("Phone informations:");
      logInfo.append("\r\n");
      try {
           logInfo.append(getPhoneInfo());
            // 导出异常信息到存储器中
           CrashLog.writeLog(logInfo.toString());
      } catch (Exception e) {
       //忽略异常
      } finally {
       // 如果系统提供了默认的异常处理器,则交给系统去结束程序,
       if (mDefaultCrashHandler != null) {
            mDefaultCrashHandler.uncaughtException(thread, ex);
       } else {
            MyApplication.getInstance().exit();
       }
    }
 }
   
 private static String getStackMsg(Throwable e) {  
      StringBuffer sb = new StringBuffer();  
      StackTraceElement[] stackArray = e.getStackTrace();  
      for (int i = 0; i < stackArray.length; i++) {  
          StackTraceElement element = stackArray[i];  
          sb.append(element.toString() + "\r\n");
      }  
      return sb.toString();
 } 
 private String getPhoneInfo()
            throws NameNotFoundException {
       StringBuffer info = new StringBuffer();
  
        // 应用的版本号
        PackageManager pm = mContext.getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
                PackageManager.GET_ACTIVITIES);
        info.append("App Version Name: ");
        info.append(pi.versionName);
        info.append("\r\n");
        // android版本号
        info.append("OS Version: ");
        info.append(Build.VERSION.RELEASE);
        info.append("_");
        info.append(Build.VERSION.SDK_INT);
        info.append("\r\n");
        // 手机制造商
        info.append("Vendor: ");
        info.append(Build.MANUFACTURER);
        info.append("\r\n");
        // 手机型号
        info.append("Model: ");
        info.append(Build.MODEL);
        info.append("\r\n");
        // cpu架构
        info.append("CPU ABI: ");
        info.append(Build.CPU_ABI);
        info.append("\r\n");
        
        return info.toString();
    }
}

3. 自定义Application类,初始化CrashLog和CrashHandler,并提供完全退出应用的接口exit()。

public class MyApplication extends Application{
 // 单例模式
 private static MyApplication mAppInstance;
 // Activity容器
 private List<Activity> mActivityList = new LinkedList<Activity>();
 
 public MyApplication(){ 
 }
 
 public static MyApplication getInstance() {
  if( mAppInstance == null ) {
   mAppInstance = new MyApplication();
  }
  return mAppInstance;
 }
 
 // 每新建一个Activity,都要添加到容器中
 public void addActivity(Activity a){
  mActivityList.add(a);
 }
 
 // 遍历容器中所有Activity并finish
 public void exit(){
     for (Activity activity : mActivityList) {  
         activity.finish();  
     }  
     System.exit(0);  
  }
 @Override
 public void onCreate() {
     super.onCreate();
     CrashLog.setContext(this);
     CrashHandler.create(this);
 }
}

© 著作权归作者所有

粉丝 0
博文 34
码字总数 35169
作品 0
成都
私信 提问
android测试之monkey

本文转载自http://www.testwo.com/blog/6188 感谢本文的作者; 一、Monkey test简介 Android的SDK 里面,Monkey的tools是一个命令行工具,当连接Android设备时,只要在命令行里输入相应命令就...

yangiris
2018/06/26
0
0
抓取Android APP崩溃和无响应日志的小工具

前言 在Android APP的测试过程中经常遇到crash和anr,开发人员习惯通过eclipse或者eclipse的ddms组件进行捕抓日志,测试人员常通过在dos窗口下adb命令的方式来抓取日志。前者的缺点是启动时非...

shzwork
03/26
8
0
为什么不能往Android的Application对象里存储数据

在一个App里面总有一些数据需要在多个地方用到。这些数据可能是一个 session token,一次费时计算的结果等。通常为了避免activity之间传递对象的开销 ,这些数据一般都会保存到持久化存储里面...

拉偶有所依
2015/04/08
1K
10
Android开发在路上:少去踩坑,多走捷径

近一朋友提了几个Android问题让我帮忙写个小分享,我觉得对新人还是挺有帮助的,所以有了这个小分享。 1.目前, Android APP开发完成后,通常需要在哪些机型上进行测试? 2.目前, 开发Andro...

zplswf
2014/08/07
300
2
Android开发在路上:少去踩坑,多走捷径【转】

作者:gzjay,腾讯MIG无线产品部 高级工程师 最近一朋友提了几个Android问题让我帮忙写个小分享,我觉得对新人还是挺有帮助的,所以有了这个小分享。 1.目前, Android APP开发完成后,通常需...

火蚁
2014/07/20
678
7

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis Plus删除

/** @author beth @data 2019-10-17 00:30 */ @RunWith(SpringRunner.class) @SpringBootTest public class DeleteTest { @Autowired private UserInfoMapper userInfoMapper; /** 根据id删除......

一个yuanbeth
今天
4
0
总结

一、设计模式 简单工厂:一个简单而且比较杂的工厂,可以创建任何对象给你 复杂工厂:先创建一种基础类型的工厂接口,然后各自集成实现这个接口,但是每个工厂都是这个基础类的扩展分类,spr...

BobwithB
今天
5
0
java内存模型

前言 Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模...

ls_cherish
今天
4
0
友元函数强制转换

友元函数强制转换 p522

天王盖地虎626
昨天
5
0
js中实现页面跳转(返回前一页、后一页)

本文转载于:专业的前端网站➸js中实现页面跳转(返回前一页、后一页) 一:JS 重载页面,本地刷新,返回上一页 复制代码代码如下: <a href="javascript:history.go(-1)">返回上一页</a> <a h...

前端老手
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部