简述:
在Android开发中,如果站在开发者的角度来讲,其存储方式大致分为5种,下面我就先简单介绍一下这几种存储方式,在本篇博文中谈谈SharedPreferences的用法并封装一个在开发中常用的SharedPreferences的工具类,并在以后的几篇博文中一一谈谈其他几种Android的存储方式,OK,废话不多说,看看下面的存储方式:1、SharedPreferences
Store private primitive data in key-value pairs.
以键值对的形式保存私有的简单数据。
2、Internal Storage
Store private data on the device memory.
在手机内存中保存不对外共享的信息。
3、External Storage
Store public data on the shared external storage.
在外部存储设备上保存公共的数据信息。主要指保存在SDCard上。
4、SQLite Databases
Store structured data in a private database.
将结构化的数据保存进数据库。
5、Network Connection
Store data on the web with your own network server.
将数据保存到自己的远程服务器上。
SharedPreferences基本用法:
概念:SharedPreferences是Android系统提供的一个通用的数据持久化框架,用于存储和读取key-value类型的原始基本数据类型对,目前支持string、int、long、float、boolean等基本类型的存储,对于自定义的对象数据类型,无法使用SharedPreferences来存
应用场景
SharedPreferences主要用于存储系统的配置信息,比如保存用户登录时的用户名、密码以及第一次安装或升级App时加载欢迎页面,再有就是一些App的配置信息,例如手势锁密码、音效等。
API介绍
(1)获得SharedPreferences对象:SharedPreferences sp=Context.getSharedPreferences(String name, int mode);
SharedPrefrences sp =Activity.getPreferences(int mode);
两者的区别:
getSharedPreferences是Context类中的方法,可以指定file name以及mode。
getPreferences是Activity类中的方法,只需指定mode。
Context.MODE_PRIVATE: 默认的操作模式,代表该文件是私有数据,指定该SharedPreferences的数据只能被本应用App程序读、写,写入的内容也会覆盖原文件的内容。
Context.MODE_WORLD_READABLE: 指定 SharedPreferences数据能被其他应用App程序读,但是不支持写。
Context.MODE_WORLD_WRITEABLE: 指定 SharedPreferences数据能被其他应用程序读、写。
Context.MODE_APPEND:该模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
最后关于SharedPreferences本身是一个接口,无法直接创建实例,通过Context的getSharedPreferences(String name, int mode)方法来获取实例。而通过这个方法创建出来的对象有点单例模式的意思,所以在读取SharedPreferences数据时只需写入正确的“文件名”就OK了。
(2)写入数据
在SharedPrefrences的源码中有一个内部类Editor,这个内部类承担了“写”数据的任务,其用法如下:
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(String key, boolean value);
editor.putFloat(String key, float value);
editor.putInt(String key, int value);
editor.putLong(String key, long value);
editor.putString(String key, String value);
注意最后不要忘记调用editor.commit();方法,否则数据不会被保存进去的。
在这里还需要补充一下,SharedPreferences文件最终以xml文件形式存储在/data/data/包名/shared_prefs目录下,形式如下:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="pwd">123456</string>
<string name="username">tinyjoy</string>
<int name="age">24</int>
</map>
所以在向SharedPreferences文件中写入数据时是以key-value键值对的形式。
(3)读取数据
与写入数据时的数据写入类型相对应,读取数据有以下几种方法:
getAll()
getBoolean(String key, boolean defValue)
getFloat(String key, float defValue)
getInt(String key, int defValue)
getLong(String key, long defValue)
getString(String key, String defValue)
(4)删除数据
删除数据有两个方法:
remove(String key);//删除指定”键“的那条数据。
clear();//删除整个SharedPreferences文件
另外还需要提醒一下:SharedPreferences文件保存在安装App的文件中,当我们把App卸载后相应的SharedPreferences文件也就一起被删除了。SharedPreferences的用法相对比较简单,基本的用法大致就这些了,那么接下来我们就封装一个工具类,这样就在做项目是减轻些负担。
SharedPreferences保存对象
SharedPreferences只能保存一些简单的数据,那么对于复杂数据如一个User对象怎么办呢?对于对象的保存一般方式为:对象首先要实现序列化Serializable,然后将该对象转化为String类型保存起来,我们读取的时候再将String类型反序列化。对于Serializable转化为String,以及反序列化可以采用Base64或者16进制的方法。
案例:
public class User implements Serializable {
private String name;
private String sex;
public User() {
}
public User(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
转化采用16进制的转换:
/**
* 方法描述:将数组转为16进制
*/
private static String bytesToHexString(byte[] bArray) {
if (bArray == null) {
return null;
}
if (bArray.length == 0) {
return "";
}
StringBuffer sb = new StringBuffer(bArray.length);
String sTemp;
for (int i = 0; i < bArray.length; i++) {
sTemp = Integer.toHexString(0xFF & bArray[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
/**
* 方法描述:将16进制的数据转为数组
*
* @param data
* @return modified:
*/
private static byte[] StringToBytes(String data) {
String hexString = data.toUpperCase().trim();
if (hexString.length() % 2 != 0) {
return null;
}
byte[] retData = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i++) {
int int_ch; // 两位16进制数转化后的10进制数
char hex_char1 = hexString.charAt(i); 两位16进制数中的第一位(高位*16)
int int_ch1;
if (hex_char1 >= '0' && hex_char1 <= '9')
int_ch1 = (hex_char1 - 48) * 16; 0 的Ascll - 48
else if (hex_char1 >= 'A' && hex_char1 <= 'F')
int_ch1 = (hex_char1 - 55) * 16; A 的Ascll - 65
else
return null;
i++;
char hex_char2 = hexString.charAt(i); ///两位16进制数中的第二位(低位)
int int_ch2;
if (hex_char2 >= '0' && hex_char2 <= '9')
int_ch2 = (hex_char2 - 48); 0 的Ascll - 48
else if (hex_char2 >= 'A' && hex_char2 <= 'F')
int_ch2 = hex_char2 - 55; A 的Ascll - 65
else
return null;
int_ch = int_ch1 + int_ch2;
retData[i / 2] = (byte) int_ch;//将转化后的数放入Byte里
}
return retData;
}
使用:
public static void saveObject(Context context, String key, Object obj) {
try {
// 保存对象
SharedPreferences.Editor shareData = context.getSharedPreferences(DEFAULT_FILE_NAME, 0).edit();
//先将序列化结果写到byte缓存中,其实就分配一个内存空间
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
//将对象序列化写入byte缓存
os.writeObject(obj);
//将序列化的数据转为16进制保存
String bytesToHexString = bytesToHexString(bos.toByteArray());
//保存该16进制数组
shareData.putString(key, bytesToHexString);
shareData.apply();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "对象保存失败");
}
}
public static Object readObject(Context context, String key) {
try {
SharedPreferences sharedata = context.getSharedPreferences(DEFAULT_FILE_NAME, 0);
if (sharedata.contains(key)) {
String string = sharedata.getString(key, "");
if (TextUtils.isEmpty(string)) {
return null;
} else {
//将16进制的数据转为数组,准备反序列化
byte[] stringToBytes = StringToBytes(string);
ByteArrayInputStream bis = new ByteArrayInputStream(stringToBytes);
ObjectInputStream is = new ObjectInputStream(bis);
//返回反序列化得到的对象
Object readObject = is.readObject();
return readObject;
}
}
} catch (StreamCorruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//所有异常返回null
return null;
}
工具类
关于工具类的封装,就是为了实现代码的解耦,同时也易于提高代码的可读性,我封装的SharedPreferences的工具类如下:
package com.lzy.sharedpreferenceutil;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* 作者:lzy
* 邮箱:1556342503@qq.com
*/
public class SharedPreferencesUtil {
private static final String TAG = SharedPreferencesUtil.class.getSimpleName();
/**
* file name of the sharedPrefrences stores data on SDCard
*/
public static final String FILE_NAME = "share_data";
/**
* construct method
*/
private SharedPreferencesUtil() {
}
/**
* modifying values and store the data on the SDcard in a
* {@link SharedPreferences} object.
*
* @param context The context to use. Usually your
* {@link android.app.Application} or
* {@link android.app.Activity} object.
* @param key The name of the preference to modify.
* @param object The new value for the preference.
* @Time 2016年1月7日
* @Author lizy18
*/
public static void put(Context context, String key, Object object) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
if (object instanceof String) {
editor.putString(key, (String) object);
} else if (object instanceof Integer) {
editor.putInt(key, (Integer) object);
} else if (object instanceof Boolean) {
editor.putBoolean(key, (Boolean) object);
} else if (object instanceof Float) {
editor.putFloat(key, (Float) object);
} else if (object instanceof Long) {
editor.putLong(key, (Long) object);
} else {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(object);
String bytesToHexString = bytesToHexString(bos.toByteArray());
editor.putString(key, bytesToHexString);
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "saving object failed!");
}
}
editor.apply();
}
/**
* Retrieve a series of value(including String value,Integer value,Boolean
* value,Float value,Long value) from the preferences.
*
* @param context The context to use. Usually your
* {@link android.app.Application} or
* {@link android.app.Activity} object.
* @param key key The name of the preference to retrieve.
* @param defValue Value to return if this preference does not exist.
* @return Returns the preference value if it exists, or defValue.
* @Time 2016年1月7日
* @Author lizy18
*/
public static Object get(Context context, String key, Object defValue) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
FILE_NAME, Context.MODE_PRIVATE);
if (!contains(context, key)) {
return defValue;
}
if (defValue instanceof String) {
return sharedPreferences.getString(key, (String) defValue);
} else if (defValue instanceof Integer) {
return sharedPreferences.getInt(key, (Integer) defValue);
} else if (defValue instanceof Boolean) {
return sharedPreferences.getBoolean(key, (Boolean) defValue);
} else if (defValue instanceof Float) {
return sharedPreferences.getFloat(key, (Float) defValue);
} else if (defValue instanceof Long) {
return sharedPreferences.getLong(key, (Long) defValue);
} else {
String string = sharedPreferences.getString(key, "");
if (TextUtils.isEmpty(string))
return defValue;
try {
byte[] stringToBytes = StringToBytes(string);
ByteArrayInputStream bis = new ByteArrayInputStream(stringToBytes);
ObjectInputStream is = new ObjectInputStream(bis);
return is.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
return defValue;
}
/**
* Removing the given preference value in the preferences.
*
* @param context The context to use. Usually your
* {@link android.app.Application} or
* {@link android.app.Activity} object.
* @param key The name of the preference to remove.
* @Time 2016年1月7日
* @Author lizy18
*/
public static void remove(Context context, String key) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(key);
editor.apply();
}
/**
* remove <em>all</em> values from the preferences.
*
* @param context The context to use. Usually your
* {@link android.app.Application} or
* {@link android.app.Activity} object.
* @Time 2016年1月7日
* @Author lizy18
*/
public static void clear(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.apply();
}
/**
* Checks whether the preferences contains a preference.
*
* @param context The context to use. Usually your
* {@link android.app.Application} or
* {@link android.app.Activity} object.
* @param key The name of the preference to check.
* @return Returns true if the preference exists in the preferences,
* otherwise false.
* @Time 2016年1月7日
* @Author lizy18
*/
public static boolean contains(Context context, String key) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
FILE_NAME, Context.MODE_PRIVATE);
return sharedPreferences.contains(key);
}
/**
* convert array to hexadecimal String
*/
private static String bytesToHexString(byte[] bArray) {
if (bArray == null) {
return null;
}
if (bArray.length == 0) {
return "";
}
StringBuffer sb = new StringBuffer(bArray.length);
String sTemp;
for (int i = 0; i < bArray.length; i++) {
sTemp = Integer.toHexString(0xFF & bArray[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
/**
* 方法描述:将16进制的数据转为数组
*/
private static byte[] StringToBytes(String data) {
String hexString = data.toUpperCase().trim();
if (hexString.length() % 2 != 0) {
return null;
}
byte[] retData = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i++) {
int int_ch; // 两位16进制数转化后的10进制数
char hex_char1 = hexString.charAt(i); 两位16进制数中的第一位(高位*16)
int int_ch1;
if (hex_char1 >= '0' && hex_char1 <= '9')
int_ch1 = (hex_char1 - 48) * 16; 0 的Ascll - 48
else if (hex_char1 >= 'A' && hex_char1 <= 'F')
int_ch1 = (hex_char1 - 55) * 16; A 的Ascll - 65
else
return null;
i++;
char hex_char2 = hexString.charAt(i); ///两位16进制数中的第二位(低位)
int int_ch2;
if (hex_char2 >= '0' && hex_char2 <= '9')
int_ch2 = (hex_char2 - 48); // 0 Ascii - 48
else if (hex_char2 >= 'A' && hex_char2 <= 'F')
int_ch2 = hex_char2 - 55; // A Ascii - 65
else
return null;
int_ch = int_ch1 + int_ch2;
retData[i / 2] = (byte) int_ch;//将转化后的数放入Byte里
}
return retData;
}
}