Android 全局错误日志捕获的工具类

--------------------- CrashHandler ---------------------
public class CrashHandler implements Thread.UncaughtExceptionHandler {


    private static CrashHandler mInstance;
    private Thread.UncaughtExceptionHandler mDefautHandler;
    private static final String TAG = "CrashHandlerTag";

    private CrashHandler() {

    }

    public static CrashHandler getInstance() {
        if (mInstance == null) {
            synchronized (CrashHandler.class) {
                if (mInstance == null) {
                    mInstance = new CrashHandler();
                }
            }
        }
        return mInstance;
    }


    public void init() {
        mDefautHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }


    @Override
    public void uncaughtException(Thread thread, Throwable ex) {


        if (ex != null) {

            // 收集设备信息、版本信息、异常信息
            String info = collectDeviceInfo(BaseApplication.getInstance().getApplicationContext(), ex);
            // 本地存储
            saveInfo(info);
            Log.d(TAG, "已捕获到异常 ");

            //不进行延时处理的话kill不能执行完成
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
                    // 异常已经处理,结束进程
                    Process.killProcess(Process.myPid());
                    System.exit(1);

                }
            }, 100);

        } else {
            Log.d(TAG, "没有捕获异常 ");
            //没有处理还交给系统默认的处理器
            if (mDefautHandler != null) {
                mDefautHandler.uncaughtException(thread, ex);
            }
        }

    }

    /**
     * 收集设备信息
     *
     * @param c
     * @param ex
     */
    private String collectDeviceInfo(Context c, Throwable ex) {
        Map<String, String> infos = new HashMap<>();
        //收集版本信息
        try {
            PackageManager pm = c.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(c.getPackageName(), PackageManager.GET_ACTIVITIES);
            if (pi != null) {
                String versionCode = pi.versionCode + "";
                String versionName = TextUtils.isEmpty(pi.versionName) ? "没有版本名称" : pi.versionName;
                infos.put("versionCode", versionCode);
                infos.put("versionName", versionName);
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        //收集设备信息
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                infos.put(field.getName(), field.get(null).toString());
            } catch (Exception e) {

            }
        }

        //收集异常信息
        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();

        // 转化为字符串
        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");
        }
        sb.append(result);

        return sb.toString();
    }

    /**
     * 保存异常信息到本地
     * @param infos
     */
    private void saveInfo(String infos) {
        Log.d(TAG, "输出log日志: " + infos);
        // 把采集到的信息写入到本地文件
        LogLocalUtils.writeLogToFile(infos);

    }


}

--------------------- LogLocalUtils---------------------

public class LogLocalUtils {

    private static final String TAG = "LogLocalUtils";

    private static String basePath = Environment.getExternalStorageDirectory().getPath()
            + "/Android/data/com.example.app/log/";

    /**
     * 开启全局错误日志捕获
     */
    public static void openErrorCatch() {
        CrashHandler.getInstance().init();
    }

    /**
     * 记录用户在什么时间启动的App
     * 登录成功进入菜单界面记录一次
     */
    public static void startAppRecord() {
        writeLogToFile("----------> 登录成功,进入到菜单界面了... <----------");
    }

    /**
     * 保存日志信息到log.txt文件中
     * 每次调用往log.txt文件中添加信息
     *
     * @param logMessage 日志内容
     */
    public static void writeLogToFile(String logMessage) {

        try {
            //新建多级目录
            File sdCardDir = new File(basePath);
            if (!sdCardDir.exists() && !sdCardDir.mkdirs()) {
                try {
                    sdCardDir.createNewFile();
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.d(TAG, "writeLogToFile-sdCardDir.createNewFile():" + e.getMessage());
                }
            }
            //一个月创建一次日志文件
            String yearMonth = new SimpleDateFormat("yyyyMM").format(new Date());
            String fileName = "log-" + yearMonth + ".txt";
            String logFilePath = basePath + fileName;
            FileOutputStream outputStream = new FileOutputStream(new File(logFilePath), true);
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date());
            String message =
                    "<---------------------------start---------------------------->"
                            + "\n"
                            + "\n"
                            + time + "\n"
                            + "日志信息:" + logMessage + "\n"
                            + "\n"
                            + "<---------------------------end---------------------------->"
                            + "\n"
                            + "\n"
                            + "\n"
                            + "\n";
            outputStream.write(message.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "writeLogToFile-error: " + e.getMessage());
        }

    }


    /**
     * 保存异常信息文件到sdcard中
     * 每次调用创建新文件
     *
     * @param errorLog 日志内容
     */
    public static void writeLogToSdCard(String errorLog) {

        String sdPath = basePath + "/error_log";
        //新建多级目录
        File sdCardDir = new File(sdPath);

        if (!sdCardDir.exists() && !sdCardDir.mkdirs()) {
            
            try {
                sdCardDir.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
                Log.d(TAG, "sdCardDir.createNewFile()-error:" + e.getMessage());
            }

        }

        try {
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
                    .format(new Date());
            String fileName = time + ".txt";
            //新建文件
            File saveFile = new File(sdCardDir, fileName);

            if (!saveFile.exists()) {
                saveFile.createNewFile();
            }

            final FileOutputStream outStream = new FileOutputStream(saveFile);

            if (!TextUtils.isEmpty(errorLog)) {
                String message =
                        "<---------------------------start---------------------------->"
                                + "\n"
                                + "\n"
                                + time + "\n"
                                + "日志信息:" + errorLog + "\n"
                                + "\n"
                                + "<---------------------------end---------------------------->"
                                + "\n";
                outStream.write(message.getBytes());
                outStream.close();
            }


            Log.d(TAG, "日志输出成功! ");

        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "流写入错误:" + e.toString());
        }
    }
}

如何使用?

启动全局日志捕获的事件(出现异常崩溃后,日志会输出到sdcard中):

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        //开启全局错误日志捕获
        LogLocalUtils.openErrorCatch();
    }
}

记录App启动时间的日志(看个人情况,也可以在Application中记录):

public class HomeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        //登录成功进入Home界面后,记录一条App启动的日志
        LogLocalUtils.startAppRecord();
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Android应用中,可以通过全局捕获异常来避免应用闪退。可以通过以下步骤实现: 1. 创建一个自定义的Application类,并在其中重写`Thread.UncaughtExceptionHandler`接口的`uncaughtException`方法。 2. 在`uncaughtException`方法中处理全局异常,例如记录异常信息、上传日志或者进行其他处理操作。 3. 在Application的onCreate方法中,将自定义的UncaughtExceptionHandler设置为默认的异常处理器。 下面是一个示例代码: ```java public class MyApplication extends Application implements Thread.UncaughtExceptionHandler { @Override public void onCreate() { super.onCreate(); // 设置全局异常处理器 Thread.setDefaultUncaughtExceptionHandler(this); } @Override public void uncaughtException(Thread thread, Throwable ex) { // 处理全局异常,例如记录异常信息、上传日志等操作 Log.e("MyApplication", "Uncaught Exception: " + ex.getMessage()); // 重启应用或者执行其他操作 restartApp(); } private void restartApp() { // 重启应用,可以根据实际需求来实现 Intent intent = new Intent(getApplicationContext(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pendingIntent); // 退出应用 System.exit(0); } } ``` 记得在AndroidManifest.xml文件中将自定义的Application类配置为应用的默认Application类: ```xml <application android:name=".MyApplication" ...> ... </application> ``` 通过以上步骤,当应用发生未捕获异常时,会调用自定义的异常处理方法,你可以在其中进行相应的处理操作,例如记录异常信息、上传日志等。最后,你可以选择重启应用或者执行其他操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

窗台的花花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值