SharedPreferences在專案中應用——開發記錄
阿新 • • 發佈:2018-11-10
開發記錄:在日常開發中,長使用的幾種本地序列化方式,SP的使用是最普遍的,所以對SP 的封裝就異常重要了,用起來順手的SP封裝工具,能夠節省你很多時間。
- 面試技能點
- 原生程式碼實現
- 工具類(只想要程式碼 Github 三個類直接貼到專案中就行了。)
枯燥的原理時間:
1. SharedPreferences讀取xml檔案時,會以DOM方式解析(把整個xml檔案直接載入到記憶體中解析),在呼叫getXXX()方法時取到的是記憶體中的資料,方法執行時會有個鎖來阻塞,目的是等待檔案載入完畢,沒載入完成之前會wait()。
2. SharedPreferences寫檔案時,如果呼叫的commit(),會將資料同步寫入記憶體中,記憶體資料更新,再同步寫入磁碟中;如果呼叫的apply(),會將資料同步寫入記憶體中,記憶體資料更新,然後非同步寫人磁碟,也就是說可能寫磁碟操作還沒有完成就直接返回了。在主執行緒中建議使用apply(),因為同步寫磁碟,當檔案較大時,commit()會等到寫磁碟完成再返回,可能會有ANR問題。
3. SP第一次初始化到讀取到資料存在一定延遲,因為需要到檔案中讀取資料,因此可能會對UI執行緒流暢度造成一定影響。
原生實現:
//獲得SharedPreferences的例項 sp_name是檔名 SharedPreferences sp = getSharedPreferences("sp_name", Context.MODE_PRIVATE); //獲得Editor 例項 SharedPreferences.Editor editor = sp.edit(); //以key-value形式儲存資料 editor.putString("data_key", "data"); //apply()是非同步寫入資料 editor.apply(); //commit()是同步寫入資料 //editor.commit();
PrefsHelper: SP 封裝類
public class PrefsHelper { //儲存檔名稱 private static final String PREFERENCE_FILE_NAME = "Example"; //使用者個人的資訊 private static final String KEY_USER_INFO = "UserInfo"; // 註冊 public static void init(Context context) { Prefs.init(context.getApplicationContext(), PREFERENCE_FILE_NAME); } /** * 儲存使用者的登入資料。 */ public static void setUserInfo(@NonNull UserBean info) { String infoToSave = new Gson().toJson(info); LogUtil.d("UserBeanToSp:%s" + infoToSave); Prefs.set(KEY_USER_INFO, infoToSave); } /** * 獲取使用者的個人資訊。 */ @Nullable public static UserBean getUserInfo() { String savedInfo = Prefs.getString(KEY_USER_INFO); if (TextUtils.isEmpty(savedInfo)) { return null; } return new Gson().fromJson(savedInfo, UserBean.class); } /** * 清除使用者登入資料。 */ public static void removeLoginInfo() { LogUtil.d("Removing UserBean info."); Prefs.remove(KEY_USER_INFO); } }
Prefs:SP 具體操作類
/* package */ class Prefs {
private static Context appContext;
private static String fileName;
/**
* 為後續呼叫初始化此類.
* @param context 上下文.
* @param file SP的檔案讀寫.
*/
public static void init(@NonNull Context context, @NonNull String file){
appContext = context.getApplicationContext();
fileName = file;
}
/**
*檢索SP值,假設第二個引數是正確的類.
* @param <T> 支援型別Boolean, Integer, Long, Float, Double, String,不支援型別會丟擲
*/
@SuppressWarnings("unchecked")
public static <T> T get(@NonNull String key, T fallback) throws
UnsupportedOperationException {
SharedPreferences sp = getSharedPreferences();
Object result;
if (fallback instanceof Boolean){
result = sp.getBoolean(key, (Boolean)fallback);
}
else if (fallback instanceof String){
result = sp.getString(key, (String) fallback);
}
else if (fallback instanceof Integer){
result = sp.getInt(key, (Integer) fallback);
}
else if (fallback instanceof Float){
result = sp.getFloat(key, (Float) fallback);
}
else if (fallback instanceof Long) {
result = sp.getLong(key, (Long) fallback);
}
else{
throw new UnsupportedOperationException("Type not supported: " + fallback.getClass()
.getSimpleName());
}
return (T)result;
}
/**
* 從首選項中檢索字串值,預設值為空字串。.
*/
public static String getString(@NonNull String key){
return get(key, "");
}
/**
* 長值檢索預設是 0 程式碼。
*/
public static long getLong(@NonNull String key){
return get(key, 0L);
}
/**
* 從首選項中檢索整數值, default is <code>0</code>.
*/
public static int getInt(@NonNull String key){
return get(key, 0);
}
/**
* 檢索一個布林值, default is <code>false</code>.
*/
public static boolean getBoolean(@NonNull String key){
return get(key, false);
}
/**
* 把值放進SP 中
* @param <T> Boolean, Integer, Long, Float, Double, String allowed. For other types, an
* UnsupportedOperationException is thrown.
*/
public static <T> void set(@NonNull String key, @NonNull T value) {
SharedPreferences.Editor editor = getSharedPreferences().edit();
if (value instanceof Boolean){
editor.putBoolean(key, (Boolean) value);
}
else if (value instanceof String){
editor.putString(key, (String) value);
}
else if (value instanceof Integer){
editor.putInt(key, (Integer) value);
}
else if (value instanceof Float){
editor.putFloat(key, (Float) value);
}
else if (value instanceof Long) {
editor.putLong(key, (Long) value);
}
else{
throw new UnsupportedOperationException("Type not supported: " + value.getClass()
.getSimpleName());
}
//use apply instead of commit to improve performance on UI thread.
editor.apply();
}
public static void remove(String key) {
getSharedPreferences().edit().remove(key).apply();
}
/**
* clear all data!
* @see SharedPreferences.Editor#clear()
*/
public static void clear(){
getSharedPreferences().edit().clear().apply();
}
private static SharedPreferences getSharedPreferences() {
checkInitiatedOrThrow();
return appContext.getSharedPreferences(fileName, Context.MODE_PRIVATE);
}
/**
* Retrieve all values from the preferences.
* @see SharedPreferences#getAll()
*/
public static Map<String, ?> getAll(){
return getSharedPreferences().getAll();
}
private static void checkInitiatedOrThrow() {
if (appContext == null || TextUtils.isEmpty(fileName)) {
throw new IllegalStateException("The Prefs class is not initialized correctly.");
}
}
}
LocalDataManager:單例模式呼叫 PrefsHelper
public class LocalDataManager {
private static LocalDataManager instance;
private UserBean mUserBean;
private LocalDataManager() {
// 私有化構造
}
public static LocalDataManager getInstance() {
if (instance == null) {
synchronized (LocalDataManager.class) {
// 執行緒安全的單利模式
if (instance == null) {
instance = new LocalDataManager();
}
}
}
return instance;
}
/**
* 獲取使用者個人資訊
*
* @return
*/
public UserBean getUserInfo() {
if (mUserBean == null) {
mUserBean = PrefsHelper.getUserInfo();
}
return mUserBean;
}
/**
* 獲取使用者個人資訊
*
* @return
*/
public void saveUserInfo(@NonNull UserBean mUserBean) {
//Update cached object!
this.mUserBean = mUserBean;
PrefsHelper.setUserInfo(mUserBean);
}
/**
* 清楚使用者資訊
*
* @return
*/
public void clearLoginInfo() {
mUserBean = null;
PrefsHelper.removeLoginInfo();
}
}
MianActivity : 具體使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化Prefs 建議在Application 中進行初始化
PrefsHelper.init(this);
UserBean mUserBean = new UserBean();
mUserBean.setAll_money(1);
LocalDataManager.getInstance().saveUserInfo(mUserBean);
// 一般登入的時候,拿到使用者的資料,直接儲存在SP 中,或者APP 是否首次登入等判斷
UserBean bean = LocalDataManager.getInstance().getUserInfo();
LogUtil.e(bean.getAll_money()+"元");
}
}
程式碼拿走,留個贊,互相幫助!!!
下一篇準備寫ViewPager +Fragment 懶載入,也是在日常開發中遇到的問題。避免下次採坑。