Android自定义全局异常捕获——Activity形式
前言
开发安卓的小伙伴都遇到过APP突然崩溃,无响应的情况.如果发生在自己手中,那么还可以通过IDE查看错误日志,但是实际都是发生在用户手中,那么这个时候产生崩溃,无响应ANR异常就很麻烦.无从下手.因此,需要全局异常捕获.也就是对未知异常,程序员没有处理的异常进行处理,记录等便于分析查找原因,
而一个美观的崩溃提示则可以大大加分 。
效果展示
源码
MyUncaughtExceptionHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Locale;
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { private static MyUncaughtExceptionHandler myUncaughtExceptionHandler; private Context context; private StringBuilder stringBuilder; private Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
public MyUncaughtExceptionHandler(Context context) { this.context = context; }
public static synchronized MyUncaughtExceptionHandler getInstance(Context ctx) { if (myUncaughtExceptionHandler == null) { myUncaughtExceptionHandler = new MyUncaughtExceptionHandler(ctx); } return myUncaughtExceptionHandler; }
public void init() { defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); }
@Override public void uncaughtException(Thread thread, Throwable throwable) { if (throwable == null) { defaultUncaughtExceptionHandler.uncaughtException(thread, throwable); }
stringBuilder = new StringBuilder();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS", Locale.getDefault()); String date = simpleDateFormat.format(new Date()); addMessage("崩溃时间", date);
try { PackageManager pm = context.getPackageManager(); PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES); addMessage("版本名", pi.versionName); addMessage("版本号", pi.versionCode); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); addMessage("error", "记录版本信息失败!" + e.getMessage()); }
Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); Object obj = field.get(null); if (obj != null) { addMessage(field.getName(), obj); } } catch (IllegalAccessException e) { e.printStackTrace(); addMessage("error", "记录设备信息失败!" + e.getMessage()); } }
addMessage(null, "=============================================================="); addMessage(null, "======================== 崩溃日志 ========================="); addMessage(null, "==============================================================");
Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); throwable.printStackTrace(printWriter); Throwable cause = throwable.getCause(); while (cause != null) { cause.printStackTrace(printWriter); cause = cause.getCause(); } printWriter.close(); addMessage(null, writer.toString());
try { File root = context.getExternalFilesDir("log"); String filename = date + ".log"; File file = new File(root, filename); FileOutputStream fos = new FileOutputStream(file); fos.write(stringBuilder.toString().getBytes()); fos.close(); } catch (IOException e) { e.printStackTrace(); defaultUncaughtExceptionHandler.uncaughtException(thread, throwable); }
Intent intent = new Intent(context, UncaughtExceptionActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra("error", stringBuilder.toString()); context.startActivity(intent); System.exit(1);
}
private void addMessage(String key, Object obj) { if (obj instanceof String[]) { String[] list = (String[]) obj; ArrayList<String> array = new ArrayList<>(Arrays.asList(list)); stringBuilder.append(key).append("=").append(array.toString()).append("\n"); } if (key == null) { stringBuilder.append(obj) .append("\n"); } else { stringBuilder.append(key) .append("=") .append(obj) .append("\n"); } } }
|
UncaughtExceptionActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class UncaughtExceptionActivity extends AppCompatActivity { public static final String TAG = "UncaughtExceptionActivity";
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String msg = getIntent().getStringExtra("error");
ScrollView scrollView = new ScrollView(this); scrollView.setLayoutParams(new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT, ScrollView.LayoutParams.MATCH_PARENT)); TextView textView = new TextView(this); textView.setText(msg); scrollView.addView(textView);
setContentView(scrollView); }
@Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 0, 0, "重启").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); menu.add(0, 1, 0, "上传").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); return super.onCreateOptionsMenu(menu); }
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case 0: Intent intent = new Intent(this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); System.exit(1);
case 1: Toast.makeText(this, "已上传!", Toast.LENGTH_SHORT).show(); } return true; } }
|
MyApplication.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import android.app.Application;
public class MyApplication extends Application { public static final String TAG = "MyApplication";
@Override public void onCreate() { super.onCreate(); MyUncaughtExceptionHandler.getInstance(MyApplication.this).init(); } }
|
AndroidManifest.xml
1 2 3 4 5 6 7 8 9
| <application android:name=".MyApplication" ......>
<activity android:label="崩溃异常" android:name=".UncaughtExceptionActivity" />
</application>
|