我们写程序的时候都希望能写出一个没有任何Bug的程序,期望在任何情况下都不会发生程序崩溃。不过理想是丰满的,现实是骨感的。没有一个程序员能保证自己写的程序绝对不会出现异常崩溃。特别是针对用户数达到几十万几百万的程序,当你用户数达到一定数量级后,就算你的程序出现个别异常崩溃情况也不用惊讶。

  既然我们写的程序都有可能发生异常崩溃,如果是还没发布的程序,我们可以通过测试抓取Log来分析。不过针对已经发布的程序,我们没法重现现象,所以让用户反馈程序异常信息就很重要。下面我们说说如何收集程序运行过程的异常信息。

(PS:新建的QQ群,有兴趣可以加入一起讨论:Android群:322599434)

1、Android异常捕获接口

//当线程因未捕获的异常而突然终止时,调用处理程序的接口
static interface UncaughtExceptionHandler

2、设置线程捕获异常

  从上面的接口我们可以看到,这个接口是针对线程来说,也就是说我们如果需要监控某个线程运行情况,只要把这个接口实现了,然后把监控方法设置到具体的线程里面即可。一般来说,我们最需要监控的就是我们的UI线程也就是主线程。

//设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。
static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

3、UncaughtExceptionHandler 实例


//Edited by mythou
//http://www.cnblogs.com/mythou/
public class MythouCrashHandler implements UncaughtExceptionHandler
{
private static final String TAG = "MythouCrashHandler---->";
private UncaughtExceptionHandler defaultUEH;

  //构造函数,获取默认的处理方法
public MythouCrashHandler()
{
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}

  //这个接口必须重写,用来处理我们的异常信息
@Override
public void uncaughtException(Thread thread, Throwable ex)
{
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
     //获取跟踪的栈信息,除了系统栈信息,还把手机型号、系统版本、编译版本的唯一标示
StackTraceElement[] trace = ex.getStackTrace();
StackTraceElement[] trace2 = new StackTraceElement[trace.length+];
System.arraycopy(trace, , trace2, , trace.length);
trace2[trace.length+] = new StackTraceElement("Android", "MODEL", android.os.Build.MODEL, -);
trace2[trace.length+] = new StackTraceElement("Android", "VERSION", android.os.Build.VERSION.RELEASE, -);
trace2[trace.length+] = new StackTraceElement("Android", "FINGERPRINT", android.os.Build.FINGERPRINT, -);
    //追加信息,因为后面会回调默认的处理方法
ex.setStackTrace(trace2);
ex.printStackTrace(printWriter);
     //把上面获取的堆栈信息转为字符串,打印出来
String stacktrace = result.toString();
printWriter.close();
Log.e(TAG, stacktrace); //这里把刚才异常堆栈信息写入SD卡的Log日志里面
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
String sdcardPath = Environment.getExternalStorageDirectory().getPath();
writeLog(stacktrace, sdcardPath + "/mythou");
} defaultUEH.uncaughtException(thread, ex);
}

  //写入Log信息的方法,写入到SD卡里面
private void writeLog(String log, String name)
{
CharSequence timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis());
String filename = name + "_" + timestamp + ".log"; try
{
FileOutputStream stream = new FileOutputStream(filename);
OutputStreamWriter output = new OutputStreamWriter(stream);
BufferedWriter bw = new BufferedWriter(output);
       //写入相关Log到文件
bw.write(log);
bw.newLine();
bw.close();
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

  上面就是实现了获取处理跟踪信息的方法,上面的方法是参照VLC的异常处理机制编写的。做了一些简单修改。不过上面只是获取了异常信息,如果程序安装到用户机器上,我们没法获取到这些信息,总不能让用户把机器拿过来给你,然后你把Log拷贝出来吧。(这个我以前做嵌入式的时候到试过,让客户把机器拿过来,拷贝里面的Log,那时候做的机器无法联网。现在想起来都纠结,O(∩_∩)O哈哈~) 为了不再纠结,我们需要一个可以把Log发送到我们服务器的功能,下面是把一个服务信息发送到我们指定服务器功能。

3、通过网络发送Log

//Edited by mythou
//http://www.cnblogs.com/mythou/
   public class SendCrashLog extends AsyncTask<String, String, Boolean>
{
public SendCrashLog() { } @Override
protected Boolean doInBackground(String... params)
{
if (params[].length() == )
return false;
HttpClient httpClient = new DefaultHttpClient();
       //你的服务器,这里只是举个例子。把异常信息当作http请求发送到服务器
HttpPost httpPost = new HttpPost("http://www.mythou/getlog.php");
       //这里把相关的异常信息转为http post请求的数据参数
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("model", params[]));
nameValuePairs.add(new BasicNameValuePair("device", params[]));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
         //发送相关请求信息
httpClient.execute(httpPost);
} catch (ClientProtocolException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
Log.d(TAG, "Device model sent.");
return true;
} @Override
protected void onPostExecute(Boolean result) { }
}

  上面就是我上一篇文章讲的异步任务的使用,我们在异步任务里面编写了一个发送http请求的服务,用来把相关的异常信息发送到我们指定的服务器上面。这个需要你的服务器解析发送的http请求,这个难度不大,一般做个web的人都知道如何做。在上面的异常处理里面再调用这里的发送方法:

//Edited by mythou
//http://www.cnblogs.com/mythou/
SendCrashLogsendLog = new SendCrashLog();
//刚才的异常信息字符串
sendLog .execute(stacktrace);

通过上面的方法就可以把异常信息发送到指定的服务器,也就可以跟踪客户使用软件的情况,方便我们修改程序的问题。当然这个信息收集一般都隐私和后台流量问题,这个需要在程序里面做点提示,免得背上流氓软件的骂名。

Edited by mythou

原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3194400.html 

Android 收集已发布程序的崩溃信息的更多相关文章

  1. 【转】Android 收集已发布程序的崩溃信息

    我们写程序的时候都希望能写出一个没有任何Bug的程序,期望在任何情况下都不会发生程序崩溃.不过理想是丰满的,现实是骨感的.没有一个程序员能保证自己写的程序绝对不会出现异常崩溃.特别是针对用户数达到几十 ...

  2. Android将应用程序的崩溃信息如何保存到本地文件,并上传服务器

    导语:最近实在是太忙了,没有怎么更新公众号,也没有怎么认真去写一些内容,在这里先给关注我的朋友说一声抱歉,可能在接下来的一段时间,还是很忙,但是我会争取抽空多分享一下技术文章,给大家看,共同进步,也希 ...

  3. Android中获取应用程序(包)的信息----PackageManager

    本节内容是如何获取Android系统中应用程序的信息,主要包括packagename.label.icon.占用大小等.具体分为两个 部分,计划如下:   第一部分: 获取应用程序的packagena ...

  4. Android中获取应用程序(包)的信息-----PackageManager的使用(一)

    本节内容是如何获取Android系统中应用程序的信息,主要包括packagename.label.icon.占用大小等.具体分为两个 部分,计划如下:  第一部分: 获取应用程序的packagenam ...

  5. Android中获取应用程序(包)的信息-----PackageManager的使用

    本节内容是如何获取Android系统中应用程序的信息,主要包括packagename.label.icon.占用大小等.具体分为两个 部分,计划如下: 第一部分: 获取应用程序的packagename ...

  6. 【转】Android中获取应用程序(包)的信息-----PackageManager的使用(一)

    转载请注明出处:http://blog.csdn.net/qinjuning       本节内容是如何获取Android系统中应用程序的信息,主要包括packagename.label.icon.占 ...

  7. Android中获取应用程序(包)的大小-----PackageManager的使用(二)

    通过第一部分<<Android中获取应用程序(包)的信息-----PackageManager的使用(一)>>的介绍,对PackageManager以及 AndroidMani ...

  8. 如何实现已发布app的自动更新

    要实现app的自动更新,做两件事情就可以搞定 1.获取当前手机中的app版本号 我们可以通过查询mainbundle中的获取CFBundleVersion NSDictionary *infoDict ...

  9. 构建一个Gods Eye Android应用程序:第1部分 – 收集已安装的Android应用程序

    首先问候一下我的黑客伙伴们,在之前的Introduction to Amunet 教程中,我们了解到Amunet可能是一个间谍Android应用程序. 我不浪费太多时间因而直入主题. 在本教程中,我们 ...

随机推荐

  1. Oracle 12C -- plug unplugged PDB into CDB

    connetct to CDB as a common user and verify that pdb_test is closed SQL> select con_id,dbid,name, ...

  2. CentOS安装OpenResty(Nginx+Lua)开发环境

    一.简介 OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用于方便地搭建能够处理超高并发.扩展性极高 ...

  3. MPU6050陀螺仪和加速度计的校准

    加速度计和陀螺仪的校准: 在传感器静止不动水平放置时,测出陀螺仪和加速度计各轴的偏移值,保存.以后每次上电调用dmp_set_xx_bias()就行了. u8 run_self_test(void) ...

  4. Android中五种常用的menu

    Android Menu在手机的应用中起着导航的作用,作者总结了5种常用的Menu. 1.左右推出的Menu 前段时间比较流行,我最早是在海豚浏览器中看到的,当时耳目一新.最早使用左右推出菜单的,听说 ...

  5. 谈谈MySQL的WriteSet并行复制

    [历史背景] 岁月更迭中我已经从事MySQL-DBA这个工作三个年头,见证MySQL从“基本可用”,“边缘系统可以用MySQL”,“哦操!你怎么不用MySQL”; 正所谓!“一个数据库的境遇既取决于历 ...

  6. Four Node.js Gotchas that Operations Teams Should Know about

    There is no doubt that Node.js is one of the fastest growing platforms today. It can be found at sta ...

  7. sqlite 判断表中是否包含 某个字段

    数据库 都有一个 根表..(我的理解) 也就是 你创建了一个数据库 里面就带有 一个表 sqlite_master 字段有 type , name  , tbl_name , rootpage ,sq ...

  8. Python 构建方便的函数调用

    CODE: #!/usr/bin/python # -*- coding: utf-8 -*- ''' Created on 2014-7-14 @author: guaguastd @name: c ...

  9. 牛腩学用MUI做手机APP

    斗鱼直播间直播学习撸码,最终目标是用MUI做一个手机APP(暂定android平台,攒钱买IPHONE 7SE!!!),直播内容含整个软件APP的制作过程(含后台接口的制作,放到自己买的阿里云服务器, ...

  10. .net4.5使用async和await异步编程实例

    关于异步编程的简单理解: 在.NET4.5中新增了异步编程的新特性async和await,使得异步编程更为简单.通过特性可以将这项复杂的工作交给编译器来完成了.之前传统的方式来实现异步编程较为复杂,这 ...