1. 程式人生 > >Android下利用SharePreference儲存序列化物件的方法

Android下利用SharePreference儲存序列化物件的方法

在android下做持久化的資料儲存,大部分是用到了sqlite資料庫或者sharepreference。當然我們為了圖方便,少寫sql語句,大部分都是用ORM形式的開源資料庫框架,例如greendao和cupboard或者dao4,但是在一般小型儲存系統中,我還是比較喜歡用sp來儲存,畢竟使用方便,資料量又不大,所以我覺得儲存些不是很多的物件資料,用sp來儲存還是很方便的。

雖說sharepreference是輕量級儲存工具,但他的功能還是很強大的,畢竟基於檔案儲存,雖說效率可能沒有sql那麼高,但是畢竟不要建立多張表,又不用寫多個實體,把資料統統放在一個類裡面,然後儲存讀取都能很方便的操作。

sharepreference儲存物件是利用將物件轉化為位元組流,然後寫入本地xml檔案中,下次通過讀取設定時的id來實現從xml檔案中讀取位元組流然後再轉化為物件.

下面介紹一下關於利用sharepreference儲存的用法:

package com.nickming.cachedemo.utils;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import android.util.Log;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;

/**
 * desc:
 *
 * @author:nickming date:2015/12/18
 * time: 01:10
 * e-mail:
[email protected]
*/ public class SaveObjectUtils { private Context context; private String name; public SaveObjectUtils(Context context, String name) { this.context = context; this.name = name; } /** * 根據key和預期的value型別獲取value的值 * * @param key * @param clazz * @return */ public <T> T getValue(String key, Class<T> clazz) { if (context == null) { throw new RuntimeException("請先呼叫帶有context,name引數的構造!"); } SharedPreferences sp = this.context.getSharedPreferences(this.name, Context.MODE_PRIVATE); return getValue(key, clazz, sp); } /** * 針對複雜型別儲存<物件> * * @param key * @param object */ public void setObject(String key, Object object) { SharedPreferences sp = this.context.getSharedPreferences(this.name, Context.MODE_PRIVATE); //建立位元組輸出流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); //建立位元組物件輸出流 ObjectOutputStream out = null; try { //然後通過將字物件進行64轉碼,寫入key值為key的sp中 out = new ObjectOutputStream(baos); out.writeObject(object); String objectVal = new String(Base64.encode(baos.toByteArray(), Base64.DEFAULT)); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, objectVal); editor.commit(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (baos != null) { baos.close(); } if (out != null) { out.close(); } } catch (IOException e) { e.printStackTrace(); } } } @SuppressWarnings("unchecked") public <T> T getObject(String key, Class<T> clazz) { SharedPreferences sp = this.context.getSharedPreferences(this.name, Context.MODE_PRIVATE); if (sp.contains(key)) { String objectVal = sp.getString(key, null); byte[] buffer = Base64.decode(objectVal, Base64.DEFAULT); //一樣通過讀取位元組流,建立位元組流輸入流,寫入物件並作強制轉換 ByteArrayInputStream bais = new ByteArrayInputStream(buffer); ObjectInputStream ois = null; try { ois = new ObjectInputStream(bais); T t = (T) ois.readObject(); return t; } catch (StreamCorruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (bais != null) { bais.close(); } if (ois != null) { ois.close(); } } catch (IOException e) { e.printStackTrace(); } } } return null; } /** * 對於外部不可見的過渡方法 * * @param key * @param clazz * @param sp * @return */ @SuppressWarnings("unchecked") private <T> T getValue(String key, Class<T> clazz, SharedPreferences sp) { T t; try { t = clazz.newInstance(); if (t instanceof Integer) { return (T) Integer.valueOf(sp.getInt(key, 0)); } else if (t instanceof String) { return (T) sp.getString(key, ""); } else if (t instanceof Boolean) { return (T) Boolean.valueOf(sp.getBoolean(key, false)); } else if (t instanceof Long) { return (T) Long.valueOf(sp.getLong(key, 0L)); } else if (t instanceof Float) { return (T) Float.valueOf(sp.getFloat(key, 0L)); } } catch (InstantiationException e) { e.printStackTrace(); Log.e("system", "型別輸入錯誤或者複雜型別無法解析[" + e.getMessage() + "]"); } catch (IllegalAccessException e) { e.printStackTrace(); Log.e("system", "型別輸入錯誤或者複雜型別無法解析[" + e.getMessage() + "]"); } Log.e("system", "無法找到" + key + "對應的值"); return null; } }

為了區分於建立的sp物件,所以我是建議在給個context下都例項化這個工具物件,但是如果圖方便,亦可以利用application來實現上下文的。

用法,由於我一個專案中需要建立了一個單例,所以我將單例的資料都封裝在stateinfo實體 裡面,點選儲存時拿出物件儲存,記得stateinfo一定要實現序列化介面,不然那會報空指標異常.

package com.nickming.cachedemo.ui;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.nickming.cachedemo.R;
import com.nickming.cachedemo.db.MTStateInfo;
import com.nickming.cachedemo.db.MTStateManager;
import com.nickming.cachedemo.utils.SaveObjectUtils;

public class Main2Activity extends AppCompatActivity {

    private Button mSave;
    private Button mShow;
    private TextView mResult;
    SaveObjectUtils utils;
    private static final String key=Main2Activity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        mSave= (Button) findViewById(R.id.btn_save1);
        mResult= (TextView) findViewById(R.id.tv_result1);
        mShow= (Button) findViewById(R.id.btn_show1);
        utils=new SaveObjectUtils(this,key);

        mSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                MTStateManager.getInstance().setTaskId(324444);
                MTStateManager.getInstance().setBeginTime("20132003055");
                MTStateInfo info=MTStateManager.getInstance().getStateInfo();
                utils.setObject(""+info.getTaskId(),info);
            }
        });
        mShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MTStateInfo test=utils.getObject("324444",MTStateInfo.class);
                MTStateManager.getInstance().clearDatas();
                MTStateManager.getInstance().setDatas(test);
                mResult.setText(""+MTStateManager.getInstance().getBeginTime());
            }
        });
    }
    
}
用sp儲存物件最大好處就是不要新建好多張表,例如我的stateinfo裡還有一個自定義的物件,用greendao時還需要再宣告一次,但是用sp就不需要,他不管你是自定義的還是系統的,都能毫無差錯的儲存,我想這也是他的好處之一。

下次有時間,我還會介紹一下greendao和cupboard在android studio上的用法.