Monitoring of uncaught exceptions in the JAVA layer in android

In Android, the java virtual machine sets a default UncaughtExceptionHandler for each process to handle exceptions that are not try catch in this process, so as long as the UncaughtExceptionHandler interface is implemented, we can catch the global uncaught exception by ourselves Exceptions can be recorded and dealt with here to help us better improve the stability of the app.

  1. For exceptions thrown by sub-threads, after using UncaughtExceptionHandler to catch them, the app will not crash due to sub-thread exceptions
  2. For exceptions thrown by the main thread, you need to use the following processing to prevent the app from crashing
 if (thread == Looper.getMainLooper().getThread()) {
    
    
      while (true) {
    
    
        try {
    
    
           Looper.loop();
        } catch (Throwable throwable) {
    
    
            //...
        }
     }
}

Implement a CrashHandler class to monitor the crash of java layer code


import android.content.Context;
import android.os.Looper;
import android.util.Log;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import androidx.annotation.NonNull;

class CrashHandler implements Thread.UncaughtExceptionHandler {
    
    
    private static final String TAG = "CrashHandler";

    private Context mContext;

    public void init(Context context) {
    
    
        mContext = context;
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(@NonNull Thread thread, @NonNull Throwable e) {
    
    
        //处理主线程的异常,让Looper重新开始轮询
        if (thread == Looper.getMainLooper().getThread()) {
    
    
            while (true) {
    
    
                try {
    
    
                    Log.i(TAG, "uncaughtException: start");
                    dumpException(e);
                    Looper.loop();
                    Log.i(TAG, "uncaughtException: end");
                } catch (Throwable throwable) {
    
    
                    Log.i(TAG, "uncaughtException: " + thread.getName() + " thread get " + throwable);
                }
            }
        }
        // 非主线程的异常,不需要特殊处理
        Log.i(TAG, "uncaughtException: " + thread.getName() + " thread get " + e);
        dumpException(e);
    }

    private void dumpException(Throwable throwable) {
    
    
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis()));
        File file = new File(mContext.getCacheDir() + "/" + time);
        Log.i(TAG, "dumpException: mContext.getCacheDir()" + mContext.getCacheDir());
        try {
    
    
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            pw.println(time);
            pw.println();
            throwable.printStackTrace(pw);
            pw.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

Initialize the exception handler when the Application is initialized

        CrashHandler crashHandler = new CrashHandler();
        crashHandler.init();

But you need to pay attention when using this method. If the main thread keeps crashing and we keep re-polling through Looper.loop(), the app will become unresponsive.
For the crash exception of the java layer, we can use the PrintWriter class to output the call stack of the code to a file for saving. The saved information can be reported to the cloud for device location problems, see the function (dumpException).

Guess you like

Origin blog.csdn.net/liu_12345_liu/article/details/111305549