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