Save the log file to the sdcard, directory: crash folder under the sdcard root directory
First, set permissions, no permissions to the final effect
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>Two classes must be created to collect error information for exceptionsHere is the CrashHandler class
Here is the CrashApplication class/** * Created by BAIPEI on 2017/12/5. */ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.Thread.UncaughtExceptionHandler; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.os.Environment; import android.os.Looper; import android.util.Log; import android.widget.Toast; public class CrashHandler implements UncaughtExceptionHandler{ private static final String TAG = "CrashHandler"; private Thread.UncaughtExceptionHandler mDefaultHandler;// System default UncaughtException processing class private static CrashHandler INSTANCE = new CrashHandler();// CrashHandler instance private Context mContext;// Context object for program private Map<String, String> info = new HashMap<String, String>();// Used to store device information and exception information private SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd-HH-mm-ss");// Used to format the date as part of the log file name /** Make sure there is only one instance of CrashHandler */ private CrashHandler() { } /** Get CrashHandler instance, singleton mode */ public static CrashHandler getInstance() { return INSTANCE; } /** * Initialization * * @param context */ public void init(Context context) { mContext = context; mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// Get the system default UncaughtException processor Thread.setDefaultUncaughtExceptionHandler(this);// Set this CrashHandler as the program's default processor } /** * When UncaughtException occurs, it goes into the overridden method to handle it */ public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { // Let the default exception handler of the system handle the custom unhandled mDefaultHandler.uncaughtException(thread, ex); } else { try { Thread.sleep(3000);// If processed, allow the program to continue running for 3 seconds before exiting, ensuring that the file is saved and uploaded to the server } catch (InterruptedException e) { e.printStackTrace(); } // Exit the program android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } } /** * Customize error handling, collect error information and send error reports. * * @param ex * Exception Information * @return true If the exception information is handled; otherwise, false is returned. */ public boolean handleException(Throwable ex) { if (ex == null) return false; new Thread() { public void run() { Looper.prepare(); Toast.makeText(mContext, "I'm sorry,Program Exception,About to quit", Toast.LENGTH_SHORT).show(); Looper.loop(); } }.start(); // Collect device parameter information collectDeviceInfo(mContext); // Save Log File saveCrashInfo2File(ex); return true; } /** * Collect device parameter information * * @param context */ public void collectDeviceInfo(Context context) { try { PackageManager pm = context.getPackageManager();// Get Package Manager PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);// Get information about the app, the main Activity if (pi != null) { String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; info.put("versionName", versionName); info.put("versionCode", versionCode); } } catch (NameNotFoundException e) { e.printStackTrace(); } Field[] fields = Build.class.getDeclaredFields();// Reflection mechanism for (Field field : fields) { try { field.setAccessible(true); info.put(field.getName(), field.get("").toString()); Log.d(TAG, field.getName() + ":" + field.get("")); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } private String saveCrashInfo2File(Throwable ex) { StringBuffer sb = new StringBuffer(); for (Map.Entry<String, String> entry : info.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\r\n"); } Writer writer = new StringWriter(); PrintWriter pw = new PrintWriter(writer); ex.printStackTrace(pw); Throwable cause = ex.getCause(); // Loop to write all exception information to the writer while (cause != null) { cause.printStackTrace(pw); cause = cause.getCause(); } pw.close();// Remember to close String result = writer.toString(); sb.append(result); // Save File long timetamp = System.currentTimeMillis(); String time = format.format(new Date()); String fileName = "crash-" + time + "-" + timetamp + ".log"; if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { try { File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "crash"); Log.i("CrashHandler", dir.toString()); if (!dir.exists()) dir.mkdir(); FileOutputStream fos = new FileOutputStream(new File(dir, fileName)); fos.write(sb.toString().getBytes()); fos.close(); return fileName; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return null; } }
import android.app.Application; /** * Created by BAIPEI on 2017/12/5. */ public class CrashApplication extends Application { @Override public void onCreate() { super.onCreate(); CrashHandler crashHandler = CrashHandler.getInstance(); crashHandler.init(this); } }Here's MainActivity, because we want to make an exception, if we don't call that exception here,That exception won't work, and we won't get the results we wantHere is the layout file, which is also a click eventimport android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button mBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { mBtn = (Button) findViewById(R.id.btn); mBtn.setOnClickListener(this); } @Override public void onClick(View v) { //Call this exception in a click event throw new RuntimeException("String"); } }<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="bwie.com.crashhandler_diqitian.MainActivity"> <Button android:id="@+id/btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="click"/> </android.support.constraint.ConstraintLayout>Don't forget to put AndroidManifest.xml Change the application inside<application android:name=".CrashApplication" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity"> ... </activity> </application>