[Android] 數據實體的自動存取–SharedPreferences篇

本例代碼以SharedPreferences為數據存取載體。
利用SharedPreferences存取一個數據,步驟如下:
[java] 
SharedPreferences sharedPre = getSharedPreferences(name, mode); 
存: 
SharedPreferences.Editor editor = sharedPre.edit(); 
 
editor.put(key,value); 
editor.commit(); 
取: 
value = sharedPre.get(key,defaultValue); 
觀察以上,存取的關鍵是規范好對<key,value>的操作。其中key為字符串為預先定義好的。如果有多組<key,value>,則為每組想好key的名稱也是一件挺糾結的事。

本文自動讀取的核心在於直接使用數據實體的屬性名做為key值,在存取時遍歷數據實例的屬性,使用反射類讀取屬性的名稱,對屬性值進行寫出或寫入。
 首先,事先定義好可處理的存取數據類型如下:
[java]
public static final int CLZ_BYTE = 1; 
public static final int CLZ_SHORT = 2; 
public static final int CLZ_INTEGER = 3; 
public static final int CLZ_LONG = 4; 
public static final int CLZ_STRING = 5; 
public static final int CLZ_BOOLEAN = 6; 
public static final int CLZ_FLOAT = 7; 
public static final int CLZ_DOUBLE = 8; 
public static final Map<Class<?>, Integer> TYPES; 
static { 
    TYPES = new HashMap<Class<?>, Integer>(); 
    TYPES.put(byte.class, CLZ_BYTE); 
    TYPES.put(short.class, CLZ_SHORT); 
    TYPES.put(int.class, CLZ_INTEGER); 
    TYPES.put(long.class, CLZ_LONG); 
    TYPES.put(String.class, CLZ_STRING); 
    TYPES.put(boolean.class, CLZ_BOOLEAN); 
    TYPES.put(float.class, CLZ_FLOAT); 
    TYPES.put(double.class, CLZ_DOUBLE); 

寫出:
[java]
private void doSave(GoodsBean bean) { 
    SharedPreferences sharedPre = getSharedPreferences(GoodsBean.class.getName(), Context.MODE_PRIVATE); 
    SharedPreferences.Editor editor = sharedPre.edit(); 
    Class<? extends GoodsBean> clazz = bean.getClass(); 
    Field[] arrFiled = clazz.getDeclaredFields(); 
    try { 
        for (Field f : arrFiled) { 
            Log.d("ANDROID_LAB", "type[" + f.getType() + "] name[" + f.getName() + "]"); 
            int type = TYPES.get(f.getType()); 
            switch (type) { 
            case CLZ_BYTE: 
            case CLZ_SHORT: 
            case CLZ_INTEGER: 
                editor.putInt(f.getName(), f.getInt(bean)); 
                break; 
            case CLZ_LONG: 
                editor.putLong(f.getName(), f.getLong(bean)); 
                break; 
            case CLZ_STRING: 
                editor.putString(f.getName(), (String) f.get(bean)); 
                break; 
            case CLZ_BOOLEAN: 
                editor.putBoolean(f.getName(), f.getBoolean(bean)); 
                break; 
            case CLZ_FLOAT: 
                editor.putFloat(f.getName(), f.getFloat(bean)); 
                break; 
            case CLZ_DOUBLE: 
                editor.putFloat(f.getName(), (float) f.getDouble(bean)); 
                break; 
            } 
        } 
        editor.commit(); 
    } catch (IllegalArgumentException e) { 
        e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
        e.printStackTrace(); 
    } 

讀入:
[java]
private GoodsBean doRead() { 
    SharedPreferences sharedPre = getSharedPreferences(GoodsBean.class.getName(), Context.MODE_PRIVATE); 
    GoodsBean bean = new GoodsBean(); 
    Class<? extends GoodsBean> clazz = bean.getClass(); 
    Field[] arrFiled = clazz.getDeclaredFields(); 
    try { 
        for (Field f : arrFiled) { 
            int type = TYPES.get(f.getType()); 
            switch (type) { 
            case CLZ_BYTE: 
                byte byteValue = (byte) sharedPre.getInt(f.getName(), 0); 
                f.set(bean, byteValue); 
                break; 
            case CLZ_SHORT: 
                short shortValue = (short) sharedPre.getInt(f.getName(), 0); 
                f.set(bean, shortValue); 
                break; 
            case CLZ_INTEGER: 
                int intValue = sharedPre.getInt(f.getName(), 0); 
                f.set(bean, intValue); 
                break; 
            case CLZ_LONG: 
                long longValue = sharedPre.getLong(f.getName(), 0L); 
                f.set(bean, longValue); 
                break; 
            case CLZ_STRING: 
                String str = sharedPre.getString(f.getName(), null); 
                f.set(bean, str); 
                break; 
            case CLZ_BOOLEAN: 
                boolean bool = sharedPre.getBoolean(f.getName(), false); 
                f.set(bean, bool); 
                break; 
            case CLZ_FLOAT: 
                float floatValue = sharedPre.getFloat(f.getName(), 0.0f); 
                f.set(bean, floatValue); 
                break; 
            case CLZ_DOUBLE: 
                double doubleValue = sharedPre.getFloat(f.getName(), 0.0f); 
                f.set(bean, doubleValue); 
                break; 
            } 
        } 
    } catch (IllegalArgumentException e) { 
        e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
        e.printStackTrace(); 
    } 
    return bean; 

GoodsBean.java
[java] 
package lab.sodino.autosave; 
 
public class GoodsBean { 
    public String name; 
    public long time; 
    public int price; 
    public boolean isPaid; 
    /** 測試用。 */ 
    public byte testByte; 
    /** 測試用。 */ 
    public short testShort; 
    public float cicle; 
    public double testDouble; 
 
    public String toString() { 
        StringBuffer strBuffer = new StringBuffer(); 
        strBuffer.append("name[" + name + "]\n"); 
        strBuffer.append("time[" + time + "]\n"); 
        strBuffer.append("price[" + price + "]\n"); 
        strBuffer.append("isPaid[" + isPaid + "]\n"); 
        strBuffer.append("cicle[" + cicle + "]\n"); 
        strBuffer.append("testByte[" + testByte + "]\n"); 
        strBuffer.append("testShort[" + testShort + "]\n"); 
        strBuffer.append("testDouble[" + testDouble + "]\n"); 
        return strBuffer.toString(); 
    } 
 
    public static GoodsBean newInstance() { 
        GoodsBean bean = new GoodsBean(); 
        bean.name = "AutoSave"; 
        bean.time = 12345234252342l; 
        bean.price = 1024; 
        bean.isPaid = true; 
        bean.cicle = 2.356f; 
        bean.testByte = 8; 
        bean.testShort = 128; 
        bean.testDouble = 9856.2145d; 
        return bean; 
    } 

註意事項如下:
1.由於 SharedPreferences默認僅支持int/long/boolean/string/float 5種數據類型的讀寫,所以有一些強制轉換的操作。由01.gif可看出對double的存取操作會導致數據失真。在實際編碼工作中應註意些現象。如下圖:

2.需要處理好初始默認值。

自動存取的優點:
1.避免給一大堆key起名字,減少糾結時間。
2.方便、高效。數據結構的改變不需要重新修改存取過程。
3.出混淆包後,所有的key值也隨著一起混淆瞭,在一定程度上保護瞭程序邏輯。見圖01.png

缺點:
1.自動存取會將定義的數據結構全部存或全部取。如果想增加一些不需要本地存儲的屬性,則需要另建新類繼承原有數據結構才得以實現。

有利有弊,但總的來說利遠大於弊。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *