Android 键值对存储 SharedPreferencesManager

在这里插入图片描述

SharedPreferences 的介绍和特点:

Android 提供的一个类似 Redis 的键值对的存储方式、叫 SharedPreferences 。不同于 Map 容器(内存存储)、 这个存储方式为文件存储,最终是存在 Android 文件系统的 xml 文件中。

SharedPreferences 的特点:

1 只支持基本数据类型 ,例如字符串、整形、布尔等

2 不支持夸进程

3 不适合存储大量数据、例如比较大的实体 json 。大量数据建议做 sql 数据库存储

4 查询效率,虽然 SharedPreferences 在调研后知道了它已经内置了内存缓存。但是大量数据的查询效率上还是不如数据库。毕竟数据库有一些调优的手段或者索引等来增加查询速度

SharedPreferences 的封装 SPUtils 在应用中的使用和缺点:

SharedPreferences 虽然简单,但是在 Android 应用中有大量的使用场景,例如一些简单的状态,需要在下次杀死进程后再次启动 App 保留。

目前我调研我们应用中所使用的 SPUtils 封装查询到他在 C 端使用的场景多大 1300 处,可谓很频繁。

根据既有的 SPUtils 的代码做分析,发现他的几个不良的地方:

1 键值对的 key 管理混乱,业务 key 不应该和工具类混合在一起。这个这个工具类拿到其他地方或者其他应用就不可以使用。

2 每次 put 和 get 的时候都强制传 Context ,这样是不合理对使用也是很不方便的。在每个使用的地方我还得想办法把 Context 传过来,另外这样每次都相当于去打开和关闭一个文件句柄对效率也是非常存在影响,正确的做饭是在 application 初始化的时候全局配置一次,后面 put 和 get 应该只需要传关键参数 key value

3 不支持序列化

4 不支持内存缓存(之前认为SharedPreferences 没有内存缓存的时候 )

最终根据以上的痛点,我对 SharedPreferences 进行了重构

先来读一下它的 README.md

我所重构的 SharedPreferencesManager 的特点:

SharedPreferencesManager
一款支持内存映射的 SharedPreferences 工具库

基于 SharedPreferences 键值对的特性,在 SharedPreferences xml 文件缓存(磁盘缓存)前置了一层并发安全内存容器模型 ConcurrentHashMap

优先从内存缓存中取数据,大幅提高了读取数据的效率

支持对象的序列化和反序列化

和原生的 SharedPreferences 一样不支持夸进程

使用

Init

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        SharedPreferencesManager.getInstance().init(this);
    }
}
Put

SharedPreferencesManager.getInstance().put("keyString", "value");
Get

String s = (String) SharedPreferencesManager.getInstance().get("keyString", "x");

API

在这里插入图片描述
序列化用法

ShaerdPreferencesManager 提供了基于 Json 对非基本数据类型对象的序列化和反序列化的能力,思路为:

要保持类库的无依赖性,低耦合性。ShaerdPreferencesManager 只提供解析接口,对对象的序列化和反序列化不做具体实现,这一部分交由调用者去实现。

每个使用者所采用的 Json 解析方式不一样 (Gson、FastJson、Jackson等) ShaerdPreferencesManager 也不可能做全面覆盖。

public interface JsonParserStrategy {
    String encode(Object o);

    Object decode(String jsonString, Class<?> c);
}
建议用法:

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        SharedPreferencesManager.getInstance().init(this);
        SharedPreferencesManager.getInstance().setJsonParserStrategy(new JsonParserStrategy() {
            @Override
            public String encode(Object o) {
                String jsonString;
                //采用 gson 的实现解析方式
                Gson gson = new Gson();
                jsonString = gson.toJson(o);

                //采用 fastjson 的实现解析方式
                //jsonString = JSON.toJSONString(o);
                return jsonString;
            }

            @Override
            public Object decode(String jsonString, Class<?> c) {
                if (jsonString == null) {
                    return null;
                }

                Object o;
                //采用 gson 的实现解析方式
                Gson gson = new Gson();
                o = gson.fromJson(jsonString, c);

                //采用 fastjson 的实现解析方式
                // o = JSON.parseObject(jsonString, c);
                return o;
            }
        });
    }
}
Sample:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        User user = new User();
        user.name = "张三";
        user.age = 30;
        user.address = "北京市东城区银河SOHO";
        user.sex = "男";
        user.phone = "110";
        user.isVip = true;

        SharedPreferencesManager.getInstance().put("currentUser", user);

        User cacheUser = (User) SharedPreferencesManager.getInstance().get("currentUser", new User());
        Log.e(SharedPreferencesManager.class.getSimpleName(), cacheUser.toString());

    }

    class User {
        String name;
        int age;
        String address;
        String sex;
        String phone;
        boolean isVip;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", address='" + address + '\'' +
                    ", sex='" + sex + '\'' +
                    ", phone='" + phone + '\'' +
                    ", isVip=" + isVip +
                    '}';
        }
    }

}

TODO
增加内存缓存淘汰策略,淘汰内存缓存中使用低频的数据,防止内存占用过大。这部分数据如果再次需要被使用从磁盘缓存中取

总结:

我所重构的 SharedPreferencesManager 是解决了上述的 4 项痛点

另外在序列化的设计上增加了自认为巧妙的将实际解析接口提供给调用者。由调用者来决定使用什么解析库,或者手动去解析,这样保持工具库的纯净和无依赖性

但是最终这个库还有一个小缺点

就是 get 取数据的时候还需要做强制转化,虽然使用没有什么影响但是还是没那么优雅

最终还因为此工具库是基于 SharedPreferences 的封装,SharedPreferences 原本就不支持跨进程,所以这个库也不支持夸进程。

基于以上的点,最终这个库可能不会被采纳使用到实际项目中(因为微信有使用好几年基于 c/c++ 的成熟解决方法 MMKV),但是我不会因此而遗憾,写完这个库也能感觉自己的代码设计能力又进步了一点点

https://github.com/13120241790/SharedPreferencesManager

https://github.com/Tencent/MMKV

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Android TV 上获取蓝牙键值并将其传递给内核,您需要执行以下步骤: 1. 在 Android TV 上设置蓝牙配对设备。 2. 创建一个 BroadcastReceiver 以接收蓝牙键值。 3. 在 BroadcastReceiver 中处理蓝牙键值,并将其传递给内核。 以下是一个示例 BroadcastReceiver: ```java public class BluetoothReceiver extends BroadcastReceiver { private static final String TAG = "BluetoothReceiver"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); switch (state) { case BluetoothAdapter.STATE_OFF: Log.d(TAG, "Bluetooth off"); break; case BluetoothAdapter.STATE_TURNING_OFF: Log.d(TAG, "Turning Bluetooth off..."); break; case BluetoothAdapter.STATE_ON: Log.d(TAG, "Bluetooth on"); break; case BluetoothAdapter.STATE_TURNING_ON: Log.d(TAG, "Turning Bluetooth on..."); break; } } else if (BluetoothDevice.ACTION_KEY_EVENT.equals(action)) { int keyCode = intent.getIntExtra(BluetoothDevice.EXTRA_KEY_CODE, -1); if (keyCode != -1) { // Do something with the key code, such as pass it to the kernel } } } } ``` 您需要将此 BroadcastReceiver 注册到您的 Android TV 应用程序中,并使用 IntentFilter 指定要接收的蓝牙广播。例如,您可以在 onCreate() 方法中注册 BroadcastReceiver: ```java IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); filter.addAction(BluetoothDevice.ACTION_KEY_EVENT); registerReceiver(new BluetoothReceiver(), filter); ``` 在 BroadcastReceiver 中,您可以处理蓝牙键值并将其传递给内核。为了将键值传递给内核,您需要使用 JNI 调用 C 函数,并将键值作为参数传递。例如: ```java public class MyNativeLibrary { static { System.loadLibrary("my_native_library"); } public static native void sendKeyEvent(int keyCode); } ``` 您需要在您的 C 代码中实现 sendKeyEvent() 函数,以便它能够将键值传递给内核。例如: ```c JNIEXPORT void JNICALL Java_com_example_MyNativeLibrary_sendKeyEvent(JNIEnv *env, jobject obj, jint keyCode) { // Send key event to kernel } ``` 这是一个简单的示例,您需要根据您的特定用例进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值