我们的程序虽然在发布之前都会经过严格测试,但是总会有一个bug导致奔溃,这时为了将这个bug记录下来,如果有机会也可以把这些奔溃日志发给我们,做进一步的处理.
一、异常捕捉
- 要对程序的异常进行捕获,必须重写UncaughtExceptionHandler,如下:
- public class MyUncaughtException implements UncaughtExceptionHandler {
- private Context mContext;
- private UncaughtExceptionHandler mDefaultHandler;
- @Override
- public void uncaughtException(Thread thread, Throwable ex) {
- // TODO Auto-generated method stub
- if (!handleException(thread, ex) && mDefaultHandler != null) {
- mDefaultHandler.uncaughtException(thread, ex);
- } else {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- //默认处理
- mDefaultHandler.uncaughtException(thread, ex);
- <span style="white-space:pre"> </span>android.os.Process.killProcess(android.os.Process.myPid());
- System.exit(1);
- // 重新启动程序,注释上面的退出程序
- Intent intent = new Intent();
- intent.setClass(mContext,MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- android.os.Process.killProcess(android.os.Process.myPid());
- }
- //单例模式保证
- private MyUncaughtException() {
- }
- private static MyUncaughtException instance = null;
- public static MyUncaughtException getInstance() {
- if(instance == null) {
- instance = new MyUncaughtException();
- }
- return instance;
- }
- //初始化
- public void init(Context context) {
- mContext = context;
- mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
- Thread.setDefaultUncaughtExceptionHandler(this);
- }
- //异常处理,保存错误信息,发送等操作
- private boolean handleException(Thread thread, Throwable e) {
- if(e == null) {
- return false;
- }
- final String error = e.getLocalizedMessage();
- //显示异常信息
- new Thread() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- Looper.prepare();
- String description = "程序出错了";
- if(error != null) {
- description += error;
- }
- Toast.makeText(mContext, description, Toast.LENGTH_SHORT).show();
- Looper.loop();
- super.run();
- }
- }.start();
- //保存错误信息
- saveCrashLog();
- return true;
- }
- //这里暂不写实现了
- private void saveCrashLog() {
- }
- 需要在Application中注册,用来监控整个程序
- public class MyApp extends Application {
- @Override
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- MyUncaughtException exceptionHandler = MyUncaughtException.getInstance();
- exceptionHandler.init(getApplicationContext());
- }
- }
- 修改androidManifest.xml中application的name
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:name="MyApp"
4. 始终不理解的是为什么要使用线程处理,为什么将线程升级为looper线程?
如果主线程发生uncaughtException 通常会导致main thread 的looper 退出,这时不会再响应任何UI消息,所以要在其他线程中调用显示的方法。
一直没有找到这地方的源码,猜测,在调用Toast.show()方法的时候,最后会形成一条消息Message,并且如果当前线程没有Handler,会自动构造一个默认的Handler,进行处理,最后这个消息发送Handler对应的Loooper,所以,这个线程一定要是Looper线程,而且在Toast之前,Looper线程已经调用Looper.prapare();