android 监测bug上传到服务器,基于Android 错误信息捕获发送至服务器的详解

程序员最头疼的事情就是bug和debug。这次debug长达20天,搞的我心力交瘁。累,因为Android兼容性,不同手机会有不同的bug出来,而且很难复现,所以就上网找了下类似保存错误log到文件再上传到服务器,现把源码也共享出来。上传至服务器的代码我没加。相信大家都有现成的代码了。

先讲下原理,跟JavaEE的自定义异常捕获一样,将错误一直向上抛,然后在最上层统一处理。这里就可以获得Exception Message,进行保存操作

异常捕获类如下:

/**

* @author Stay

*      在Application中统一捕获异常,保存到文件中下次再打开时上传

*/

public class CrashHandler implements UncaughtExceptionHandler {

/** 是否开启日志输出,在Debug状态下开启,

* 在Release状态下关闭以提示程序性能

* */

public static final boolean DEBUG = true;

/** 系统默认的UncaughtException处理类 */

private Thread.UncaughtExceptionHandler mDefaultHandler;

/** CrashHandler实例 */

private static CrashHandler INSTANCE;

/** 程序的Context对象 */

//    private Context mContext;

/** 保证只有一个CrashHandler实例 */

private CrashHandler() {}

/** 获取CrashHandler实例 ,单例模式*/

public static CrashHandler getInstance() {

if (INSTANCE == null) {

INSTANCE = new CrashHandler();

}

return INSTANCE;

}

/**

* 初始化,注册Context对象,

* 获取系统默认的UncaughtException处理器,

* 设置该CrashHandler为程序的默认处理器

*

* @param ctx

*/

public void init(Context ctx) {

//        mContext = ctx;

mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();

Thread.setDefaultUncaughtExceptionHandler(this);

}

/**

* 当UncaughtException发生时会转入该函数来处理

*/

@Override

public void uncaughtException(Thread thread, Throwable ex) {

if (!handleException(ex) && mDefaultHandler != null) {

//如果用户没有处理则让系统默认的异常处理器来处理

mDefaultHandler.uncaughtException(thread, ex);

} else {  //如果自己处理了异常,则不会弹出错误对话框,则需要手动退出app

try {

Thread.sleep(3000);

} catch (InterruptedException e) {

}

android.os.Process.killProcess(android.os.Process.myPid());

System.exit(10);

}

}

/**

* 自定义错误处理,收集错误信息

* 发送错误报告等操作均在此完成.

* 开发者可以根据自己的情况来自定义异常处理逻辑

* @return

* true代表处理该异常,不再向上抛异常,

* false代表不处理该异常(可以将该log信息存储起来)然后交给上层(这里就到了系统的异常处理)去处理,

* 简单来说就是true不会弹出那个错误提示框,false就会弹出

*/

private boolean handleException(final Throwable ex) {

if (ex == null) {

return false;

}

//        final String msg = ex.getLocalizedMessage();

final StackTraceElement[] stack = ex.getStackTrace();

final String message = ex.getMessage();

//使用Toast来显示异常信息

new Thread() {

@Override

public void run() {

Looper.prepare();

//                Toast.makeText(mContext, "程序出错啦:" + message, Toast.LENGTH_LONG).show();

//                可以只创建一个文件,以后全部往里面append然后发送,这样就会有重复的信息,个人不推荐

String fileName = "crash-" + System.currentTimeMillis()  + ".log";

File file = new File(Environment.getExternalStorageDirectory(), fileName);

try {

FileOutputStream fos = new FileOutputStream(file,true);

fos.write(message.getBytes());

for (int i = 0; i < stack.length; i++) {

fos.write(stack[i].toString().getBytes());

}

fos.flush();

fos.close();

} catch (Exception e) {

}

Looper.loop();

}

}.start();

return false;

}

// TODO 使用HTTP Post 发送错误报告到服务器  这里不再赘述

//    private void postReport(File file) {

//      在上传的时候还可以将该app的version,该手机的机型等信息一并发送的服务器,

//      Android的兼容性众所周知,所以可能错误不是每个手机都会报错,还是有针对性的去debug比较好

//    }

}

在Application onCreate时就注册ExceptionHandler,此后只要程序在抛异常后就能捕获到。

public class App extends Application{

@Override

public void onCreate() {

super.onCreate();

CrashHandler crashHandler = CrashHandler.getInstance();

//注册crashHandler

crashHandler.init(getApplicationContext());

}

}

?public class LogActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

try {//制造bug

File file = new File(Environment.getExternalStorageState() ,"crash.bin");

FileInputStream fis = new FileInputStream(file);

byte[] buffer = new byte[1024];

fis.read(buffer);

} catch (Exception e) {

//这里不能再向上抛异常,如果想要将log信息保存起来,则抛出runtime异常,

//          让自定义的handler来捕获,统一将文件保存起来上传

throw new RuntimeException(e);

}

}

}

注意,如果catch后不throw就默认是自己处理了,ExceptionHandler不会捕获异常了。再分享一个Log的封装类,只要在这里设置DEBUG的值就能让控制台是否打印出log

public class DebugUtil {

public static final String TAG = "ICON";

public static final boolean DEBUG = true;

public static void toast(Context context,String content){

Toast.makeText(context, content, Toast.LENGTH_SHORT).show();

}

public static void debug(String tag,String msg){

if (DEBUG) {

Log.d(tag, msg);

}

}

public static void debug(String msg){

if (DEBUG) {

Log.d(TAG, msg);

}

}

public static void error(String tag,String error){

Log.e(tag, error);

}

public static void error(String error){

Log.e(TAG, error);

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

除了欧拉公式,这8个数学公式也足够美丽且神奇

来源&#xff1a;算法与数学之美1概率分布公式

20 ubuntu 中科大源_Ubuntu18.04更换国内源(阿里,网易,中科大,清华等源)

Ubuntu18.04更换国内源(阿里&#xff0c;网易&#xff0c;中科大&#xff0c;清华等源)ubuntu源路径&#xff1a;/etc/apt/sources.list1. 备份/etc/apt/sources.list文件mv /etc/apt/sources.list /etc/apt/sources.list.backup2. 新建/etc/apt/sources.list文件&#xff0c;并…

canvas rotate 累加旋转_震惊,canvas文字粒子效果,只需要100行代码,简单易懂。

震惊,canvas文字粒子效果&#xff0c;只需要100行代码&#xff0c;简单易懂。canvas是使用JavaScript程序绘图(动态生成),相比于css&#xff0c;可以更加简单方便的绘制细节的样式。其中最强大的功能莫过去像素的处理。一个像素一个像素去绘制任何想要的展示效果。接下来&#…

SET ARITHABORT ON 对UI的影响

今天在live上出现一件很奇怪的事情&#xff0c;就是有一部分User首页上的My action item处于一直loading的状态&#xff0c;而运行SP的时候内容是可以拉出来的&#xff0c;排查出来的结果是ARITHABORT option是off的&#xff0c;今天就来脑补一下这个ARITHABORT。 Microsoft De…

CES 2020前瞻:一份最全的趋势预测报告

来源&#xff1a; CES20202020年&#xff0c;消费级技术领域的总体趋势可以总结为&#xff1a;最顶尖的产品将变得更强大、更完善。虽然我们并不喜欢“溢价”这个已经被用滥了的字眼&#xff0c;但不得不承认&#xff0c;新一年中溢价会成为新的常态。最好的东西会变得更好&…

Android pda出入库管理,出入库PDA管理系统软件

随着经济的高速发展&#xff0c;市场的日新月异&#xff0c;仓库管理越来越重要起来&#xff0c;企业里从原料的入库到成品的出库都需经过仓库来管理控制&#xff0c;仓库工作责任重大、数据即时准确犹为关键&#xff0c;现代企业大多都借助出入库管理系统软件来管控仓库&#…

backlog配置_TCP/IP协议中backlog参数

TCP建立连接是要进行三次握手&#xff0c;但是否完成三次握手后&#xff0c;服务器就处理(accept)呢&#xff1f;backlog其实是一个连接队列&#xff0c;在Linux内核2.2之前&#xff0c;backlog大小包括半连接状态和全连接状态两种队列大小。半连接状态为&#xff1a;服务器处于…

一棵树的生物量怎么算_桂花开花小、开花少怎么办?四点建议送给你!

原标题&#xff1a;桂花开花小、开花少怎么办&#xff1f;四点建议送给你&#xff01;虽然冬天绝大多数桂花都处在休眠期&#xff0c;生长缓慢&#xff0c;不开花&#xff0c;但四季桂花是个例外&#xff0c;只要温度合适养护得当&#xff0c;冬天也能让我们闻到桂花香。桂花开…

面向对象(特点)、局部变量与全局变量的区别、匿名对象、构造函数、

一、 1&#xff0c;本文档为记录练习面向对象学习的文档。 2&#xff1a; 面向对象的三大特点&#xff1a; 1&#xff09;、封装&#xff1a;隐藏对象的属性和实现细节&#xff0c;仅对外提供公共访问方式&#xff0c; 优点&#xff1a;1、隔离了变化。 2、…

28篇标志性论文见证「自然语言处理NLP」2019-2020年度亮点进展

来源&#xff1a;专知【导读】自然语言处理专家elvis在medium博客上发表了关于NLP在2019年的亮点总结。对于自然语言处理&#xff08;NLP&#xff09;领域而言&#xff0c;2019年是令人印象深刻的一年。在这篇博客文章中&#xff0c;我想重点介绍一些我在2019年遇到的与机器学习…

spark while_05_尚硅谷大数据技术之Spark内核解析(1.1) - 十一vs十一

尚硅谷大数据课程之Spark内核解析(作者&#xff1a;尚硅谷大数据研发部)官网&#xff1a;版本&#xff1a;V1. Spark 内核概述Spark内核泛指Spark的核心运行机制&#xff0c;包括Spark核心组件的运行机制、Spark任务调度机制、Spark内存管理机制、Spark核心功能的运行原理等&am…

python中难的算法_一个python的比较难的算法,有懂的人可以进来一下

问 题我的需求:结构数据是这样的:要求按照这样的公式:组合一: 时间词地方词动词等级名词价格词&#xff1b;比如2016年深圳大鹏新区给健康全身检查要多少钱就是按照这样的公式组合出来的关键词那么有什么办法用最短的办法来实现,我下面是我的算法,用pandas的算法:for times in …

android 进程管理机制,Android的进程管理机制

Linux系统对进程的管理方式是一旦进程活动停止&#xff0c;系统就会结束该进程。Android系统虽基于Linux&#xff0c;但在进程管理上&#xff0c;采取了另外一种机制。当当前进程活动停止时&#xff0c;系统并不会立即结束当前进程&#xff0c;而是会将该进程保存在内存中&…

IOS 获取农历方法(转)

声明&#xff1a;以下为使用iOS的 NSChineseCalendar 网上之前发现有人说这个方法不是完全准确&#xff0c;有些日期会显示的不对&#xff0c;本人没有验证过&#xff0c;也实在懒得用C那套方法去实现。 另外我做的不过是个简单的功能&#xff0c;还不包括什么节气 节日那些复杂…

AI初创公司都去哪了?2019年科技公司“五巨头”收购盘点

大数据文摘出品来源&#xff1a;venturebeat人工智能人才的争夺大战愈演愈烈。 今年&#xff0c;Pinterest的首席技术官Vanja Josifovski离职加入了Airbnb&#xff0c;而Pinterest则聘请了沃尔玛的首席技术官Jeremy King来领导工程团队。此外&#xff0c;包括谷歌和苹果在内的所…

angular element()

使用angular.element()获取一个dom的方法。 1.可以使用jquery的选择器 2.可以使用javascript的原生查找元素的方法 下面是angular.element()提供的方法 <input type"checkbox" class"input" /><input type"text" class"input1&quo…

电脑连接android手机测试,关于如何将手机画面投屏到PC的测试(Android)

如何将手机画面投屏到PC上并进行控制呢?为什么要投屏一边LOL ,一边朋友圈?办公呢? 我手机插上充电就好,电脑上刷刷手机呢?哈哈准备工具下载工具如何使用无线使用写在最后后续为什么要投屏我最近买了个带鱼屏, 屏幕长到用不完的地步了. 总想折腾折腾看看还能玩出来什么花样手…

【前沿科技】看完这篇文章前,你绝对想象不到欧美航空机器人竟然发展到这个程度了!...

来源&#xff1a;中国机器人网《工程》杂志撰文认为&#xff0c;工业机器人在许多行业中已经建立了良好的基础&#xff0c;并且通常与现代化的先进制造系统相关联&#xff0c;但是&#xff0c;航空制造仍然严重依赖熟练的手工作业。航空制造中采用机器人的一个主要障碍是缺乏精…

beautifulsoup网页爬虫解析_Python爬虫快速入门,静态网页爬取

在开始之前&#xff0c;请确保你的电脑上已经安装好了BeautifulSoup库&#xff0c;可以通过在命令行中输入pip install beautifulsoup4来进行安装。一、数据解析在爬取之前&#xff0c;我们需要检测下响应状态码是否为200&#xff0c;如果请求失败&#xff0c;我们将爬取不到任…

android获取小程序音频时长,微信小程序获取音频时长与实时获取播放进度

首先在没有播放音频之前&#xff0c;居然拿不到总时长但是在播放之后也需要设置setTimeout来获取所以在监听音频播放进度更新事件中获取。顺便获取当前播放进度按照官方的写法audioPlayed: function () {myAudio.play()setTimeout(() > {myAudio.onTimeUpdate(() > {cons…