Crash(应用崩溃)是由于代码异常而导致 App 非正常退出,导致应用程序无法继续使用,所有工作都
停止的现象。发生 Crash 后需要重新启动应用(有些情况会自动重启),而且不管应用在开发阶段做得
多么优秀,也无法避免 Crash 发生,特别是在 Android 系统中,系统碎片化严重、各 ROM 之间的差
异,甚至系统Bug,都可能会导致Crash的发生.
package com.example.crash;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
public class CrashHandler implements Thread.UncaughtExceptionHandler {
//文件后缀名
public static final String FILE_NAME_SUFFIX = ".trace";
private static Thread.UncaughtExceptionHandler mDefalutCrashHandler;
private static Context context;
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static class Singleton{
public static final CrashHandler INSTNCE=new CrashHandler();
}
public CrashHandler() {
}
public static CrashHandler getInstance(){
return Singleton.INSTNCE;
}
public void init(@NonNull Context context) {
//默认为 RuntimeInit#KillApplicationHandler
mDefalutCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
this.context=context.getApplicationContext();
}
@Override
public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) {
Log.e("filesDir","uncaughtException +++++++++++++++++++++++++++++++++++++ ");
try {
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(context, "很抱歉,程序出现异常,正在收集日志,即将退出", Toast.LENGTH_LONG)
.show();
Looper.loop();
}
}.start();
//自行处理
File file = dealException(e, t);
//上传服务器
} catch (Exception e1) {
e1.printStackTrace();
} finally {
//交给系统默认程序处理
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
Log.e("filesDir", "error : ", e1);
}
// 退出程序
if (mDefalutCrashHandler != null) {
mDefalutCrashHandler.uncaughtException(t, e);
}
}
}
/**
* 到处异常处理消息到SD卡
*
* @param e
* @param t
* @return
*/
private File dealException(Throwable e, Thread t) {
String time = dateFormat.format(new Date());
// File file = new File(context.getExternalCacheDir().getAbsoluteFile(), "crash_info");
File file = new File(context.getCacheDir().getAbsoluteFile(), "crash_info");
if (!file.exists()) {
file.mkdirs();
}
File crashFile = new File(file, time + FILE_NAME_SUFFIX);
//往文件中写入数据
PrintWriter pw=null;
try {
pw = new PrintWriter(new BufferedWriter(new FileWriter(crashFile)));
pw.println(time);
pw.println("thread : " + t.getName());
pw.println(getPhoneInfo());
e.printStackTrace(pw);
} catch (IOException ex) {
ex.printStackTrace();
} catch (PackageManager.NameNotFoundException ex) {
ex.printStackTrace();
} finally {
if (null!=pw){
pw.flush();
pw.close();
}
}
return crashFile;
}
private String getPhoneInfo() throws PackageManager.NameNotFoundException {
PackageManager pm=context.getPackageManager();
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
StringBuilder builder=new StringBuilder();
//App版本号
builder.append("APP Version :");
builder.append(packageInfo.versionName);
builder.append("_");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
builder.append(packageInfo.getLongVersionCode());
}else {
builder.append(packageInfo.versionCode);
}
builder.append("\n");
//Android版本号
builder.append("OS version :");
builder.append(Build.VERSION.RELEASE);
builder.append("_");
builder.append(Build.VERSION.SDK_INT);
builder.append("\n");
//手机制造商
builder.append("Vendor : ");
builder.append(Build.MANUFACTURER);
builder.append("\n");
//手机型号
builder.append("Model : ");
builder.append(Build.MODEL);
builder.append("\n");
return builder.toString();
}
}
直接在application中调用
public class MyApplication extends Application {
private static MyApplication instance;
public static MyApplication getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
instance = this;
CrashHandler.getInstance().init(this);
}