Android实现多次闪退清除数据

背景

很多时候由于后台返回的数据异常,可能会导致App闪退。而如果这些异常数据被App本地缓存下来,那么即使杀掉进程重新进入还是会发生闪退。唯一的解决方法就是清除App数据,但是用户可能没有这个意识或者嫌麻烦就直接不再使用了,这是我们无法接受的。在使用淘宝、追书神器等App时我发现有时候它们也会连续闪退,但是往往闪退三次后就恢复正常了,所以一般成熟的App都会做连续闪退三次后清除缓存数据的工作。而目前笔者搜不到有哪篇blog来讲这方面的事情,所以就姑且由我来讲讲此事,为希望提高App用户体验的朋友提供些许参考。

ACRA

为了能够在闪退的时候做一些事情,我们可以使用ACRA,这是Github上的一个开源项目,允许使用者设置一些Sender在App闪退的时候做一些事情。具体使用可以直接参考Github。如果不希望使用ACRA,那么也可以自己实现一个UncachedExceptionHandler并替换系统默认的Handler,并在这个Handler里面对数据进行处理。

实现清除数据

ACRA提供了自己的一些Sender,如使用系统邮件客户端向指定邮箱发送邮件的EmailIntentSender。而我们希望记录闪退次数和清除数据则需要implements ReportSender接口。

public class CrashHandler implements ReportSender {
    @Override
    public void send(Context context, CrashReportData errorContent) throws ReportSenderException {
        Timber.i("闪退,检查是否需要清空数据");
        new CrashModel().checkAndClearData();
    }
}

这里我们写了一个CrashModel用来记录闪退次数和时间决定是否需要清空数据,具体代码如下。 由于在ReportSender的时候无法打开其它线程,所以我们无法使用SharedPerferences来清理数据(打开SP的时候其实打开了一个新线程)。为此需要找到数据缓存的位置并将文件删除。同样道理,记录闪退时间也只能通过文件记录。当然,你可以选择一些文件不进行删除,如用户信息等不太容易出问题的数据。

public class CrashModel {

    private static final String KEY_CRASH_TIMES = "crash_times";
    private static final String CRASH_TIME_FILE_NAME = "crash_time";
    //不能通过App.getPackageName来获取包名,否则会有问题,只能默认为cn.campusapp.campus。所以对于debug或者运营版本,清数据会把release的清掉
    private static final String FILE_DIR = String.format("/data/data/%s/", BuildConfig.APPLICATION_ID);
    private static final String ACCOUNT_FILE_NAME = String.format("%s%s", FILE_DIR, "shared_prefs/account_pref.xml");
    private static ArrayList<String> FILES_DONTNEED_DELETE = new ArrayList<>();  //该目录中的文件不会被删除

    static {
        FILES_DONTNEED_DELETE.add(ACCOUNT_FILE_NAME);  //目前账号信息文件不会被删除,但是会手动改变数据,只保留userId  accessToken 和school
    }

    protected ArrayList<Long> mCrashTimes;
    Gson gson = new Gson();
    private File mFileDir;

    public CrashModel() {
        mFileDir = new File(FILE_DIR);
        mCrashTimes = readCrashTimes();
        if (mCrashTimes == null) {
            mCrashTimes = new ArrayList<>();
            storeCrashTimes(mCrashTimes);
        }
    }

    public void checkAndClearData() {
        long timeNow = System.currentTimeMillis();

        if (checkClearData(timeNow, new ArrayList<>(mCrashTimes))) {
            Timber.i("已经在5分钟之内有三次闪退,需要清理数据");
            try {
                clearData();
            } catch (Exception e) {
                Timber.e(e, "清空所有数据失败");
            }
        } else {
            mCrashTimes.add(timeNow);
            storeCrashTimes(mCrashTimes);
            Timber.i("此次不需要清空数据, %s", gson.toJson(mCrashTimes));
        }
    }

    private void storeCrashTimes(ArrayList<Long> crashTimes) {
        try {
            String str = gson.toJson(crashTimes);
            Files.writeToFile(mFileDir, CRASH_TIME_FILE_NAME, str);
        } catch (Exception e) {
            Timber.e(e, "保存闪退时间失败");
        }

    }

    private ArrayList<Long> readCrashTimes() {
        try {
            String timeStr = Files.readFileContent(mFileDir, CRASH_TIME_FILE_NAME);
            return gson.fromJson(timeStr, new TypeToken<ArrayList<Long>>() {
            }.getType());
        } catch (Exception e) {
            Timber.e(e, "读取闪退时间失败");
        }
        return null;
    }

    /**
     * 检查是否需要清空数据,目前的清空策略是在5分钟之内有三次闪退的就清空数据,也就是从后往前遍历,只要前两次闪退发生在5分钟之内,就清空数据
     *
     * @return
     */
    private boolean checkClearData(long time, ArrayList<Long> crashTimes) {
        Timber.i(gson.toJson(crashTimes));
        int count = 0;
        for (int i = crashTimes.size() - 1; i >= 0; i--) {
            long crashTime = crashTimes.get(i);
            if (time - crashTime <= 5 * 60 * 1000) {
                count++;
                if (count >= 2) {
                    break;
                }
            }
        }
        if (count >= 2) {
            //在5分钟之内有三次闪退,这时候需要清空数据
            return true;
        } else {
            return false;
        }
    }

    /**
     * 清空数据,包括数据库中的和SharedPreferences中的
     *
     * @throws Exception
     */
    private void clearData() throws Exception {
        Timber.i("开始清理数据");
        Files.deleteFilesExceptSomeInDirectory(mFileDir, FILES_DONTNEED_DELETE);
    }

}

然后我们需要将CrashHandler 添加到ACRA的异常处理Sender列表中。在你的Application类中添加如下代码。

@ReportsCrashes(
		  //一些ACRA的设置,具体参考ACRA文档,因为我们使用自定义Sender,所以这里完全可以不用设置
        //mailTo = "[email protected]",
        //mode = ReportingInteractionMode.TOAST,
        //resToastText = R.string.crash_toast_text
)
public class App extends Application {

    @Override
    public void onCreate() {
    	if (!BuildConfig.DEBUG) {  //这里我判断只有在非DEBUG下才清除数据,主要是为了在开发过程中能够保留线程。
                ACRA.init(APPLICATION_CONTEXT);
                CrashHandler handler = new CrashHandler();
              	ACRA.getErrorReporter().setReportSender(handler);  //在闪退时检查是否要清空数据
        }

    }
}

总结

以上即为实现多次闪退后清除数据的实现,希望大家开发的App Bug越来越少,鲁棒性越来越强。

时间: 2024-08-24 13:33:46

Android实现多次闪退清除数据的相关文章

Android中处理崩溃闪退错误

Android中处理崩溃闪退异常 大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了崩溃现象,开发者应该及时获取在该设备上导致崩溃的信息,这对于下一个版本的bug修复帮助极大,所以今天就来介绍一下如何在程序崩溃的情况下收集相关的设备参数信息和具体的异常信息,并发送这些信息到服务器供开发者分析和调试程序. 我们需要的是软件有一个全局的异常捕获器,当出

android studio安装后闪退

最近想把以前项目的android代码工程从Eclipse 转移到android studio中,下载谷歌最近的android studio安装包2.3版本安装后,打开android studio,程序闪退,在网上也找了好多答案,可是一一试过后,都不能用,最近FQ到google,搜索,找到问题原因,原因是JDK版本太低,我本机原来的JDK版本是1.7,随后下载安装JDK1.8,安装后,可以正常打开android studio. 转载此文,请注明来源,谢谢

JAVA Eclipse开发Android程序会经常闪退是怎么回事

类没有new就直接用会闪退,比如下面我在前面声明了ClientSocket的类,点击连接按钮之后,如果不先new就直接Connect就会闪退 ? 你在当前页面创建findViewById的时候,如果找不到指定的ID也会闪退,比如我要查找指定的ID为btnMoveL_SetA,当写错的时候也会有问题,而XML本身不会报错,假如ID确实存在,只不过不在这个页面的话. ? 还有必须是点击按钮之后,根据ID寻找界面控件-获取控件内容-转换成字符串/文本,而不能在界面onCreate的时候完成第一步的绑定

开发android过程中eclipse闪退解决

有一次eclipse崩溃了,然后再双击就无法打开了.换了几个版本也是如此. 后来找到了这个方法:删除文件 [workspace]/.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi 原来是workspace的问题. 当然还有一个办法就是换一个workspace.

Android常见崩溃或闪退的问题描述及原因总结

1.nullpointer——就是使用一个对象的时候还没有对其进行初始化导致该问题 一般在何种情况下容易出现呢? (1)父窗口+子窗口同时出现的,父窗口因为某种原因消掉了,子窗口还在,操作子窗口找不到父窗口的pid,就会出现问题 (2)加载过程中进行刷新或者其他点击操作,可能某种资源还没有初始化成功,就会出现该问题 (3)异常情况下,比如断网了,比如需要连接的设备没有连接,则相应资源拿不到,此时点击某些按钮,也会出现该问题 2.OOM——在视频\图片的来回切换,比如横竖屏的来回切换过程中比较容易

解决Android出现闪退

Android项目中经常闪退(anr)原因有很多种,各种没有捕获的异常都会导致项目的崩溃,对于此问题除了在写代码是要考虑全面,并对可能出现 的Exception进行捕获,同时也可以设置一个全局异常捕获的机制来保证你的疏忽(对应该捕获的异常没有做处理).具体步骤如下: 1.首先创建一个Handler 继承java.lang.Thread.UncaughtExceptionHandler: //未捕获异常    @Override    public void uncaughtException(T

升级iOS8和iOS9系统后,保险箱Pro、私人保险箱、私密相冊打开就闪退的官方解决方式

升级iOS8和iOS9.iOS10系统后,保险箱Pro.私人保险箱.私密相冊打开就闪退的官方解决方式 查看设备iOS操作系统版本号号办法:iPhone/iPad->设置->通用->关于本机->版本号 a.假设iPhone/iPad操作系统是iOS8.3之后(比方iOS8.3.iOS8.4.iOS9.iOS10),则关闭全部网络或开启飞行模式,看保险箱Pro还闪退不.假设不闪退,则立即进入闪退app(保险箱Pro.私人保险箱.私密相冊).上传全部照片和视频到手机系统相冊.以后使用这个

升级iOS8系统后,保险箱Pro、私人保险箱、私密相册打开就闪退的官方解决方案

  写在前面的话: 1.   本文适用条件    适用于:您的保险箱Pro.私人保险箱.私密相册在iPhone或iPad升级到iOS8系统后,一打开就闪退,无法进入程序:app图标如下:             2.   不要删除闪退app    请不要删除闪退app,因为数据都在里面:如果你不小心删除了,请检查删除app前你是否将iPhone或iPad数据备份到电脑iTunes或iCloud上,如果备份过,是可以恢复闪退app数据到iPhone或iPad的,请立即联系技术支持: 3.   官方

【重要】安卓微信闪退,非清空数据法解决,不破坏聊天记录【完善中】

前言 [本文不建议跳读.少读] 之前研究过微信记录的恢复办法,对其存储结构稍有了解,今天又遇到闪退的问题,真想用现在流行的话说:日了狗了. 于是乎,到网上搜索了一番,全是让你清除数据.重装.卸载之类的.对于这些方法,我只想说,简直就是害人.如果你是刚装的微信这样做,或者聊天记录对你来说不重要,那么你就去折腾.但是,度过聊天记录对你来说很重要,那么,请慎重! 本文通过自己的探索,寻求了闪退的终极解决办法,如果还不能解决,需要保全聊天记录的,可以联系我来帮您导出,切勿手贱! 症状描述 最近老是提示空