基于Android错误信息捕获发送至服务器的详解
2023-06-13 09:15:01 时间
程序员最头疼的事情就是bug和debug。这次debug长达20天,搞的我心力交瘁。累,因为Android兼容性,不同手机会有不同的bug出来,而且很难复现,所以就上网找了下类似保存错误log到文件再上传到服务器,现把源码也共享出来。上传至服务器的代码我没加。相信大家都有现成的代码了。
先讲下原理,跟JavaEE的自定义异常捕获一样,将错误一直向上抛,然后在最上层统一处理。这里就可以获得ExceptionMessage,进行保存操作
异常捕获类如下:
复制代码代码如下:
先讲下原理,跟JavaEE的自定义异常捕获一样,将错误一直向上抛,然后在最上层统一处理。这里就可以获得ExceptionMessage,进行保存操作
异常捕获类如下:
/**
*@authorStay
* 在Application中统一捕获异常,保存到文件中下次再打开时上传
*/
publicclassCrashHandlerimplementsUncaughtExceptionHandler{
/**是否开启日志输出,在Debug状态下开启,
*在Release状态下关闭以提示程序性能
**/
publicstaticfinalbooleanDEBUG=true;
/**系统默认的UncaughtException处理类*/
privateThread.UncaughtExceptionHandlermDefaultHandler;
/**CrashHandler实例*/
privatestaticCrashHandlerINSTANCE;
/**程序的Context对象*/
// privateContextmContext;
/**保证只有一个CrashHandler实例*/
privateCrashHandler(){}
/**获取CrashHandler实例,单例模式*/
publicstaticCrashHandlergetInstance(){
if(INSTANCE==null){
INSTANCE=newCrashHandler();
}
returnINSTANCE;
}
/**
*初始化,注册Context对象,
*获取系统默认的UncaughtException处理器,
*设置该CrashHandler为程序的默认处理器
*
*@paramctx
*/
publicvoidinit(Contextctx){
// mContext=ctx;
mDefaultHandler=Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
*当UncaughtException发生时会转入该函数来处理
*/
@Override
publicvoiduncaughtException(Threadthread,Throwableex){
if(!handleException(ex)&&mDefaultHandler!=null){
//如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread,ex);
}else{ //如果自己处理了异常,则不会弹出错误对话框,则需要手动退出app
try{
Thread.sleep(3000);
}catch(InterruptedExceptione){
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
}
}
/**
*自定义错误处理,收集错误信息
*发送错误报告等操作均在此完成.
*开发者可以根据自己的情况来自定义异常处理逻辑
*@return
*true代表处理该异常,不再向上抛异常,
*false代表不处理该异常(可以将该log信息存储起来)然后交给上层(这里就到了系统的异常处理)去处理,
*简单来说就是true不会弹出那个错误提示框,false就会弹出
*/
privatebooleanhandleException(finalThrowableex){
if(ex==null){
returnfalse;
}
// finalStringmsg=ex.getLocalizedMessage();
finalStackTraceElement[]stack=ex.getStackTrace();
finalStringmessage=ex.getMessage();
//使用Toast来显示异常信息
newThread(){
@Override
publicvoidrun(){
Looper.prepare();
// Toast.makeText(mContext,"程序出错啦:"+message,Toast.LENGTH_LONG).show();
// 可以只创建一个文件,以后全部往里面append然后发送,这样就会有重复的信息,个人不推荐
StringfileName=""+System.currentTimeMillis() +".log";
Filefile=newFile(Environment.getExternalStorageDirectory(),fileName);
try{
FileOutputStreamfos=newFileOutputStream(file,true);
fos.write(message.getBytes());
for(inti=0;i<stack.length;i++){
fos.write(stack[i].toString().getBytes());
}
fos.flush();
fos.close();
}catch(Exceptione){
}
Looper.loop();
}
}.start();
returnfalse;
}
//TODO使用HTTPPost发送错误报告到服务器 这里不再赘述
// privatevoidpostReport(Filefile){
// 在上传的时候还可以将该app的version,该手机的机型等信息一并发送的服务器,
// Android的兼容性众所周知,所以可能错误不是每个手机都会报错,还是有针对性的去debug比较好
// }
}
在ApplicationonCreate时就注册ExceptionHandler,此后只要程序在抛异常后就能捕获到。
publicclassAppextendsApplication{
@Override
publicvoidonCreate(){
super.onCreate();
CrashHandlercrashHandler=CrashHandler.getInstance();
//注册crashHandler
crashHandler.init(getApplicationContext());
}
}
?publicclassLogActivityextendsActivity{
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try{//制造bug
Filefile=newFile(Environment.getExternalStorageState(),"crash.bin");
FileInputStreamfis=newFileInputStream(file);
byte[]buffer=newbyte[1024];
fis.read(buffer);
}catch(Exceptione){
//这里不能再向上抛异常,如果想要将log信息保存起来,则抛出runtime异常,
// 让自定义的handler来捕获,统一将文件保存起来上传
thrownewRuntimeException(e);
}
}
}
注意,如果catch后不throw就默认是自己处理了,ExceptionHandler不会捕获异常了。
publicclassDebugUtil{
publicstaticfinalStringTAG="ICON";
publicstaticfinalbooleanDEBUG=true;
publicstaticvoidtoast(Contextcontext,Stringcontent){
Toast.makeText(context,content,Toast.LENGTH_SHORT).show();
}
publicstaticvoiddebug(Stringtag,Stringmsg){
if(DEBUG){
Log.d(tag,msg);
}
}
publicstaticvoiddebug(Stringmsg){
if(DEBUG){
Log.d(TAG,msg);
}
}
publicstaticvoiderror(Stringtag,Stringerror){
Log.e(tag,error);
}
publicstaticvoiderror(Stringerror){
Log.e(TAG,error);
}
}
相关文章
- android onresume方法,非静态方法’onResume’Android Studio
- 代码加密 android,Android 开发怎样做代码加密或混淆「建议收藏」
- android开发笔记之 Android代码混淆打包
- android 混淆规则作用,Android代码混淆详解
- android okio使用方法,Android 开源框架 Okio 原理剖析「建议收藏」
- android XSS攻击
- android listview更新数据
- mac 电脑android环境变量设置,mac上Android环境变量配置[通俗易懂]
- android activity singletask,Android Activity启动模式之singleTask实例详解
- android定时器取消,Android定时器崩溃取消
- android短信验证码代码,Android短信验证码自动填写实现代码
- android调用相册并显示图片_Android获取相册列表
- 【Android 内存优化】Bitmap 内存缓存 ( Bitmap 缓存策略 | LruCache 内存缓存 | LruCache 常用操作 | 工具类代码 )
- 【Android Gradle 插件】build.gradle 中的 android 配置 ( 配置项 | compileSdkVersion 配置 | buildToolsVersion 配置 )
- 【Android UI】贝塞尔曲线 ④ ( 使用 android.graphics.Path 提供的 cubicTo 方法绘制三阶贝塞尔曲线示例 )
- android上传图片至服务器详解手机开发
- [android] 采用httpclient提交数据到服务器详解手机开发
- [android] 保存文件到SD卡详解手机开发
- Android Studio 导入项目 出现安装Error:Cause: failed to find target with hash string ‘android-23’ 等错误详解手机开发
- JDBC从搭建服务器,到运行到Android全集锦!!详解编程语言
- 掌上药店Android 4.0.7 去广告清爽版
- Android系统与Linux之间的联系(android和linux)
- 使用Android实现连接MySQL数据库:实现快速数据交互与管理(android连接mysql数据库)
- android内存优化之图片优化
- Android开发技巧之在a标签或TextView控件中单击链接弹出Activity(自定义动作)
- Android笔记之:CM9源码下载与编译的应用
- Android基础之使用Fragment控制切换多个页面
- Android调用系统的发邮件功能的小例子
- Android获取assets文件夹中的数据并写入SD卡示例
- Android根据电话号码获得联系人头像实例代码