“This is the second day of my participation in the First Challenge 2022.

First, the SharedPreferences

Unlike the way files are stored, the SharedReferences API should be used if the set of keys to be stored is relatively small. The SharedReferences object points to a file containing key-value pairs and provides simple read and write methods.

Preference and MMKV are introduced gradually from SharedReferences.

1.1 Obtaining the SharedPreferences Object

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

The getSharedPreferences() method in the Context class

This method takes two arguments:

  • The first parameter specifies the name of the SharedPreferences file, or one will be created if the specified file does not exist. The SharedPreferences file is stored in the /data/data/ /shared_prefs/ directory.

  • The second parameter specifies the mode of operation. Currently, only MODE_PRIVATE is available. It is the default mode and has the same effect as 0, indicating that only the current application can read and write the SharedPreferences file.

The getPreferences() method in the Activity class

This method is similar to the getSharedPreferences() method in the Context, except that it only takes an action mode parameter because the name of the currently active class is automatically used as the file name for SharedPreferences.

Note: Since API level 17, MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE modes have been deprecated. Throws a SecurityException if used.

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

public class SPUtils {
    // The name of the file saved in the phone
    public static final String FILE_NAME = "scc_data";

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

File path: / data/data/com. SCC. Datastorage shared_prefs/scc_data. The XML

1.2 Writing Data

Pass keys and values to be written through methods such as putInt() and putString(). Then call apply() or commit() to save the changes.


    private void putSp(a) {
        SPUtils.getInstance().put("name"."Scc");
        SPUtils.getInstance().put("age".20);
    }
    
    /** * save method, we need to get the specific type of save data, and then call different save method according to the type */ if you only use the individual type such as String, can write a separate method */
    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);
    }

Copy the code

1.3 Reading Data

Methods such as getInt() and getString() are called to get data from SharedPreference, provide the key for the desired value, and optionally return the default if the key does not exist.

    private void getSp(a) {
        Log.e("SP"."SpString:"+SPUtils.getInstance().getString("name"));
        Log.e("SP"."SpInt:"+SPUtils.getInstance().getInt("age"));
    }
    
    // Get String data
    public String getString(String key) {
        if (MStringUtils.isNullOrEmpty(key)) {
            return "";
        }
        return getSP().getString(key, "");
    }
    // Get data of type Int
    public Integer getInt(String key) {
        if (MStringUtils.isNullOrEmpty(key)) {
            return 0;
        }
        return getSP().getInt(key, 0);
    }
Copy the code

1.4 Deleting Data

The remove() method is called to remove the data from SharedPreference, providing a key for the desired value.

    private void removeSp(a) {
        SPUtils.getInstance().remove("name");
        Log.e("SP"."Remove:"+SPUtils.getInstance().getString("name"));
        Log.e("SP"."SpInt:"+SPUtils.getInstance().getInt("age"));
    }
    // Remove the corresponding value of a key
    public void remove(String key) {
        if (!MStringUtils.isNullOrEmpty(key)) {
            SharedPreferences.Editor editor = getSP().edit();
            editor.remove(key);
            SharedPreferencesCompat.apply(editor);
        }
    }
Copy the code

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

Some simple key-value pair stores can use SharedPreference, such as the login account password and some basic user information.

Second, the Jetpack Preferences

By default, Preference uses SharedReferences to hold values. The SharedReferences API allows simple key-value pairs to be read and written to files saved across application operations. The Preference Library uses a private SharedReferences instance, so only your application can access it.

Since I rarely use Jetpack Preferences, I will not introduce it here. If you are interested, you can go to the official documentation.

3. MMKV — MMAP-based high-performance universal key-value component

MMKV is a key-value component based on MMAP memory mapping. Protobuf is used to realize the underlying serialization/deserialization, which has high performance and strong stability. It has been used on wechat since the middle of 2015, and its performance and stability have been verified over time. Has been ported to Android/macOS/Win32 / POSIX platform, and open source.

Git address

3.1 MMKV advantage

  • Very efficient: MMKV uses Mmap to keep the memory synchronized with the file, and the operating system is responsible for writing the memory back to the file, without worrying about data loss caused by crash. Using Protobuf to encode/decode values, make full use of Android for optimal performance.
  • Multi-process concurrency: THE MMKV supports concurrent read and write access between processes.
  • Easy to use: You can always use MMKV. All changes are saved immediately, without synchronization or apply calls. Similar to SharedReferences, can be used directly
  • A few files (small) : MMKV contains process locks, encoding/decoding helpers, MMAP logic, etc. Very clean and tidy.

3.2 Performance Comparison (from MMKV official)

We compare MMKV with SharedPreferences and SQLite and repeat the learning operation for 1K times. The relevant test code is in. The result is Android/MMKV/ MMKvdemo/chart.

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

Single-performance processes visible: MMKV exceeds shared Preferences & SQLite, and has similar or superior read performance.

Multi-process performance: MMMKV in writing performance and reading performance, are far beyond MultiProcessSharedPreferences & SQLite & SQLite, MMKV in Android multi-process key – value storage component is the default choice.

3.3 Android Access Guide

3.3.1 Introducing dependencies

Add the following dependencies to build. Gradle for your project’s app_module:

dependencies {
    implementation 'com. Tencent: MMKV: 1.2.12'
}
Copy the code

3.3.2 rainfall distribution on 10-12 initialization

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

    public void onCreate(a) {
        super.onCreate();
        // Initialize MMKV
        String rootDir = MMKV.initialize(this);
        Log.e("SP"."mmkv root: " + rootDir);
    }
Copy the code

3.3.3 Writing Data

    private void putMMKV(a) {
        MMKVUtils.getInstance().encode("name"."mmkv-Scc");
        MMKVUtils.getInstance().encode("age".40);
    }
    // To save the data, we need to get the specific type of save data, and then call different save methods according to the type
    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()); }}// Save any Parcelable types
    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);
    }
Copy the code

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

  • The following Java language base types are supported:

    • Boolean, int, long, float, double, byte[]
  • Support for the following Java classes and containers:

    • String, Set the < String >
    • anyParcelableThe type of

3.3.4 Reading Data

    private void getMMKV(a) {
        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);
    }    
Copy the code

3.3.5 Removing Data

    private void removeMMKV(a) {
        MMKVUtils.getInstance().removeValueForKey("name");
        Log.e("SP"."Remove:"+MMKVUtils.getInstance().decodeString("name"));
        Log.e("SP"."MMKVInt:"+MMKVUtils.getInstance().decodeInt("age"));
    }
    // Remove a key pair
    public void removeValueForKey(String key) {
        mmkv.removeValueForKey(key);
    }

    // Remove multiple key pairs simultaneously
    public void removeValuesForKeys(String[] strings) {
        mmkv.removeValuesForKeys(strings);
    }

    // Clear all keys
    public void clearAll(a) {
        mmkv.clearAll();
    }
Copy the code

3.3.6 Adding Data Extension

  • Different services require different storage, and you can create your own instance.
  • The service requires multi-process access, so the flag bit mmKv.multi_process_mode is added during initialization

3.4 Huawei mobile phones should be cautious about using Tencent MMKV framework

Problem Description:

Using MMKV instead of native SharedPreference, on some Huawei phones, the configuration file will be lost for no reason and the entire application will feel like a re-installation.

Huawei mobile phones cautiously use Tencent MMKV framework

Then you can customize the file storage path.

The default path: / data/data/com. SCC. Datastorage (your package name)/files/MMKV


    // Customize the file path.
    String dir = getFilesDir().getAbsolutePath()+"mmkv-z2";
    String dirPath = MMKV.initialize(this,dir);
    
    / / MMKV source code
    public static String initialize(Context context, String rootDir) {
        MMKVLogLevel logLevel = MMKVLogLevel.LevelInfo;
        return initialize(context, rootDir, (MMKV.LibLoader)null, logLevel);
    }

Copy the code

3.5 SharedPreferences migration

  • MMKV provides importFromSharedPreferences () function, can be more convenient to transfer data.

  • MMKV also additional implementation of SharedPreferences, SharedPreferences.Editor these two interfaces, in the migration of only two or three lines of code, other CRUD operation code need not change.

    private void importSharedPreferences(a) {
        //SharedPreferences preferences = getSharedPreferences("myData", MODE_PRIVATE);
        MMKV preferences = MMKV.mmkvWithID("myData");
        // Migrate old data
        {
            SharedPreferences old_man = getSharedPreferences("myData", MODE_PRIVATE);
            preferences.importFromSharedPreferences(old_man);
            old_man.edit().clear().commit();
        }
        // The same as before
        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.14 f);
        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);
        // No need to call commit()
        //editor.commit();
    }
Copy the code

3.6 macOS/Win32 / POSIX platform

Other platforms can access the official documents themselves.

4. Related links

Android data processing scheme

Android Data Store (1)- File storage