前言:解决用户远在他方但是出现了闪退问题无法调试和复现。
之前尝试使用如Thread.UncaughtExceptionHandler方式发现并不能捕获到异常并执行自己想要的操作,而且进程会阻塞导致ANR
步骤一:在app的入口类application的onCreate中添加如下代码
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
while (true) {
try {
Looper.loop();
} catch (Throwable e) {
Log.e("Crash【主线程】", e.getMessage());
Intent intent = new Intent(getInstance(), CrashActivity.class);
intent.putExtra(INTENT_KEY_IN_THROWABLE, e);
getInstance().startActivity(intent);
System.out.println("捕获异常");
}
}
}
});
步骤二:新建一个异常显示的activity,当出现异常会跳转该activity并展示异常信息
package com.fangtao.activities.other;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.fangtao.R;
import com.fangtao.activities.ClassificationActivity;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CrashActivity extends AppCompatActivity {
private static final String INTENT_KEY_IN_THROWABLE = "throwable";
/** 报错代码行数正则表达式 */
private static final Pattern CODE_REGEX = Pattern.compile("\\(\\w+\\.\\w+:\\d+\\)");
/** 系统包前缀列表 */
private static final String[] SYSTEM_PACKAGE_PREFIX_LIST = new String[]
{"android", "com.android", "androidx", "com.google.android", "java", "javax", "dalvik", "kotlin"};
private static CrashActivity activity;
private String mStackTrace;
private TextView tvError;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash);
activity = this;
Bundle bundle = getIntent().getExtras();
Throwable throwable = (Throwable)bundle.getSerializable(INTENT_KEY_IN_THROWABLE);
tvError = findViewById(R.id.tv_error);
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
throwable.printStackTrace(printWriter);
Throwable cause = throwable.getCause();
if (cause != null) {
cause.printStackTrace(printWriter);
}
mStackTrace = stringWriter.toString();
Matcher matcher = CODE_REGEX.matcher(mStackTrace);
SpannableStringBuilder spannable = new SpannableStringBuilder(mStackTrace);
if (spannable.length() > 0) {
while (matcher.find()) {
// 不包含左括号(
int start = matcher.start() + "(".length();
// 不包含右括号 )
int end = matcher.end() - ")".length();
// 代码信息颜色
int codeColor = 0xFF999999;
int lineIndex = mStackTrace.lastIndexOf("at ", start);
if (lineIndex != -1) {
String lineData = spannable.subSequence(lineIndex, start).toString();
if (TextUtils.isEmpty(lineData)) {
continue;
}
// 是否高亮代码行数
boolean highlight = true;
for (String packagePrefix : SYSTEM_PACKAGE_PREFIX_LIST) {
if (lineData.startsWith("at " + packagePrefix)) {
highlight = false;
break;
}
}
if (highlight) {
codeColor = 0xFF287BDE;
}
}
// 设置前景
spannable.setSpan(new ForegroundColorSpan(codeColor), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// 设置下划线
spannable.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
tvError.setText(spannable);
}
}
public static CrashActivity getInstance() {
return activity;
}
}