Android data storage (2)-SP VS DataStore VS MMKV

一、SharedPreferences

        Unlike file storage, if you want to save a relatively small set of key-values, you should use the SharedReferences API. The SharedReferences object points to a file containing key-value pairs and provides simple read and write methods.

        This article gradually introduces Preference and MMKV starting from SharedReferences.

1.1 Get the SharedPreferences object

        To use SharedPreferences to store data, you first need to get the SharedPreferences object. Android mainly provides two methods for obtaining the SharedPreferences object.

getSharedPreferences() method in the Context class

This method receives two parameters:

  • The first parameter is used to specify the name of the SharedPreferences file. If the specified file does not exist, one will be created. SharedPreferences files are stored in the /data/data/<package name>/shared_prefs/directory.

  • The second parameter is used to specify the operation mode, currently only MODE_PRIVATE is optional , it is the default operation mode , and the effect is the same as directly passing in 0, which means that only the current application can modify the SharedPreferences file read and write.

getPreferences() method in Activity class

        This method is very similar to the getSharedPreferences() method in Context, but it only accepts an operation mode parameter, because when using this method, the currently active class name will be automatically used as the file name of SharedPreferences.

NOTE: MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE modes have been deprecated since API level 17. Throws SecurityException if used.

The getSharedPreferences() method in the Context class         is used here :

public class SPUtils {
    //保存在手机里面的文件名
    public static final String FILE_NAME = "scc_data";

    private static final SPUtils spUtils = new SPUtils();
    public static SPUtils getInstance() {
        return spUtils;
    }
    private SPUtils() {
    }
    private SharedPreferences getSP() {
        return AppGlobalUtils.getApplication().getSharedPreferences(FILE_NAME,
                Context.MODE_PRIVATE);
    }
}

File save path: /data/data/com.scc.datastorage/shared_prefs/scc_data.xml

1.2 Write data

        Pass the key and value to write through methods such as putInt() and putString(). Then call apply() or commit() to save the changes.

    private void putSp() {
        SPUtils.getInstance().put("name","Scc");
        SPUtils.getInstance().put("age",20);
    }
    
    /**
     * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
     * 如果仅用到String等个别类型,可单独写方法
     */
    public void put(String key, Object value) {
        if(MStringUtils.isNullOrEmpty(key)){
            return;
        }
        SharedPreferences.Editor editor = getSP().edit();
        if (value instanceof String) {
            editor.putString(key, (String)value);
        } else if (value instanceof Integer) {
            editor.putInt(key, (Integer) value);
        } else if (value instanceof Boolean) {
            editor.putBoolean(key, (Boolean) value);
        } else if (value instanceof Float) {
            editor.putFloat(key, (Float) value);
        } else if (value instanceof Long) {
            editor.putLong(key, (Long) value);
        }
        SharedPreferencesCompat.apply(editor);
    }

1.3 Read data

        Call methods such as getInt() and getString() to get data from the SharedPreference, providing the key for the desired value, and optionally returning a default value if the key does not exist.

    private void getSp() {
        Log.e("SP","SpString:"+SPUtils.getInstance().getString("name"));
        Log.e("SP","SpInt:"+SPUtils.getInstance().getInt("age"));
    }
    
    //获取String类型数据
    public String getString(String key) {
        if (MStringUtils.isNullOrEmpty(key)) {
            return "";
        }
        return getSP().getString(key, "");
    }
    //获取Int类型数据
    public Integer getInt(String key) {
        if (MStringUtils.isNullOrEmpty(key)) {
            return 0;
        }
        return getSP().getInt(key, 0);
    }

1.4 Delete data

        Call the remove() method to remove data from the SharedPreference, providing the key with the desired value.

    private void removeSp() {
        SPUtils.getInstance().remove("name");
        Log.e("SP","Remove:"+SPUtils.getInstance().getString("name"));
        Log.e("SP","SpInt:"+SPUtils.getInstance().getInt("age"));
    }
    //移除某个key值已经对应的值
    public void remove(String key) {
        if (!MStringUtils.isNullOrEmpty(key)) {
            SharedPreferences.Editor editor = getSP().edit();
            editor.remove(key);
            SharedPreferencesCompat.apply(editor);
        }
    }

        Then let's look at the contents of scc_data.xml:

        SharedPreference can be used to store some simple key-value pairs, such as login account password and some basic user information.

二、Jetpack Preferences

        DataStore is a component in Android Jetpack. It is a data storage solution. Like SharedPreferences, it is stored in the form of key-value. Jetpack DataStore is a new and improved data storage solution designed to replace SharedPreferences, allowing applications to store data in an asynchronous, transactional manner.

Jetpack DataStore you always want to know about it? _Shuaici's Blog-CSDN Blog

3. MMKV—a high-performance general-purpose key-value component based on mmap

        MMKV is a key-value component based on mmap memory mapping. The underlying serialization/deserialization is implemented using protobuf, with high performance and strong stability . It has been used on WeChat since mid-2015, and its performance and stability have been verified by time. It has been ported to Android / macOS / Win32 / POSIX platforms, and is also open source .

git address

3.1 Advantages of MMKV

  • Very efficient : MMKV uses mmap to keep memory in sync with the file, and the operating system is responsible for writing the memory back to the file, so there is no need to worry about data loss caused by crash. Encode/decode numeric values ​​using protobuf to get the most out of Android for best performance.

  • Multi-process concurrency : MMKV supports concurrent read and write access between processes.

  • Ease of use : You can use MMKV anytime. All changes are saved immediately, no synchronization is required, and no apply call is required. Similar to the usage of SharedReferences, you can directly

  • Few files (small) : MMKV contains process locks, encode/decode helpers and mmap logic, etc. Very tidy.

3.2 Performance comparison (taken from MMKV official)

        We compare MMKV with SharedPreferences and SQLite, and repeat the learning operation 1k times. The relevant test code is in. The result becomes Android/MMKV/mmkvdemo/charts.

        (The test operating machine is Huawei Mate 20 Pro 128G, Android 10, each group is repeated 1k times, and the time unit is ms)

        The single-performance process can be seen : MMKV surpasses shared Preferences & SQLite, and has similar or superior performance in reading performance.

        Multi-process performance : MMMKV far surpasses MultiProcessSharedPreferences & SQLite & SQLite both in terms of write performance and read performance. MMKV is the best choice for Android multi-process key-value storage components.

3.3 Android access guide

        3.3.1 Introducing dependencies

        Add the following dependencies to the build.gradle corresponding to your project's app_module:

dependencies {
    implementation 'com.tencent:mmkv:1.2.12'
}

        3.3.2 Initialization

        The use of MMKV is very simple, and all changes take effect immediately without calling sync or apply . Initialize MMKV when the App starts, and set the root directory of MMKV (files/mmkv/), preferably in the Application:

    public void onCreate() {
        super.onCreate();
        //初始化MMKV
        String rootDir = MMKV.initialize(this);
        Log.e("SP","mmkv root: " + rootDir);
    }

        3.3.3 Write data

    private void putMMKV() {
        MMKVUtils.getInstance().encode("name","mmkv-Scc");
        MMKVUtils.getInstance().encode("age",40);
    }
    //保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
    public void encode(String key, Object object) {
        if (object instanceof String) {
            mmkv.encode(key, (String) object);
        } else if (object instanceof Integer) {
            mmkv.encode(key, (Integer) object);
        } else if (object instanceof Boolean) {
            mmkv.encode(key, (Boolean) object);
        } else if (object instanceof Float) {
            mmkv.encode(key, (Float) object);
        } else if (object instanceof Long) {
            mmkv.encode(key, (Long) object);
        } else if (object instanceof Double) {
            mmkv.encode(key, (Double) object);
        } else if (object instanceof byte[]) {
            mmkv.encode(key, (byte[]) object);
        } else {
            mmkv.encode(key, object.toString());
        }
    }
    //保存任何Parcelable的类型
    public void encode(String key, Parcelable parcelable) {
        Log.e("mmkv","Parcelable.start"+parcelable.getClass());
        boolean isTrue = mmkv.encode(key, parcelable);
        Log.e("mmkv","Parcelable.end"+isTrue);
    }

        You will find that he is basically the same as the above SharedReferences. Of course, MMKV storage supports far more data types than SharedReferences. Supported data types

  • The following Java language fundamental types are supported:

    • boolean、int、long、float、double、byte[]

  • The following Java classes and containers are supported:

    • String、Set<String>

    • any Parcelabletype

        3.3.4 Read data

    private void getMMKV() {
        Log.e("SP","MMKVString:"+MMKVUtils.getInstance().decodeString("name"));
        Log.e("SP","MMKVInt:"+MMKVUtils.getInstance().decodeInt("age"));
    }
    public String decodeString(String key) {
        return mmkv.decodeString(key, "");
    }
    public Integer decodeInt(String key) {
        return mmkv.decodeInt(key, 0);
    }    

        3.3.5 Removing data

    private void removeMMKV() {
        MMKVUtils.getInstance().removeValueForKey("name");
        Log.e("SP","Remove:"+MMKVUtils.getInstance().decodeString("name"));
        Log.e("SP","MMKVInt:"+MMKVUtils.getInstance().decodeInt("age"));
    }
    //移除某个key对
    public void removeValueForKey(String key) {
        mmkv.removeValueForKey(key);
    }

    //同时移除多个key对
    public void removeValuesForKeys(String[] strings) {
        mmkv.removeValuesForKeys(strings);
    }

    //清除所有key
    public void clearAll() {
        mmkv.clearAll();
    }

        3.3.6 Add data extension

  • Different businesses require different storage, and you can create your own instances separately.

  • If the business requires multi-process access, then add the flag bit MMKV.MULTI_PROCESS_MODE when initializing

3.4 Huawei mobile phones use Tencent MMKV framework with caution

Problem description :

        Use MMKV to replace the native SharedPreference. On some Huawei phones, the configuration file will be lost inexplicably, and the entire application will be like reinstalling.

Huawei mobile phones use Tencent MMKV framework with caution

        Then you can customize the file storage path .

        Default path: /data/data/com.scc.datastorage (your package name)/files/mmkv

    //自定义文件路径。
    String dir = getFilesDir().getAbsolutePath()+"mmkv-z2";
    String dirPath = MMKV.initialize(this,dir);
    
    //mmkv源码  
    public static String initialize(Context context, String rootDir) {
        MMKVLogLevel logLevel = MMKVLogLevel.LevelInfo;
        return initialize(context, rootDir, (MMKV.LibLoader)null, logLevel);
    }

3.5 SharedPreferences Migration

  • MMKV provides the importFromSharedPreferences() function, which can easily migrate data.

  • MMKV also implements two additional interfaces, SharedPreferences and SharedPreferences.Editor, which only need two or three lines of code during migration, and other CRUD operation codes do not need to be changed.

    private void importSharedPreferences() {
        //SharedPreferences preferences = getSharedPreferences("myData", MODE_PRIVATE);
        MMKV preferences = MMKV.mmkvWithID("myData");
        // 迁移旧数据
        {
            SharedPreferences old_man = getSharedPreferences("myData", MODE_PRIVATE);
            preferences.importFromSharedPreferences(old_man);
            old_man.edit().clear().commit();
        }
        // 跟以前用法一样
        SharedPreferences.Editor editor = preferences.edit();
        editor.putBoolean("bool", true);
        editor.putInt("int", Integer.MIN_VALUE);
        editor.putLong("long", Long.MAX_VALUE);
        editor.putFloat("float", -3.14f);
        editor.putString("string", "hello, imported");
        HashSet<String> set = new HashSet<String>();
        set.add("W"); set.add("e"); set.add("C"); set.add("h"); set.add("a"); set.add("t");
        editor.putStringSet("string-set", set);
        // 无需调用 commit()
        //editor.commit();
    }

3.6 macOS / Win32 / POSIX platforms

        For other platforms, you can go to the official documentation to access it yourself.

4. Related Links

Android data full solution processing

MMKV-git address

Jetpack Preferences

Android data storage (1) - file storage

Android data storage (3) - SQLite database instance

Guess you like

Origin blog.csdn.net/g984160547/article/details/122624761