天天看点

SharedPreferences 实现栈与队列

SharedPreferences 实现栈与队列

上个星期,脑袋灵感想想用SharedPreferences 实现android的app的任务栈形式,又想到Acivity singleTop模式,

singleTop

当你要启动的Activity已经存在一个实例在当前任务栈的栈顶,就直接使用该实例,否则重新创建一个新的实例并放在栈顶。即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例。

实现思路参考Acivity Task:

研究使用栈与队列组合实现,我使用游标仿单向循环链表方式实现。适合使用环境:例如搜索历史,浏览历史记录,缓存网络数据等等使用。

1.不存在栈中,则压入栈顶。

2.若在栈顶,则更新数据

3.在在栈中,不在栈顶,则移到整个栈,把当前记录移到到栈顶。

可能存在bug,之前发现游标跳空或数据丢失,已经修复,目前测试没有发现什么问题。

当然使用数据库也可以实现,利用时间截,使用order by时间截来判断,比较与当前时间最小的就是栈顶,比较与当前时间最大的就是栈底,write数据时先查询(select)内容的唯一key,若存在(exist)则表明在栈中,则更新(update)内容与时间截。若不存在,先判断下限制记录是否存满了(比如只能存放5条记录),判断下数据库是否有5条记录,若不够5条则插入(insert);若已经5条,则查询(select)比较与当前时间最大的row,执行数据更新(覆盖)。或者使用

轻量级缓存框架——ACache(ASimpleCache)
SharedPreferences 实现栈与队列
package cn.credit;

import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.dooer.andr.util.NetUtil;

/**
 * Created by Credit on 2017/1/3.
 */

public class SearchHistoryDao {
    private static String TAG = "SearchHistoryDao";
    /**
     * 离线保存文件名
     */
    private static String config_name = "search_savedata";
    /**
     * 默认只保存10条缓存数据
     */
    private static int RecordNum = ;
    public static String HISTORY_KEY = "history_string";
    public static String TYPE_KEY = "history_type";
    public static String INDEX_POINT = "index_point";

    private static String RECORD_NUM = "RecordNum";
    /**
     * 空下标
     */
    private static int isEmptyIndex = -;
    /**
     * 实例对象
     */
    private static SearchHistoryDao instance = null;
    private static SharedPreferences sp = null;
    private static Context mContext = null;

    public static synchronized SearchHistoryDao getInstance(Context context) {
        if (instance == null) {
            instance = new SearchHistoryDao();
            mContext = context.getApplicationContext();
            sp = context.getSharedPreferences(config_name, context.MODE_PRIVATE);

            /**
             *  默认只保存10条缓存数据
             */
            RecordNum = sp.getInt(RECORD_NUM, RecordNum);
        }
        return instance;
    }

    /**
     * 获取名称最近N()条记录列表
     *
     * @return
     */
    public List<String> readNameListHistory() {

        List<String> list = new ArrayList<>();
        int point = sp.getInt(INDEX_POINT, );
        String str;
        for (int i = , n = point; i < RecordNum; i++) {
            /**
             * 游标还原最后的状态
             */
            n = n >  ? (--n) : (--n + RecordNum) % RecordNum;

            str = sp.getString(HISTORY_KEY + n, "");
            if (!TextUtils.isEmpty(str)) {
                list.add(str);
            }


        }
        Log.e(TAG, "readListHistory:获取最近N()条记录列表 " + list.toString());
        return list;
    }

    /**
     * 获取详细-最近N()条记录列表
     *
     * @return
     */
    public List<Map<String, String>> readDetailListHistory() {

        List<Map<String, String>> list = new ArrayList<>();
        int point = sp.getInt(INDEX_POINT, );
        String str;
        for (int i = , n = point; i < RecordNum; i++) {
            /**
             * 游标还原最后的状态
             */
            n = n >  ? (--n) : (--n + RecordNum) % RecordNum;

            str = sp.getString(HISTORY_KEY + n, "");
            if (!TextUtils.isEmpty(str)) {
                int t = sp.getInt(TYPE_KEY + n, );
                Map<String, String> m = new HashMap<>();
                m.put(HISTORY_KEY, str);
                m.put(INDEX_POINT, n + "");
                m.put(TYPE_KEY, t + "");
                list.add(m);
            }
        }
        return list;
    }

    /**
     * 根据KeyWord获取离线保存Type
     */
    public int readHistoryTypeByKeyWord(String str) {

        int mallIndex = getIndex(str);
        if (mallIndex != isEmptyIndex) {
            return sp.getInt(TYPE_KEY + mallIndex, );
        }
        return ;
    }

    /**
     * 根据index获取离线保存Type
     */
    public int readHistoryTypeByindex(int index) {

        return sp.getInt(TYPE_KEY + index, );
    }


    /**
     * 更新一条记录
     * 简单的虚拟栈形式压入,最新的页面数据压入栈顶,使用游标方式实现(单向循环链表)
     *
     * @param str
     * @return
     */
    public boolean writeHistory(String str, int type) {
        int networkState = NetUtil.getNetworkState(mContext);
        Log.e(TAG, "writeHistory:更新一条记录 " + networkState + "  str" + str);
        /**
         *判断是否是网络获取的数据,不必更新来自离线的数据
         */
        if (networkState != NetUtil.NETWORN_NONE) {
            /**
             获取最新状态游标
             */
            int point = sp.getInt(INDEX_POINT, );
            SharedPreferences.Editor editor = sp.edit();
            /**
             * 判断当前页面数据在栈中位置
             */
            int index = getIndex(str);
            /**
             * 判断当前页面数据,是否存在在栈中了
             */
            if (index != isEmptyIndex) {
                /**
                 * 不在栈顶?弹出位置移动整个栈位置,压入栈顶
                 *
                 * 最后栈顶==point - 1;
                 * 若不是空下标,则表明数据在游标中,而point==0时,则表明了游标完成了循环回到起始点,最后栈顶下标是 RecordNum-1;
                 */

                /**
                 * 栈底
                 */
                int l = ((point + ) + RecordNum) % RecordNum;

                Log.d(TAG, "writeHistory:  index:" + index + " point:" + point + " lastIndex:"
                        + ((point - ) + RecordNum) % RecordNum + " last Task:" + l);
                if (point >  && point -  != index) {

                    int n = index;
                    editor.putString(HISTORY_KEY + index, "");
                    editor.putInt(TYPE_KEY + index, );
                    int len = ((index - point) + RecordNum) % RecordNum;
                    for (int i = ; i <= len; i++) {
                        editor.putString(HISTORY_KEY + n, sp.getString(HISTORY_KEY + ((n - ) + RecordNum) % RecordNum, ""));
                        editor.putInt(TYPE_KEY + n, sp.getInt(TYPE_KEY + ((n - ) + RecordNum) % RecordNum, ));
                        n = n >  ? (--n) : (--n + RecordNum) % RecordNum;
                    }
                    if ((n != point -  && n != ) || l == n) {
                        editor.putString(HISTORY_KEY + n, "");
                        editor.putInt(TYPE_KEY + n, );
                    }


                    Log.e(TAG, "writeHistory: 不在栈顶?弹出位置移动整个栈位置,压入栈顶" + str);
                } else {

                    if ((point + RecordNum) % RecordNum == index) {
                        editor.putInt(INDEX_POINT, (point + ) % RecordNum);
                    }

                    if ((point + RecordNum) % RecordNum ==  && point != index) {
                        int n = index;
                        editor.putString(HISTORY_KEY + index, "");
                        editor.putInt(TYPE_KEY + index, );
                         前移
                        int len = ((index - point) + RecordNum) % RecordNum;
                        Log.e(TAG, "writeHistory: 在栈顶,(point + RecordNum) % RecordNum == 0  前移" + str);
                        for (int i = ; i < len; i++) {
                            editor.putString(HISTORY_KEY + n, sp.getString(HISTORY_KEY + (n - ), ""));
                            editor.putInt(TYPE_KEY + n, sp.getInt(TYPE_KEY + (n - ), -));
                            n = n >  ? (--n) : (--n + RecordNum) % RecordNum;
                        }
                    } else {
                        /**
                         * 在栈顶,更新数据就行
                         * 进入条件
                         * 1,point=0时,则index=RecordNum-1;
                         * 2.point>0时,则index=point-1;
                         */
                        Log.e(TAG, "writeHistory: 在栈顶,更新数据就行" + str);
                        editor.putInt(TYPE_KEY + index, type);
                        editor.commit();
                        return true;
                    }

                }
            }
            Log.e(TAG, "writeHistory: 压入栈顶" + str);
            /**
             * 压入栈顶
             */
            editor.putString(HISTORY_KEY + point, str);
            editor.putInt(TYPE_KEY + point, type);
            /**
             * 移动游标
             */

            editor.putInt(INDEX_POINT, (point + ) % RecordNum);
            editor.commit();
            return true;
        }
        Log.e(TAG, "writeHistory: 网络不能使用");
        return false;
    }

    private int getIndex(String ID) {
        int point = sp.getInt(INDEX_POINT, );
        String Did = "";
        /**
         * 判断ID是否存在了
         */
        for (int i = , n = point; i < RecordNum; i++) {
            /**
             * 游标还原最后的状态
             */
            n = n >  ? (--n) : (--n + RecordNum) % RecordNum;
            Did = sp.getString(HISTORY_KEY + n, "");
            if (!TextUtils.isEmpty(Did) && Did.equals(ID)) {
                return n;
            }
        }
        return isEmptyIndex;
    }

    /**
     * 设置缓存条数
     *
     * @param num
     */
    public void setRecordNum(int num) {
        sp.edit().putInt(RECORD_NUM, num).commit();
        RecordNum = num;
    }

    /**
     * 获取缓存条数
     *
     * @return
     */
    public int getRecordNum() {
        return sp.getInt(RECORD_NUM, RecordNum);
    }

    /**
     * 清除单条记录
     *
     * @param STR
     * @return
     */
    public int clearHistoryByKeyWord(String STR) {

        int index = getIndex(STR);
        if (index != isEmptyIndex) {
            SharedPreferences.Editor editor = sp.edit();
            editor.putString(HISTORY_KEY + index, "");
            editor.putInt(TYPE_KEY + index, );
            editor.commit();
        }
        return index;
    }

    /**
     * 清除全部记录
     */

    public void clearHistory() {
        // int point = sp.getInt(INDEX_POINT, 0);
/*
        for (int i = 0, n = point; i < RecordNum; i++) {
            n = n > 0 ? (--n) : (--n + RecordNum) % RecordNum;
            editor.putString(HISTORY_KEY + n, "");
            editor.putInt(TYPE_KEY + n, 1);
        }
        editor.putInt(INDEX_POINT, 0);*/
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.commit();
    }
}