Android编程实现捕获程序异常退出时的错误log信息功能详解
程序员文章站
2023-12-18 12:49:58
本文实例讲述了android编程实现捕获程序异常退出时的错误log信息功能。分享给大家供大家参考,具体如下:
很多时候我们程序无缘无故的就挂掉了,让我们一头雾水,如果刚好...
本文实例讲述了android编程实现捕获程序异常退出时的错误log信息功能。分享给大家供大家参考,具体如下:
很多时候我们程序无缘无故的就挂掉了,让我们一头雾水,如果刚好我们在调试,那我们可以通过错误log来查看是什么原因引起的程序崩溃。但是当我们把程序发别人使用时,就没那么好运了,那我们要怎么样才能捕获到那个错误异常呢?还好android给我们提供了uncaughtexceptionhandler 这个类,我们可以通过实现这个类的接口,来全局捕获那个让程序崩掉的错误log信息。可以将错误的log保存在本地,也可以发送给服务器后台。下面来看下uncaughtexceptionhandler 的实现类crashhandler吧。
crashhandler.java
import java.io.file; import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.ioexception; 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.simpledateformat; import java.util.date; import java.util.locale; import android.content.context; import android.content.pm.packageinfo; import android.content.pm.packagemanager; import android.content.pm.packagemanager.namenotfoundexception; import android.os.build; import android.os.environment; import android.os.looper; import android.util.log; import android.widget.toast; public class crashhandler implements uncaughtexceptionhandler { private static final string tag = crashhandler.class.getsimplename(); private static final string single_return = "\n"; private static final string single_line = "--------------------------------"; private static crashhandler mcrashhandler; private context mcontext; private uncaughtexceptionhandler mdefaulthandler; private stringbuffer merrorlogbuffer = new stringbuffer(); /** * 获取crashhandler实例,单例模式。 * * @return 返回crashhandler实例 */ public static crashhandler getinstance() { if (mcrashhandler == null) { synchronized (crashhandler.class) { if (mcrashhandler == null) { mcrashhandler = new crashhandler(); } } } return mcrashhandler; } public void init(context context) { mcontext = context; // 获取系统默认的uncaughtexception处理类实例 mdefaulthandler = thread.getdefaultuncaughtexceptionhandler(); // 设置成我们处理uncaughtexception的类 thread.setdefaultuncaughtexceptionhandler(this); } @override public void uncaughtexception(thread thread, throwable ex) { log.d(tag, "uncaughtexception:" + ex); if (!handleexception(ex) && mdefaulthandler != null) { // 如果用户没有处理异常就由系统默认的异常处理器来处理 mdefaulthandler.uncaughtexception(thread, ex); } else { try { thread.sleep(3000); } catch (interruptedexception e) { e.printstacktrace(); } android.os.process.killprocess(android.os.process.mypid()); } } //处理异常事件 private boolean handleexception(throwable ex) { if (ex == null) { return false; } new thread(new runnable() { @override public void run() { looper.prepare(); toast.maketext(mcontext, "很抱歉,程序出现异常,即将退出.", toast.length_short) .show(); looper.loop(); } }).start(); // 收集设备参数信息 collectdeviceinfo(mcontext); // 收集错误日志 collectcrashinfo(ex); // 保存错误日志 saveerrorlog(); //todo: 这里可以加一个网络的请求,发送错误log给后台 // senderrorlog(); return true; } //保存日志到/mnt/sdcard/applog/目录下,文件名已时间yyyy-mm-dd_hh-mm-ss.log的形式保存 private void saveerrorlog() { if (environment.media_mounted.equals(environment.getexternalstoragestate())) { simpledateformat sdf = new simpledateformat("yyyy-mm-dd hh-mm-ss", locale.getdefault()); string format = sdf.format(new date()); format += ".log"; string path = environment.getexternalstoragedirectory().getpath()+"/applog/"; file file = new file(path); if (!file.exists()){ file.mkdirs(); } fileoutputstream fos = null; try { fos = new fileoutputstream(path+format); fos.write(merrorlogbuffer.tostring().getbytes()); fos.flush(); } catch (filenotfoundexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } finally { if (fos != null) { try { fos.close(); fos = null; } catch (ioexception e) { e.printstacktrace(); } } } } } //收集错误信息 private void collectcrashinfo(throwable ex) { writer info = new stringwriter(); printwriter printwriter = new printwriter(info); ex.printstacktrace(printwriter); throwable cause = ex.getcause(); while (cause != null) { cause.printstacktrace(printwriter); cause = cause.getcause(); } string result = info.tostring(); printwriter.close(); //将错误信息加入merrorlogbuffer中 append("", result); merrorlogbuffer.append(single_line + single_return); log.d(tag, "savecrashinfo2file:" + merrorlogbuffer.tostring()); } //收集应用和设备信息 private void collectdeviceinfo(context context) { //每次使用前,清掉merrorlogbuffer里的内容 merrorlogbuffer.setlength(0); merrorlogbuffer.append(single_return + single_line + single_return); //获取应用的信息 packagemanager pm = context.getpackagemanager(); try { packageinfo pi = pm.getpackageinfo(context.getpackagename(), packagemanager.get_activities); if (pi != null) { append("versioncode", pi.versioncode); append("versionname", pi.versionname); append("packagename", pi.packagename); } } catch (namenotfoundexception e) { e.printstacktrace(); } merrorlogbuffer.append(single_line + single_return); //获取设备的信息 field[] fields = build.class.getdeclaredfields(); getdeviceinfobyreflection(fields); fields = build.version.class.getdeclaredfields(); getdeviceinfobyreflection(fields); merrorlogbuffer.append(single_line + single_return); } //获取设备的信息通过反射方式 private void getdeviceinfobyreflection(field[] fields) { for (field field : fields) { try { field.setaccessible(true); append(field.getname(), field.get(null)); } catch (illegalargumentexception e) { e.printstacktrace(); } catch (illegalaccessexception e) { e.printstacktrace(); } } } //merrorlogbuffer添加友好的log信息 private void append(string key, object value) { merrorlogbuffer.append("" + key + ":" + value + single_return); } }
在application中的使用非常简单,只要init就好了,之后我们就只要等异常出现吧。
crashapplication.java
import android.app.application; public class crashapplication extends application{ @override public void oncreate() { super.oncreate(); crashhandler.getinstance().init(this); } }
不要忘记在androidmanifest.xml声明我们的crashapplication 。
androidmanifest.xml
<uses-permission android:name="android.permission.write_external_storage"/> <application android:allowbackup="true" android:name=".crashapplication" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/apptheme" > <activity android:name="com.example.crashtestdemo.mainactivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> </application>
更多关于android相关内容感兴趣的读者可查看本站专题:《android开发入门与进阶教程》、《android调试技巧与常见问题解决方法汇总》、《android编程之activity操作技巧总结》、《android操作json格式数据技巧总结》、《android数据库操作技巧总结》、《android文件操作技巧汇总》、《android资源操作技巧汇总》及《android控件用法总结》
希望本文所述对大家android程序设计有所帮助。