Android SharedPreferences封装实践201

2019-12-11  本文已影响0人  松哥888

为什么要封装?

系统提供SharedPreferences很不好用,参数多余,也不友好,用起来很繁琐,基本上都需要封装一下才能用。

创建方法1

// 创建函数式context的一个实例方法
public abstract SharedPreferences getSharedPreferences(String var1, int var2);

// 使用的一个例子
SharedPreferences sp=context.getSharedPreferences("名称", Context.MODE_PRIVATE);

创建方法2

// 方法定义
public static SharedPreferences getDefaultSharedPreferences(Context context) {
        throw new RuntimeException("Stub!");
    }

// 使用例子
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

创建方法3

// 方法定义
public SharedPreferences getPreferences(int mode) {
        throw new RuntimeException("Stub!");
}

// 使用实例
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);

写入操作

//可以创建一个新的SharedPreference来对储存的文件进行操作
SharedPreferences sp=context.getSharedPreferences("名称", Context.MODE_PRIVATE);
//像SharedPreference中写入数据需要使用Editor
SharedPreference.Editor editor = sp.edit();
//类似键值对
editor.putString("name", "string");
editor.putInt("age", 0);
editor.putBoolean("read", true);
//editor.apply();
editor.commit();

小结:使用者的期望是简单信息的缓存读写,不过看到的是不伦不类的文件读写。广大Android开发者的眼睛是雪亮的,几乎所有人都觉得要二次封装一下,不然用起来就觉得恶心。能设计出人人喊打的API,设计者的脑子该有多二啊

Android SharedPreference的使用
SharedPreference使用

iOS的缓存读写

作为对比,可以参考一下iOS的缓存读写,就知道简单信息的缓存API应该是什么样子的。

    //将NSString 对象存储到 NSUserDefaults 中

    NSString *passWord = @"1234567";

    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];

    [user setObject:passWord forKey:@"userPassWord"];

NSUserDefaults 简介,使用 NSUserDefaults 存储自定义对象

第1层封装

封装对象

// 创建函数式context的一个实例方法
public abstract SharedPreferences getSharedPreferences(String var1, int var2);

// 使用的一个例子
SharedPreferences sp=context.getSharedPreferences("名称", Context.MODE_PRIVATE);

实例还是静态方法

    /**
     * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
     *
     * @param context  上下文
     * @param key      关键字
     * @param object   数据
     * @param fileName 文件名
     */
    public static void put(Context context, String key, Object object, String fileName)

构造函数

统一确定Context context; String fileName这两个参数是拖油瓶,并且作为内部静态变量,对外隐藏。

public final class SPCache {
    // 隐藏两个参数
    private Context context;
    private SharedPreferences sp;

    // 禁止无参默认构造函数
    private SPCache() {}

    // 统一确定两个参数,一个fileName,对应于内部一个sp
    public SPCache(@NonNull Context context, @NonNull String fileName) {
        this.context = context.getApplicationContext();
        this.sp = this.context.getSharedPreferences(fileName, Context.MODE_PRIVATE);
    }
}

put操作封装

    /**
     * 存入缓存,类型可以是int,long,float,Boolean,String;自定义对象会通过toString()转换为字符串
     * @param key     键
     * @param object  值
     */
    public void put(@NonNull String key, Object object) {
        SharedPreferences.Editor editor = sp.edit();

        // instanceof 用来 指出对象是否是特定类的一个实例
        if (object instanceof String) {
            editor.putString(key, (String) object);
        }
        else if (object instanceof Integer) {
            editor.putInt(key, (Integer) object);
        }
        else if (object instanceof Boolean) {
            editor.putBoolean(key, (Boolean) object);
        }
        else if (object instanceof Float) {
            editor.putFloat(key, (Float) object);
        }  else if (object instanceof Long) {
            editor.putLong(key, (Long) object);
        } else {
            editor.putString(key, object.toString());
        }

        editor.commit();
    }

get操作封装

put类似,将一堆getXXX操作统一为get Object

    /**
     * 根据默认值类型,获取相应的数据。类型可以是int,long,float,Boolean,String;
     * @param key               键
     * @param defaultObject     默认值
     * @return                  数据
     */
    public Object get(@NonNull String key, @NonNull Object defaultObject) {
        if (defaultObject instanceof String) {
            return sp.getString(key, (String) defaultObject);
        }
        else if (defaultObject instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObject);
        }
        else if (defaultObject instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObject);
        }
        else if (defaultObject instanceof Float) {
            return sp.getFloat(key, (Float) defaultObject);
        }
        else if (defaultObject instanceof Long) {
            return sp.getLong(key, (Long) defaultObject);
        }
        return null;
    }

删除和清空

    /**
     * 移除键对应的数据
     * @param key  键
     */
    public void remove(@NonNull String key) {
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        editor.commit();
    }

    /**
     * 清空缓存
     */
    public void clear() {
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.commit();
    }

讨论:SharedPreferencesCompat

 public void apply(@NonNull SharedPreferences.Editor editor) {
       try {
            editor.apply();
        } catch (AbstractMethodError unused) {
            // The app injected its own pre-Gingerbread
            // SharedPreferences.Editor implementation without
            // an apply method.
            editor.commit();
       }
}
image.png

小结:既然被废弃,就不用了,直接使用editor.commit();保证安全。如果担心性能问题,应该考虑信息拆分,正确使用,符合SharedPreferences少量配置信息读写的定位

第2层封装: 静态化

public final class SPUserInfo {
    // sp 对象
    private final static SPCache spCache = new SPCache(MainApplication.getContext(), "SPUserInfo");

    // 各种key常数定义
    private final static String userNameKey = "userNameKey";
    private final static String passwordKey = "passwordKey";

    // 读写接口
    public static void put(UserInfo userInfo) {
        spCache.put(userNameKey, userInfo.getUserName());
        spCache.put(passwordKey, userInfo.getPassword());
    }

    public static UserInfo get() {
        String userName = (String) spCache.get(userNameKey, "默认的名字");
        String password = (String) spCache.get(passwordKey, "默认的密码");
        return new UserInfo(userName, password);
    }
}

Demo

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <EditText
        android:layout_marginTop="20dp"
        android:id="@+id/edit_user_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="用户名"
        android:singleLine="true"
        />
    <EditText
        android:layout_marginTop="20dp"
        android:id="@+id/edit_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密码"
        android:inputType="textPassword"
        android:singleLine="true"
        />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_marginTop="20dp">
        <Button
            android:id="@+id/input"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="存储"
            android:onClick="writeInfo"/>
        <Button
            android:id="@+id/output"
            android:layout_marginLeft="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="读取"
            android:onClick="readInfo"/>
    </LinearLayout>
    <TextView
        android:id="@+id/showtext"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="15dp"
        android:text="存储的信息"
        android:textSize="25dp"/>
    <TextView
        android:id="@+id/text_user_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="15dp"
        android:text="用户名"
        android:textSize="20dp"/>
    <TextView
        android:id="@+id/text_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="15dp"
        android:text="密码"
        android:textSize="20dp"/>
</LinearLayout>
public class MainActivity extends AppCompatActivity {

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

    public void writeInfo(View view) {
        EditText userNameEdit = (EditText)findViewById(R.id.edit_user_name);
        EditText passwordEdit = (EditText)findViewById(R.id.edit_password);
        String userName = userNameEdit.getText().toString();
        String password = passwordEdit.getText().toString();
        UserInfo userInfo = new UserInfo(userName, password);
        SPUserInfo.put(userInfo);
    }

    public void readInfo(View view) {
        TextView userNameText = (TextView)findViewById(R.id.text_user_name);
        TextView passwordText = (TextView)findViewById(R.id.text_password);
        UserInfo userInfo = SPUserInfo.get();
        userNameText.setText(userInfo.getUserName());
        passwordText.setText(userInfo.getPassword());
    }
}
上一篇 下一篇

猜你喜欢

热点阅读