目录

  • 一、简介
  • 二、数据保存
  • 三、app重启

一、简介

在道长重做轨迹功能的过程中,产品经理提出由于app需要,不仅需要保证app长时间的运行在后台,而且保证被杀重新启动时恢复数据。之前道长已经分享保证app长时间的运行在后台,如果需要就点击传送门:Android:越来越难实现的进程保活。由于android对于系统安全和用户隐私越来越看重,现在也不能保证后台运行的app进程不被杀死,所以需要在app被杀时的时候做一下现场保护。当app重新启动时检测缓存并恢复数据。

二、数据保存

这里就需要做两个工作。一个是数据保存,另一个是检测app启动。
app进程被杀时有两种可能,一种是用户主动触发杀死正在运行的app;另外一种是系统杀死后台运行的app或者app崩溃。不管是被用户主动触发杀死还是被系统杀死都是不可检测的(PS:如果能被检测的话进程保活也就没必要做了,检测到被杀死重新拉起来就好了)。由于不知道app何时被杀时,一些app重启的数据就需要实时缓存。如果不是必要不要做这个,因为数据的实时缓存需要开一个service长时间运行在后台,对运行内存的开销还是比较大的。
具体的做法道长就不说了,每个app都有不一样的需求,至于怎么实现,道长还是有必要说一下的,每隔多少秒就把需要保存数据通过broadcast发送,然后开一个service接收数据进行保存。当然可以在service中开一个计时器,每隔多少秒就把从各处接受的数据进行保存。道长选择的是后一种方法。当然如果有大触看到这篇博客,有什么意见也可以提给道长。

三、app重启

app被杀掉重启和app启动流程都是可控的,每个app都有不同的启动流程道长也就不多说了(PS:你说什么了)。道长公司app重启之后会先判断是否已经启动过(设置一个状态,登录app打开,退出app关闭,如果登录时状态为打开就说明app不是正常关闭),如果不是正常关闭就判断一下是否有数据需要恢复。如果有的话就加载,如果没有的话就初始化数据。道长重点说一下崩溃杀死app,这会让用户体验非常不好,其实做了崩溃重启的处理只是做一些补救。道长分享一个不知道那个大牛写的工具类,代码如下:

public class CrashHandler implements Thread.UncaughtExceptionHandler {    public static final String TAG = "CrashHandler";    // 系统默认的UncaughtException处理类    private Thread.UncaughtExceptionHandler mDefaultHandler;    // CrashHandler实例    private static CrashHandler INSTANCE = new CrashHandler();    // 程序的Context对象    private Context mContext;    // 用来存储设备信息和异常信息    private Map<String, String> infos = new HashMap<String, String>();    // 用于格式化日期,作为日志文件名的一部分    private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss SSS");    private CrashHandler() {    }    /**     * 获取CrashHandler实例 ,单例模式     */    public static CrashHandler getInstance() {        return INSTANCE;    }    /**     * 初始化     *     * @param context     */    public void init(Context context) {        mContext = context;        // 获取系统默认的UncaughtException处理器        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();        // 设置该CrashHandler为程序的默认处理器        Thread.setDefaultUncaughtExceptionHandler(this);    }    /**     * 当UncaughtException发生时会转入该函数来处理     */    @Override    public void uncaughtException(Thread thread, Throwable ex) {        if (!handleException(ex) && mDefaultHandler != null) {            // 如果用户没有处理则让系统默认的异常处理器来处理            mDefaultHandler.uncaughtException(thread, ex);        } else {            try {                Thread.sleep(3000);            } catch (InterruptedException e) {                Log.e(TAG, "error : ", e);            }//            ARouter.getInstance().build("/module_login/SplashActivity").navigation();//            Intent intent = new Intent(this, Spla.class);//            PendingIntent restartIntent = PendingIntent.getActivity(//                    application.getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);            //退出程序            AlarmManager mgr = (AlarmManager)BaseApplication.getIns().getSystemService(Context.ALARM_SERVICE);            // 退出程序            android.os.Process.killProcess(android.os.Process.myPid());            System.exit(1);        }    }    /**     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.     *     * @param ex     * @return true:如果处理了该异常信息;否则返回false.     */    private boolean handleException(Throwable ex) {        if (ex == null) {            return false;        }        // 使用Toast来显示异常信息        new Thread() {            @Override            public void run() {                Looper.prepare();//                Toast.makeText(mContext, "很抱歉,程序出现异常即将退出.", Toast.LENGTH_LONG).show();                Looper.loop();            }        }.start();        // 收集设备参数信息//        collectDeviceInfo(mContext);        // 保存日志文件//        saveCrashInfo2File(ex);        return true;    }    /**     * 收集设备参数信息     *     * @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 (PackageManager.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);            }        }    }    /**     * 保存错误信息到文件中     *     * @param ex     * @return 返回文件名称, 便于将文件传送到服务器     */    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 {            String time = formatter.format(new Date());            String fileName = time + ".txt";            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                String path = "文件路径";                File dir = new File(path);                if (!dir.exists()) {                    dir.mkdirs();                }                FileOutputStream fos = new FileOutputStream(path + fileName);                fos.write(sb.toString().getBytes("UTF-8"));                fos.close();            }            return fileName;        } catch (Exception e) {            Log.e(TAG, "an error occured while writing file...", e);        }        return null;    }}

道长就说到这里,希望这篇博客对你有些帮助。

更多相关文章

  1. 一句话锁定MySQL数据占用元凶
  2. Android中的PID,TID和UID
  3. Android(安卓)Mosby MVP的使用
  4. ListView分页加载数据
  5. Android(安卓)SQLite 数据库详细介绍
  6. Android(安卓)截屏并保存
  7. Android应用程序的开机自启动
  8. Android(安卓)实现自定义圆环
  9. android android 在list view中插入一条广告

随机推荐

  1. Android MVP 构架初试
  2. Android 开发热门资料免费下载 110个
  3. Android(安卓)NDK入门
  4. Android基础总结之八:ContentProvider
  5. 【android学习笔记】关于相对布局Relativ
  6. Android ADT,SDK的安装,让人烦恼的在线方
  7. 安卓实现扫一扫识别数字
  8. 安卓学习
  9. 开源弹幕引擎·烈焰弹幕使(DanmakuFlameMa
  10. Android设备不用USB调试(使用TCP/IP调试)