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 getValue(String key, Class 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 getObject(String key, Class 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 getValue(String key, Class 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上的用法.


你可能感兴趣的:(Android)