前言
相信大家都遇到过测试人员测试的时候一些偶发性的bug导致程序崩溃,实在是难以复现,所以只能通过一遍遍的检查代码然后猜测可能出现问题的代码,非常难受,因为难以复现所以很多时候改完也难以验证,接下来就为大家介绍一个“轮子”,可以帮助我们在程序崩溃的时候跳转到指定页面,并且输出日志,可复制到粘贴板,然后保留下来,有了崩溃日志,问题出在哪儿就好分析啦。
首先肯定是先感谢大神的分享
好了接下来就是实现的方法,第一步是导入处理崩溃的依赖
implementation 'cat.ereza:customactivityoncrash:2.3.0'//崩溃处理依赖
然后是在自己的Application中的onCreate()中添加以下代码
@Override
public void onCreate() {
super.onCreate();
/**
//此方法定义当应用程序在后台崩溃时是否应启动错误活动。共有三种模式:
//CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM:即使应用程序在后台运行,也会启动错误活动。
//CaocConfig.BACKGROUND_MODE_CRASH:当应用程序在后台运行时,启动默认系统错误。
//CaocConfig.BACKGROUND_MODE_SILENT:当应用程序在后台运行时,它会以静默方式崩溃。
//默认值为CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM。
*/
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SILENT) //default: CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM
.enabled(false) //是否启用 default: true
.showErrorDetails(false) //default: true 隐藏错误活动中的“错误详细信息”按钮
.showRestartButton(false) //default: true 是否可以重启页面
.logErrorOnRestart(false) //default: true
.trackActivities(true) //default: false
.minTimeBetweenCrashesMs(2000) //default: 3000
.errorDrawable(R.drawable.ic_custom_drawable) //default: bug image
.restartActivity(YourCustomActivity.class) //默认程序崩溃时重启的的activity default: null (your app's launch activity)
.errorActivity(YourCustomErrorActivity.class) //默认程序崩溃时跳转的activity default: null (default error activity)
.eventListener(new YourCustomEventListener()) //default: null
.apply();
}
然后是实现CustomEventListener
class CustomEventListener implements CustomActivityOnCrash.EventListener {
@Override
public void onLaunchErrorActivity() {
Log.i(TAG, "onLaunchErrorActivity()");
}
@Override
public void onRestartAppFromErrorActivity() {
Log.i(TAG, "onRestartAppFromErrorActivity()");
}
@Override
public void onCloseAppFromErrorActivity() {
Log.i(TAG, "onCloseAppFromErrorActivity()");
}
}
重启页面就不多介绍了
.restartActivity(YourCustomActivity.class) //默认程序崩溃时重启的的activity default: null (your app's launch activity)
主要介绍一下,崩溃时跳转的页面,然后这个页面UI和流程设计的的好的话,其实还是比较好的,最起码比程序崩溃了闪退就好多了
.errorActivity(YourCustomErrorActivity.class) //默认程序崩溃时跳转的activity default: null (default error activity)
这是我的,因为我只是用作测试阶段的时候供测试人员提供崩溃日志,所以就随便写了;
首先是布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="MissingDefaultResource">
<View
android:id="@+id/V_statusBar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/colorPrimary" />
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="出错啦"
android:textColor="#FFFFFF"
android:textSize="17sp"
android:textStyle="bold" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF">
<ImageView
android:id="@+id/IMG_null"
android:layout_width="248dp"
android:layout_height="248dp"
android:layout_centerInParent="true"
android:layout_marginTop="100dp"
android:src="@drawable/ic_null_page" />
<TextView
android:id="@+id/data_null_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/IMG_null"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textSize="16dp"
android:text="@string/error_occurred"
android:textColor="#FFD0DDF8" />
<Button
android:id="@+id/restart_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="30dp"
android:layout_centerHorizontal="true"
android:text="@string/close_app" />
<Button
android:id="@+id/more_info_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_margin="30dp"
android:layout_centerHorizontal="true"
android:text="@string/error_details" />
</RelativeLayout>
</LinearLayout>
其中的文字,颜色和图片资源就自己替换一下哈;
加下来就是具体的activity,自定义的内容比较多,懒得一一复赘了,关键代码拷贝下来就可以哈;
public final class DefaultErrorActivity extends BaseActivity<ActivityErrorBinding> {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding.VStatusBar.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(this)));
QMUIStatusBarHelper.translucent(this);
QMUIStatusBarHelper.setStatusBarDarkMode(this);
//This is needed to avoid a crash if the developer has not specified
//an app-level theme that extends Theme.AppCompat
TypedArray a = obtainStyledAttributes(R.styleable.AppCompatTheme);
if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) {
setTheme(R.style.Theme_AppCompat_Light_DarkActionBar);
}
a.recycle();
//Close/restart button logic:
//If a class if set, use restart.
//Else, use close and just finish the app.
//It is recommended that you follow this logic if implementing a custom error activity.
Button restartButton = viewBinding.restartButton;
final CaocConfig config = CustomActivityOnCrash.getConfigFromIntent(getIntent());
if (config == null) {
//This should never happen - Just finish the activity to avoid a recursive crash.
finish();
return;
}
if (config.isShowRestartButton() && config.getRestartActivityClass() != null) {
restartButton.setText(R.string.restart_app);
restartButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CustomActivityOnCrash.restartApplication(DefaultErrorActivity.this, config);
}
});
} else {
restartButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CustomActivityOnCrash.closeApplication(DefaultErrorActivity.this, config);
}
});
}
Button moreInfoButton = viewBinding.moreInfoButton;
if (config.isShowErrorDetails()) {
moreInfoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//We retrieve all the error data and show it
AlertDialog dialog = new AlertDialog.Builder(DefaultErrorActivity.this)
.setTitle(R.string.error_details)
.setMessage(CustomActivityOnCrash.getAllErrorDetailsFromIntent(DefaultErrorActivity.this, getIntent()))
.setPositiveButton(R.string.customactivityoncrash_error_activity_error_details_close, null)
.setNeutralButton(R.string.customactivityoncrash_error_activity_error_details_copy,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
copyErrorToClipboard();
}
})
.show();
TextView textView = dialog.findViewById(android.R.id.message);
if (textView != null) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.error_details_text_size));
}
}
});
} else {
moreInfoButton.setVisibility(View.GONE);
}
Integer defaultErrorActivityDrawableId = config.getErrorDrawable();
ImageView errorImageView = findViewById(R.id.customactivityoncrash_error_activity_image);
if (defaultErrorActivityDrawableId != null) {
errorImageView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), defaultErrorActivityDrawableId, getTheme()));
}
}
private void copyErrorToClipboard() {
String errorInformation = CustomActivityOnCrash.getAllErrorDetailsFromIntent(DefaultErrorActivity.this, getIntent());
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
//Are there any devices without clipboard...?
if (clipboard != null) {
ClipData clip = ClipData.newPlainText(getString(R.string.customactivityoncrash_error_activity_error_details_clipboard_label), errorInformation);
clipboard.setPrimaryClip(clip);
Toast.makeText(DefaultErrorActivity.this, R.string.customactivityoncrash_error_activity_error_details_copied, Toast.LENGTH_SHORT).show();
}
}
}
最后,别忘了在AndroidManifest.xml中添加自己的Application文件名
<application
android:name=".Application"
...
至此就可以了,程序遇到崩溃时就会自动跳转到自己定义的界面,和输出日志啦;
再次感谢分享,也可以查看原分享者的详细介绍