As you all know, Android phones and devices are very different now, and programs that run well on the simulator may crash when installed on a particular phone.
It is impossible for a developer to buy all the devices and debug them one by one, so after the program is released, if there is a crash, the developer should get it in time.
Prepare information that causes crashes, which will be very helpful for the next version of BUG repair, so today I'll show you how to collect related devices in case of program crashes.
Parameter information and specific exception information are sent to the server for developers to analyze and debug the program.
When an exception is not captured by the software, the system pops up the default forced shutdown dialog box.
Of course, we don't want users to see this phenomenon. It's really a blow to the user's mind, and it's not helpful for us to repair BUG. What we need is soft
It has a global exception trap. When an exception occurs that we haven't found, it captures the exception, records the exception information, and uploads it to the server for public distribution.
This is the specific reason for the anomaly.
Next we'll implement this mechanism, but first we'll look at the following two classes: android.app.Application and
java.lang.Thread.UncaughtExceptionHandler.
Application: Used to manage the global state of an application. When the application starts, the application will be created first, and then it will be started according to the situation (Intent).
Corresponding Activity and Service. In this example, an uncovered exception handler will be registered in the custom enhanced version of Application.
Thread.UncaughtException Handler: Threads do not capture exception handlers to handle uncovered exceptions. If an uncovered exception occurs in the program, it will bounce by default.
Force the dialog box to close out of the system. We need to implement this interface and register it as default uncovered exception handling in the program. This allows you to do something when uncovered exceptions occur
Personalized exception handling operations.
(1) New java file, CrashHandler.java implements Thread. UncaughtException Handler, which enables us to handle the main members of uncovered exceptions.
The code is as follows:
public class CrashHandler implements UncaughtExceptionHandler { public static final String TAG = "CrashHandler"; // CrashHandler instance private static CrashHandler INSTANCE = new CrashHandler(); // Context object of program private Context mContext; // System default UncaughtException processing class private Thread.UncaughtExceptionHandler mDefaultHandler; // Used to store device information and exception information private Map<String, String> infos = new HashMap<String, String>(); // Used to format the date as part of the log file name private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); /** Guarantee that there is only one CrashHandler instance */ private CrashHandler() { } /** Get the CrashHandler instance, singleton mode */ public static CrashHandler getInstance() { return INSTANCE; } /** * Initialization * * @param context */ public void init(Context context) { mContext = context; // Get the default UncaughtException processor for the system mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); // Set the CrashHandler as the default processor for the program Thread.setDefaultUncaughtExceptionHandler(this); } /** * When UncaughtException occurs, the function is transferred to handle it. */ @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { // If the user does not handle it, let the default exception handler of the system handle it. mDefaultHandler.uncaughtException(thread, ex); } else { try { Thread.sleep(3000); } catch (InterruptedException e) { Log.e(TAG, "error : ", e); } // Exit the program, comment the restart program code below android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); // Reboot the program and annotate the exit procedure above Intent intent = new Intent(); intent.setClass(mContext,MainActivity.class); intent.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); android.os.Process.killProcess(android.os.Process.myPid()); } } /** * Custom error handling, error information collection, error reporting and other operations are completed here. * * @param ex * @return true: If the exception information is processed; otherwise false is returned */ private boolean handleException(Throwable ex) { if (ex == null) { return false; } // Use Toast to display exception information new Thread() { @Override public void run() { Looper.prepare(); Toast.makeText(mContext, "Sorry, the program is out of order.", Toast.LENGTH_LONG).show(); Looper.loop(); } }.start(); // Collect equipment parameter information collectDeviceInfo(mContext); // Save log files saveCrashInfo2File(ex); return true; } /** * Collect equipment parameter information * @param ctx */ public void collectDeviceInfo(Context ctx) { try { PackageManager pm = ctx.getPackageManager(); PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); if (pi != null) { String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; infos.put("versionName", versionName); infos.put("versionCode", versionCode); } } catch (NameNotFoundException e) { Log.e(TAG, "an error occured when collect package info", e); } Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); infos.put(field.getName(), field.get(null).toString()); Log.d(TAG, field.getName() + " : " + field.get(null)); } catch (Exception e) { Log.e(TAG, "an error occured when collect crash info", e); } } } /** * Save error information to file * * @param ex * @return Return the file name for easy transfer to the server */ private String saveCrashInfo2File(Throwable ex) { StringBuffer sb = new StringBuffer(); for (Map.Entry<String, String> entry : infos.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\n"); } Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); ex.printStackTrace(printWriter); Throwable cause = ex.getCause(); while (cause != null) { cause.printStackTrace(printWriter); cause = cause.getCause(); } printWriter.close(); String result = writer.toString(); sb.append(result); try { long timestamp = System.currentTimeMillis(); String time = formatter.format(new Date()); String fileName = "crash-" + time + "-" + timestamp + ".log"; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { String path = "/sdcard/crash/"; File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } FileOutputStream fos = new FileOutputStream(path + fileName); fos.write(sb.toString().getBytes()); fos.close(); } return fileName; } catch (Exception e) { Log.e(TAG, "an error occured while writing file...", e); } return null; } } (2)Finish this. CrashHandler After that, we need to be in one Application Let it run in the environment, so we inherit it android.app.Application,Add self //My code, CrashApplication.java code is as follows: package com.scott.crash; import android.app.Application; public class CrashApplication extends Application { @Override public void onCreate() { super.onCreate(); CrashHandler crashHandler = CrashHandler.getInstance(); crashHandler.init(getApplicationContext()); } }
(3) Because we need to save device parameters and specific exception information to SDCARD when we encounter an exception in the CrashHandler above, we need to
Add read-write SDCARD privileges to Android Manifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>