SharedPreference 和 RxJava 以及对 SharedPreferece 添加 wrapper

1,341
原文链接: www.jianshu.com
需求分析

本文介绍一个SharedPreference的使用的工具类,在Android开发的过程中不可避免的会使用SharedPreference来缓存一个数据,(1)如果频繁使用的话还是最好把存取操作放在子线程去处理;(2)如果不写一个关于SharedPerference的工具类,没法复用很多操作,(3)如果每个对应的业务的数据都写对应的存取删除操作的话,到项目后期会有很多,难以维护;


针对上面的三个问题实现一个比较通用可扩展性强的工具里,SharedPerference支持六种数据:String,Boolean,Int,Long,Float和Set<String>,大部分业务都可以支持,当需要保存Object和List<Object>,均可以通过使用Object->Json->String再进行保存,SharedPerference是保存在xml文件中键值对,所以有两个重要的属性就是fileName和keyName,所以

SharePerferenceUtil的包含两个内部类:FILE_KEYS和VALUE_KEYS作为索引。

public class SPUtil {
    public static final class FILE_KEYS{
        public static final String APP_STATUS = "app_status";
        public static final String USER_INFO = "user_info";
    }
    public static final class VALUE_KEYS{
        public static final String IS_LOGIN = "is_login";
        public static final String USER = "user";
        public static final String MOBILE_LOGIN_LIST = "mobile_login_list";
    }
...

读取成功后的回调接口:

public interface SPResultListener<T> {
    void onResult(T t);
}

当存取List数据时需要Id作为表示,所以Object必须实现接口:

public interface ShareCacheableData {
    String getId();
}

1、首先基本数据类型,以Boolean为例:

存数据,调用RxJava使得写操作在I/O线程中进行:

public static final synchronized void saveBoolean(final String fileKey, final String valueKey, final boolean value){
        Observable.create(new Observable.OnSubscribe<Object>() {
            @Override
            public void call(Subscriber<? super Object> subscriber) {
                SharedPreferences sp = OpenEyeApplication.getInstance().getSharedPreferences(fileKey,Context.MODE_PRIVATE);
                SharedPreferences.Editor editor = sp.edit();
                editor.putBoolean(valueKey,value);
                editor.commit();
            }
        }).subscribeOn(Schedulers.io()).subscribe();
    }

读数据,调用RxJava使得读取操作在I/O线程中进行,读取成功后在UI线程中进行的回调:

    public static final void getBoolean(final String fileKey, final String valueKey, final SPResultListener<Boolean> resultListener){
        Observable.just("").subscribeOn(Schedulers.io())
                .map(new Func1<String, Boolean>() {
                    @Override
                    public Boolean call(String s) {
                        SharedPreferences sp = OpenEyeApplication.getInstance().getSharedPreferences(fileKey, Context.MODE_PRIVATE);
                        return sp.getBoolean(valueKey,false);
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Boolean>() {
                    @Override
                    public void call(Boolean value) {
                        if (value == null){
                            value = false;
                        }

                        if (resultListener != null){
                            resultListener.onResult(value);
                        }
                    }
                });
    }

2、存取实体对象,和存取基本的数据多了一个转String的过程,

保存实体对象:

    public static final <T extends Serializable> void saveModel(final String fileKey, final String valueKey, final T t){
        Observable.create(new Observable.OnSubscribe<Object>() {
            @Override
            public void call(Subscriber<? super Object> subscriber) {
                SharedPreferences sp = OpenEyeApplication.getInstance().getSharedPreferences(fileKey,Context.MODE_PRIVATE);
                SharedPreferences.Editor editor = sp.edit();
                editor.putString(valueKey,new Gson().toJson(t));
                editor.commit();
            }
        }).subscribeOn(Schedulers.io()).subscribe();
    }

读取实体对象:

    public static final <T extends Serializable> void getModel(final String fileKey, final String valueKey, final Class<T> clazz, final SPResultListener<T> resultListener){
        Observable.just("").subscribeOn(Schedulers.io())
                .map(new Func1<String, T>() {
                    @Override
                    public T call(String s) {
                        SharedPreferences sp = OpenEyeApplication.getInstance().getSharedPreferences(fileKey, Context.MODE_PRIVATE);
                        String sResult = sp.getString(valueKey,"");
                        if (TextUtils.isEmpty(sResult)){
                            return null;
                        }else{
                            T t = new Gson().fromJson(sResult,clazz);
                            return t;
                        }
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<T>() {
                    @Override
                    public void call(T value) {
                        if (resultListener != null){
                            resultListener.onResult(value);
                        }
                    }
                });
    }

2、存取实体对象列表,Gson转换的时候容易出错,可以特别注意一下:

往列表保存对象,ShareCacheableData是为了获取对象的唯一标识:

  public static final <T extends ShareCacheableData> void putList(final String fileKey, final String valueKey, final Class<T[]> clazz, final T t){

        Observable.create(new Observable.OnSubscribe<Object>() {
            @Override
            public void call(Subscriber<? super Object> subscriber) {
                SharedPreferences sp = OpenEyeApplication.getInstance().getSharedPreferences(fileKey,Context.MODE_PRIVATE);
                String listJson = sp.getString(valueKey,"");
                List<T> oldList = new ArrayList<>();
                if (!TextUtils.isEmpty(listJson)){
                    T[] array = new Gson().fromJson(listJson,clazz);
                    oldList = new ArrayList<T>(Arrays.asList(array));
                }

                Iterator<T> iterator = oldList.iterator();
                while (iterator.hasNext()){
                    T item = iterator.next();
                    if (TextUtils.equals(item.getId(),t.getId())){
                        iterator.remove();
                    }
                }
                oldList.add(t);

                SharedPreferences.Editor editor = sp.edit();
                editor.putString(valueKey,new Gson().toJson(oldList));
                editor.commit();
                subscriber.onStart();
            }
        }).subscribeOn(Schedulers.io()).subscribe();
    }

读取对象列表:

public static final <T extends ShareCacheableData> void getList(final String fileKey, final String valueKey, final Class<T[]> clazz, final SPResultListener<List<T>> resultListener){
        Observable.just("").subscribeOn(Schedulers.io())
                .map(new Func1<String, List<T>>() {
                    @Override
                    public List<T> call(String s) {
                        SharedPreferences sp = OpenEyeApplication.getInstance().getSharedPreferences(fileKey, Context.MODE_PRIVATE);
                        String sResult = sp.getString(valueKey,"");

                        if (TextUtils.isEmpty(sResult)){
                            return null;
                        }else{
                            T[] list = new Gson().fromJson(sResult,clazz);
                            return new ArrayList<T>(Arrays.asList(list));
                        }
                    }
                }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<List<T>>() {
                    @Override
                    public void call(List<T> value) {
                        if (resultListener != null){
                            resultListener.onResult(value);
                        }
                    }
                });
    }

结束了。。。