SharePreferencesの2つのコミット方法:commitとapplyの違い


1.まず違いを言います.
  • commit()コミットはtrueを正常に返し、apply()コミットは値
  • を返さなかった.
  • apply()のコミットに失敗した場合、
  • というプロンプトはありません.
  • は、データを先に原子にコミットし(原子コミットとは何か:トランザクションのすべての変更動作、またはすべて発生するか、1つも発生しないか)メモリに送信し、apply()を非同期でディスクにコミットします.commit()は、ディスクに同期してコミットされます.メモリストレージはすべてMapを更新する値です(具体的には以下のソースコードを参照).

  • 2.再分析の優劣
    a.効率的には、apply()はcommit()よりも効率的である.複数回コミットされた場合、書き込みディスクに時間がかかり、commit()は同期書き込みであるため、前のcommit()が実行されなかった場合、後の待機が必要である(データ書き込みの過程で、データ書き込みの正確性を保証するために、同期ロックでデータの安全性を保証する)b.しかしcommit()は書き込みデータの成功性を保証することができるため、apply()は書き込みを呼び出すだけで返されます.アプリケーションの再起動などの極端な場合、apply()はデータの書き込みに失敗する可能性がありますが、失敗した場合はわかりません.まとめcolor{red}{まとめ}まとめ:結果に厳しい場合はcommit()を使用します.結果に強く要求しないが、パフォーマンスを重視する場合はapply()を使用します.
    次は関連するソースコードです.
    public boolean commit() {
        MemoryCommitResult mcr = commitToMemory();
        SharedPreferencesImpl.this.enqueueDiskWrite(mcr, null /* sync write on this thread okay */);
        try {
            mcr.writtenToDiskLatch.await();
        } catch (InterruptedException e) {
            return false;
        }
        notifyListeners(mcr);
        return mcr.writeToDiskResult;
    }
    
    public void apply() {
        final MemoryCommitResult mcr = commitToMemory();
        final Runnable awaitCommit = new Runnable() {
            public void run() {
                try {
                    mcr.writtenToDiskLatch.await();
                } catch (InterruptedException ignored) {
                }
            }
        };
        QueuedWork.add(awaitCommit);
        Runnable postWriteRunnable = new Runnable() {
            public void run() {
                awaitCommit.run();
                QueuedWork.remove(awaitCommit);
            }
        };
        SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
        // Okay to notify the listeners before it's hit disk
        // because the listeners should always get the same
        // SharedPreferences instance back, which has the
        // changes reflected in memory.
        notifyListeners(mcr);
    }
    
    private MemoryCommitResult commitToMemory() {
        MemoryCommitResult mcr = new MemoryCommitResult();
        synchronized (SharedPreferencesImpl.this) {
            ...
            synchronized (this) {
                ...
                for (Map.Entry<String, Object> e : mModified.entrySet()) {
                    String k = e.getKey();
                    Object v = e.getValue();
                    if (v == this || v == null) {
                        if (!mMap.containsKey(k)) {
                            continue;
                        }
                        mMap.remove(k);
                    } else {
                        if (mMap.containsKey(k)) {
                            Object existingValue = mMap.get(k);
                            if (existingValue != null && existingValue.equals(v)) {
                                continue;
                            }
                        }
                        mMap.put(k, v);
                    }
                    ...
                }
                mModified.clear();
            }
        }
        return mcr;
    }
    
    private void enqueueDiskWrite(final MemoryCommitResult mcr,final Runnable postWriteRunnable) {
        final Runnable writeToDiskRunnable = new Runnable() {
            public void run() {
                synchronized (mWritingToDiskLock) {
                    writeToFile(mcr);
                }
                synchronized (SharedPreferencesImpl.this) {
                    mDiskWritesInFlight--;
                }
                if (postWriteRunnable != null) {
                    postWriteRunnable.run();
                }
            }
        };
        final boolean isFromSyncCommit = (postWriteRunnable == null);
        // Typical #commit() path with fewer allocations, doing a write on
        // the current thread.
        if (isFromSyncCommit) {
            boolean wasEmpty = false;
            synchronized (SharedPreferencesImpl.this) {
                wasEmpty = mDiskWritesInFlight == 1;
            }
            if (wasEmpty) {
                writeToDiskRunnable.run();
                return;
            }
    QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
    }