每个应用在所难免会有bug
,崩溃的时候一闪而过,这样的话交互非常的差。在此,我为大家介绍一种捕捉崩溃信息,并且友好的提示用户的方式。
在Thread
类中有这样一个函数
/**
* Set the default handler invoked when a thread abruptly terminates
* due to an uncaught exception, and no other handler has been defined
* for that thread.
*
* <p>Uncaught exception handling is controlled first by the thread, then
* by the thread's {@link ThreadGroup} object and finally by the default
* uncaught exception handler. If the thread does not have an explicit
* uncaught exception handler set, and the thread's thread group
* (including parent thread groups) does not specialize its
* <tt>uncaughtException</tt> method, then the default handler's
* <tt>uncaughtException</tt> method will be invoked.
* <p>By setting the default uncaught exception handler, an application
* can change the way in which uncaught exceptions are handled (such as
* logging to a specific device, or file) for those threads that would
* already accept whatever "default" behavior the system
* provided.
*
* <p>Note that the default uncaught exception handler should not usually
* defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
* infinite recursion.
*
* @param eh the object to use as the default uncaught exception handler.
* If <tt>null</tt> then there is no default handler.
*
* @throws SecurityException if a security manager is present and it
* denies <tt>{@link RuntimePermission}
* ("setDefaultUncaughtExceptionHandler")</tt>
*
* @see #setUncaughtExceptionHandler
* @see #getUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
defaultUncaughtExceptionHandler = eh;
}
通过注释我们可以看出这个函数是用于设置当线程由于未捕获的异常突然终止而调用的默认处理程序,下面我们通过代码来熟知这个函数的作用。
我们先定义一个CrashHandler
类,这个类实现Thread.UncaughtExceptionHandler
接口,重写uncaughtException
方法来捕捉未处理的异常信息并通过Log
打印出来。代码如下:
package com.zzw.TestCrashHandler;
import android.util.Log;
/**
* Created by zzw on 2017/4/28.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
private static CrashHandler instance;
private CrashHandler() {
}
public static CrashHandler getInstance() {
if (instance == null) {
instance = new CrashHandler();
}
return instance;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
Log.e(TAG, e.toString());
}
public void init() {
Thread.setDefaultUncaughtExceptionHandler(this);
}
}
接下来我们在Application
的onCreate()
里面初始化:
package com.zzw.TestCrashHandler;
import android.app.Application;
/**
* Created by zzw on 2017/4/28.
*/
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
CrashHandler.getInstance().init();
}
}
我们接着制造一个bug
出来:
package com.zzw.TestCrashHandler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.crash_bt).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.crash_bt:
String nullStr = null;
Log.e("zzz", nullStr);
break;
}
}
}
异常捕捉到了,但是却卡主了,然后就是ANR,看来是造成线程堵塞了,所以我们必须把这个给处理了。
package com.zzw.TestCrashHandler;
import android.content.Context;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
/**
* Created by zzw on 2017/4/28.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
private static CrashHandler instance;
private Thread.UncaughtExceptionHandler defaultHandler;//系统默认的UncaughtException处理器
private Context context;
private CrashHandler() {
}
public static CrashHandler getInstance() {
if (instance == null) {
instance = new CrashHandler();
}
return instance;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
if (!handleException(e) && defaultHandler != null) { //如果用户没有处理则让系统默认的异常处理器来处理
defaultHandler.uncaughtException(t, e);
} else {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Log.e(TAG, "error : ", ex);
}
//退出程序
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}
public void init(Context context) {
this.context = context;
//获取系统默认的UncaughtException处理器
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
private boolean handleException(Throwable e) {
if (e == null)
return false;
//使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(context, "程序发生意外情况,即将关闭,我们深感抱歉!我们将会尽快修复!", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
saveException(e);
return true;
}
/**
* 一般在这是把崩溃信息保存下来,然后等wifi的时候上传到服务器
*
* @param e 异常信息
*/
private void saveException(Throwable e) {
Log.e(TAG, e.toString());
}
}
这样的话我们就能够提示用户,然后把异常信息保存下来,等待有Wifi的时候上传就可以了。
效果如下:
这篇文章到这,Demo就不上传了,希望大家有所收获,有什么建议在下方评论,谢谢。