您的位置:首页 > 移动开发 > Android开发

Android使用UncaughtExceptionHandler获取crash信息

2017-07-20 23:59 495 查看
Android应用崩溃时如何获取crash信息及处理后续操作。

Android提供了处理此类问题的方法,Thread类中有这样一个方法

/**
* 设置线程突然终止时调用的默认处理程序
* @param eh
*/
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) {
defaultUncaughtExceptionHandler = eh;
}


通用上面的方法,可以看到要传入一个Thread.UncaughtExceptionHandler对象到此方法中。

public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}


UncaughtExceptionHandler是一个接口,首先要继承这个接口,实现我们的Crash处理

public class MyCrashExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "MyCrashExceptionHandler";

private static MyCrashExceptionHandler instance;

private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
private Context mContext;

private MyCrashExceptionHandler() {

}

public static MyCrashExceptionHandler getInstance() {
if (instance == null) {
synchronized (MyCrashExceptionHandler.class) {
if (instance == null) {
instance = new MyCrashExceptionHandler();
}
}
}
return instance;
}

public void init(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context is null!!!");
}
mContext = context.getApplicationContext();
mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();//获取系统的默认异常处理程序
Thread.setDefaultUncaughtExceptionHandler(this);//设置系统的默认异常处理
}

@Override
public void uncaughtException(Thread t, Throwable e) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "程序发生异常,即将重启", Toast.LENGTH_SHORT).show();
Looper.loop();
}
}).start();

SystemClock.sleep(2000);

Intent intent = new Intent(mContext, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
Process.killProcess(Process.myPid());
}
}


MainActivity代码

public class MainActivity extends AppCompatActivity {

ImageView img = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button btn = new Button(this);
btn.setText("崩溃");
btn.setLayoutParams(new ViewGroup.LayoutParams(-1, -2));
setContentView(btn);

MyCrashExceptionHandler myCrashExceptionHandler = MyCrashExceptionHandler.getInstance();
myCrashExceptionHandler.init(this);

btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
img.setImageResource(R.mipmap.ic_launcher);//异常
}
});
}
}


MyCrashExceptionHandler应该在Application类中初始化,这里为了方便演示,直接写在MainActivity类中了



点击崩溃按钮,提示程序发生异常,即将重启,然后重新启动MainActivity界面

上述只是演示了发生异常时重启APK,接下来我们来获取Crash信息

修改后的代码如下

public class MyCrashExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "MyCrashExceptionHandler";

private static MyCrashExceptionHandler instance;

private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
private Context mContext;

private final String mCrashFileName = "crash";

private MyCrashExceptionHandler() {

}

public static MyCrashExceptionHandler getInstance() {
if (instance == null) {
synchronized (MyCrashExceptionHandler.class) {
if (instance == null) {
instance = new MyCrashExceptionHandler();
}
}
}
return instance;
}

public void init(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context is null!!!");
}
mContext = context.getApplicationContext();
mDefaultExceptionHandler = T
cb93
hread.getDefaultUncaughtExceptionHandler();//获取系统的默认异常处理程序
Thread.setDefaultUncaughtExceptionHandler(this);//设置系统的默认异常处理
}

@Override
public void uncaughtException(Thread t, Throwable e) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "程序发生异常,即将退出", Toast.LENGTH_SHORT).show();
Looper.loop();
}
}).start();

printCrashInfo(e);
SystemClock.sleep(2000);
//
//        Intent intent = new Intent(mContext, MainActivity.class);
//        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//        mContext.startActivity(intent);
Process.killProcess(Process.myPid());
}

public void printCrashInfo(Throwable ex) {
File path = mContext.getCacheDir();
long time = System.currentTimeMillis();
File crashFile = new File(path, mCrashFileName + time + ".trace");
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(time));
try {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(crashFile)));
pw.println(date);
PackageManager pm = mContext.getPackageManager();
PackageInfo packageInfo = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
pw.println("packageName:" + mContext.getPackageName());
pw.println("APK Ver:" + packageInfo.versionName + " _ " + packageInfo.versionCode);
//TODO 这里为了演示就不打印更多的信息了
pw.println("---------------------------------------------------");
ex.printStackTrace(pw);
pw.close();
} catch (Exception e) {

}
}

/**
* 联网上传crash文件
*/
public void uploadCrashFile() {
//TODO
}
}


点击崩溃后通过ADM查看包名下的cache目录可以看到crash文件已经保存成功了



导出后可以看到详细的崩溃信息



还可以根据需要上传crash信息文件,后台做到上线APK崩溃反馈崩溃信息,更好的完善APK。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息