天天看點

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();
    }
}