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)

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