First picture, because it is a trial version of the software, there is a watermark, really sorry.

Step-by-step instructions

1. Get the SharedPreferences object

ContextImpl:
public SharedPreferences getSharedPreferences(String name, int mode) {
}
public SharedPreferences getSharedPreferences(File file, int mode) {
}
Copy the code

Description:

1. Two overloaded methods, the first calling the second.

2, pass File method, can be used for cross-process read and write (first of all, this File supports fast process read and write permission), but generally now this mode is not recommended to use, there are data loss problems, later mentioned.

3. There are two maps in the intermediate cache:

private ArrayMap<String, File> mSharedPrefsPaths; Private static ArrayMap<String, ArrayMap<File, SharedPreferencesImpl>> sSharedPrefsCache; // Get the application's SharePreferencesImpl collection by package name. Get the SharePreferencesImpl through FileCopy the code

Create a SharedPreferencesImpl object to read the corresponding XML file

private void startLoadFromDisk() { synchronized (mLock) { mLoaded = false; } new Thread(" sharedpreferencesimp-load ") {public void run() {loadFromDisk(); } }.start(); } private void loadFromDisk() {synchronized (mLock) {if (mLock) {return; } if (mbackupfile.exists ()) {if (mbackupfile.exists ()) {if (mbackupfile.exists ()) {if (mbackupfile.exists ()) {if (mbackupfile.exists ()) { // Convert backup files to official files. // This is the reason why multiple processes are not secure. mFile.delete(); mBackupFile.renameTo(mFile); }}... mLock.notifyAll(); }Copy the code

Description:

1, mLoaded: // used to check whether the load is complete, synchronization lock handle multithreading problems

Check whether there is a backup file (name.xml.bak). If there are two reasons, one is that the backup file is not deleted due to an exception in the previous file writing. The other reason is that another process is writing the file, and the current process is preparing to write the file. Therefore, the file is deleted directly, resulting in the new write problem exception. (Not verified in practice)

Load the data from the XML file into the memory map. And wakes up all blocks of code waiting for mLock.

Create the EditorImpl object

public Editor edit() { synchronized (mLock) { awaitLoadedLocked(); } return new EditorImpl(); }Copy the code

Description:

AwaitLoadedLocked () polls and waits for mLoaded to be true, or if it is not, waits for mLock to be acquired, and wakes up after data is loaded. In this case, if the LOADED XML file is very large, the practice takes a long time, which may lead to ANR.

4. Add data to Editor

public final class EditorImpl implements Editor { private final Map<String, Object> mModified = Maps.newHashMap(); public Editor putInt(String key, int value) { synchronized (mLock) { mModified.put(key, value); return this; } } public Editor clear() { synchronized (mLock) { mClear = true; return this; }}}Copy the code

Description:

1, add data also add synchronization lock, prevent multithreaded data anomalies

2. Clear method can clear all previous old data, and commitToMemory() method will judge clear in this method. If true, the original read map data will be cleared and the new mModified data will be used.

5. Processing incoming data

private MemoryCommitResult commitToMemory() { if (mClear) { if (! mMap.isEmpty()) { changesMade = true; mMap.clear(); } mClear = false; } for (map.entry <String, Object> e: mmodified.entryset ()) {... // Check whether there is a key and whether the value corresponding to the key is the same. Return new MemoryCommitResult(memoryStateGeneration, keysModified, Listeners, mapToWriteToDisk); The setDiskWriteResult method is used to end writes to sp. There are CountDownLatch, apply, and commit ends that wait for this latch.Copy the code

Description:

1. MClear ==true Clears original data

2. Traverse the newly added data and compare it with the original data. If there is no corresponding key or the corresponding value of the corresponding key is different, the new data will be overwritten and added.

MemoryCommitResult: This object is useful because setDiskWriteResult is used to end writes to sp. There are countdownlatches for which apply and commit ends wait.

6. Apply () submits data asynchronously

SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
Copy the code

QueuedWork: QueuedWork: QueuedWork: QueuedWork: QueuedWork: QueuedWork: QueuedWork: QueuedWork: QueuedWork

But the reason for asynchrony depends on the enqueueDiskWrite() argument.

7. Commit () Synchronizes the commit data

SharedPreferencesImpl.this.enqueueDiskWrite(    mcr, null /* sync write on this thread okay */);
Copy the code

Call enqueueDiskWrite() directly, and wait with a lock until the sp writes data, so it is synchronous, and this returns success/failure of the write.

8. EnqueueDiskWrite handles synchronous and asynchronous data submission

private void enqueueDiskWrite(final MemoryCommitResult mcr, final Runnable postWriteRunnable) { final boolean isFromSyncCommit = (postWriteRunnable == null); If (isFromSyncCommit) {Boolean wasEmpty = false; synchronized (mLock) { wasEmpty = mDiskWritesInFlight == 1; } if (wasEmpty) { writeToDiskRunnable.run(); // Sync is run directly, and return; } } QueuedWork.queue(writeToDiskRunnable, ! isFromSyncCommit); // asynchronously add to queue}Copy the code

Description:

1. Use the postWriteRunnable==null parameter to distinguish asynchronous synchronization

If wasEmpty==true, no thread is writing files. MDiskWritesInFlight is ++ in Step 5. If wasEmpty== 1, there is only one commit value available, so execute it directly.

If wasEmpty==false, even synchronous commits need to be queued, but no delay is required.

9. Write files

// Note: must hold mWritingToDiskLockprivate void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) { if (fileExists) { if (! NeedsWrite) {// If you do not need to write now, abort immediately. This is the result of asynchronous apply. return; } boolean backupFileExists = mBackupFile.exists(); if (DEBUG) { backupExistsTime = System.currentTimeMillis(); } // If the backup file does not exist, rename the original file to the backup file, as shown in the screenshot below. If there is, there was a problem writing the file before, so delete the existing file. There is still a problem -- a problem between multiple processes, which can cause writing interruptions in another process, or data confusion. if (! backupFileExists) { if (! mFile.renameTo(mBackupFile)) { Log.e(TAG, "Couldn't rename file " + mFile + " to backup file " + mBackupFile); mcr.setDiskWriteResult(false, false); return; } } else { mFile.delete(); }..................... XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str); ... / / mode according to modify the file permissions ContextImpl setFilePermissionsFromMode (mFile. GetPath (), mMode, 0). }Copy the code

Description:

WriteToFile () is locked before writeToFile() is called, so there are no problems between the same process, but there are problems between multiple processes.

2. Handle the existing file and determine whether needsWrite should be performed.

3. If the file already exists, check whether the backup file exists. If not, rename the existing file as the backup file

4, has made the deal with file already exists, whether backup file exists, if any, instructions for the previous file when there is a problem, remove the existing file so, that there is another problem – problem between multiple processes, will cause is another process is writing files are deleted, resulting in abnormal data.

Conclusion:

Almost read to this, the back to see the principle of MMVK, after looking at SP, or feel that the performance is really poor, multi-process security is also a problem.

Advice:

1. It is recommended to use private mode instead of cross-process processing. Cross-process can be + SP via process communication or use contentProvide.

2. It is recommended not to store too many things in an XML file to prevent long writing time from causing ANR.

3. Apply gives priority to writing data, and commit only when it is important to write results

4. Apply and commit are called only once after all data is added to prevent multiple files from being written.

\