上一节我们学习了如何对SharedPreferences的数据进行增删改查,由上一节我们可以知道SharedPreferences只能保存int、long、float、boolean、string和string的set集合,如果我们想要保存一个可序列化对象怎么办呢?要保存一个可序列化对象的集合又怎么办呢?同样如果要保存一个字节数组怎么办?以及其他类型的数组怎么办?接下来我们一一解决这些问题。
首先解决字节数组,一个思路就是将字节数组转化为string类型在保存为string,字节数组转string很简单就不写了,接下来解决可序列化对象保存问题,思路就是先将可序列化对象转化为字节数组,在用字节数组的保存方法保存,下面是可序列化对象转字节数组的方法
public byte[] putSerializable(String key, Serializable serializable) {
byte[] buff= null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(serializable);
buff=bos.toByteArray();
StreamUtil.close(oos);//关闭数据流
StreamUtil.close(bos);//关闭数据流
} catch (Exception e) {
e.printStackTrace();
}
return buff;
}
其他的问题也可以用相应的办法解决,这里就不一一介绍了,我们会发现全都转化到string类型保存的,这样就引入了一个新问题就是如何区分是string类型还是其他类型呢,用系统自带的是不好区分了,下面我们就自己编写一个SharedPreferences,先看代码
public class SharedPreferences {
List<Entry> entries;//节点
private File mFile;//文件
private DocumentBuilder documentBuilder;//dom解析器,可以替换成别的
public SharedPreferences(File file) {
// TODO Auto-generated constructor stub
if (NullUtil.isEmpty(file))
throw new NullPointerException("file is null");
mFile = file;
entries = new ArrayList<>();
try {
documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
} catch (Exception e) {
// TODO Auto-generated catch block
}
if (file.exists()) {
if (file.isDirectory())
throw new RuntimeException("file is directory");
paras();
}
}
private void paras() {
// TODO Auto-generated method stub
InputStream is = FileUtil.file2inputStream(mFile);
if (NullUtil.isEmpty(is))
return;
try {
Document document = documentBuilder.parse(is);
NodeList list = document.getChildNodes();
if (NullUtil.isEmpty(list))
return;
list = list.item(0).getChildNodes();
if (NullUtil.isEmpty(list))
return;
int len = list.getLength();
for (int i = 0; i < len; i++) {
Node node = list.item(i);
Entry entry = paras(node);
if (NullUtil.isEmpty(entry))
continue;
entries.add(entry);
}
} catch (Exception e) {
// TODO: handle exception
} finally {
StreamUtil.close(is);
}
}
//将节点转化为节点对象
private Entry paras(Node node) {
// TODO Auto-generated method stub
try {
String type = node.getNodeName();//标签名,也是类型名
if ("#text".equals(type))//去掉#text节点
return null;
NamedNodeMap map = node.getAttributes();
String key = map.getNamedItem("key").getTextContent().trim();//获取键
String value = node.getTextContent();//获取值
System.out.println(key + " " + type + " " + value);
if ("string".equals(type))//string类型
return new Entry(type, key, value);
if ("int".equals(type))//int类型
return new Entry(type, key, Integer.valueOf(value));
if ("boolean".equals(type))//boolean类型
return new Entry(type, key, Boolean.valueOf(value));
if ("float".equals(type))//float类型
return new Entry(type, key, Float.valueOf(value));
if ("long".equals(type))//long类型
return new Entry(type, key, Long.valueOf(value));
if ("double".equals(type))//double类型
return new Entry(type, key, Double.valueOf(value));
if ("set".equals(type)) {//set类型(set集合中可以放其他类型,不一定是string类型,需要去完善下)
NodeList list = node.getChildNodes();
if (NullUtil.isEmpty(list) && list.getLength() <= 0)
return new Entry(type, key, null);
int len = list.getLength();
Set<String> set = new HashSet<String>(len);
for (int i = 0; i < len; i++) {
node = list.item(i);
set.add(node.getTextContent().toString().trim());
}
return new Entry(type, key, set);
}
throw new RuntimeException("标签出错了");
} catch (Exception e) {
// TODO: handle exception
}
return null;
}
public String getString(String key, String defValue) {
Entry entry = serch(key);
if (NullUtil.isEmpty(entry))
return defValue;
if ("string".equals(entry.type))
return (String) entry.value;
return defValue;
}
public int getInt(String key, int defValue) {
Entry entry = serch(key);
if (NullUtil.isEmpty(entry))
return defValue;
if ("int".equals(entry.type))
return (int) entry.value;
return defValue;
}
public long getLong(String key, long defValue) {
Entry entry = serch(key);
if (NullUtil.isEmpty(entry))
return defValue;
if ("long".equals(entry.type))
return (long) entry.value;
return defValue;
}
public float getFloat(String key, float defValue) {
Entry entry = serch(key);
if (NullUtil.isEmpty(entry))
return defValue;
if ("float".equals(entry.type))
return (float) entry.value;
return defValue;
}
public boolean getBoolean(String key, boolean defValue) {
Entry entry = serch(key);
if (NullUtil.isEmpty(entry))
return defValue;
if ("boolean".equals(entry.type))
return (boolean) entry.value;
return defValue;
}
public double getDouble(String key, double defValue) {
Entry entry = serch(key);
if (NullUtil.isEmpty(entry))
return defValue;
if ("double".equals(entry.type))
return (double) entry.value;
return defValue;
}
@SuppressWarnings("unchecked")
public Set<String> getSet(String key, Set<String> defValue) {
Entry entry = serch(key);
if (NullUtil.isEmpty(entry))
return defValue;
if ("set".equals(entry.type))
return (Set<String>) entry.value;
return defValue;
}
public boolean contains(String key) {
int index = indexOf(key);
return index > -1;
}
public SharedPreferences putString(String key, String value) {
entries.add(new Entry("string", key, value));
return this;
}
public SharedPreferences putInt(String key, int value) {
entries.add(new Entry("int", key, value));
return this;
}
public SharedPreferences putLong(String key, long value) {
entries.add(new Entry("long", key, value));
return this;
}
public SharedPreferences putFloat(String key, float value) {
entries.add(new Entry("float", key, value));
return this;
}
public SharedPreferences putBoolean(String key, boolean value) {
entries.add(new Entry("boolean", key, value));
return this;
}
public SharedPreferences putDouble(String key, double value) {
entries.add(new Entry("double", key, value));
return this;
}
public SharedPreferences putSet(String key, Set<String> value) {
entries.add(new Entry("set", key, value));
return this;
}
public SharedPreferences remove(String key) {
int index = indexOf(key);
if (index > -1)
entries.remove(index);
return this;
}
public SharedPreferences clear() {
entries.clear();
return this;
}
private int indexOf(String key) {
if (NullUtil.isEmpty(entries))
return -1;
if (NullUtil.isEmpty(key))
return -1;
int len = entries.size();
for (int i = 0; i < len; i++) {
if (key.equals(entries.get(i).key))
return i;
}
return -1;
}
private Entry serch(String key) {
int index = indexOf(key);
return index > -1 ? entries.get(index) : null;
}
//提交数据,将数据保存到文件中
public boolean commit() {
try {
if (NullUtil.isEmpty(entries))
return false;
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //
transformer
.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
FileWriter fileWriter = new FileWriter(mFile);
Result result = new StreamResult(fileWriter);
Document document = documentBuilder.newDocument();
Iterator<Entry> iterator = entries.iterator();
Element element = document.createElement("map");
document.appendChild(element);
while (iterator.hasNext()) {
Entry entry = iterator.next();
if ("set".equals(entry.type)) {
Element setElement = document.createElement(entry.type);
element.setAttribute("key", entry.key);
Set<String> valueSet = (Set<String>) entry.value;
if (!NullUtil.isEmpty(valueSet)) {
for (String string : valueSet) {
Element setValue = document.createElement("value");
setValue.setTextContent(string);
setElement.appendChild(setValue);
}
}
} else
element.appendChild(entry2node(document, entry));
}
transformer.transform(new DOMSource(document), result);
StreamUtil.close(fileWriter);
return true;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return false;
}
private Node entry2node(Document document, Entry entry) {
// TODO Auto-generated method stub
Element element = document.createElement(entry.type);
element.setTextContent(entry.value.toString());
element.setAttribute("key", entry.key);
return element;
}
private class Entry {
String type;// int,long,float,boolean,string,set等,自己可以在添加
String key;//保存的键
Object value;//保存的值
public Entry(String type, String key, Object object) {
// TODO Auto-generated constructor stub
this.type = type;
this.value = object;
this.key = key;
}
}
}
通过上面我们发现我们用类型作为标签名,key是属性,value是值,这样我们就可以区分类型了,上面只是模仿了系统的SharedPreferences,如果需要保存其他类型或其他类型的集合,就需要对这个类稍微修改下,重点是修改解析和保存方法。这样就解决了上面提到的问题。