SharePreferencesの2つのコミット方法:commitとapplyの違い
18003 ワード
1.まず違いを言います. commit()コミットはtrueを正常に返し、apply()コミットは値 を返さなかった. apply()のコミットに失敗した場合、 というプロンプトはありません.は、データを先に原子にコミットし(原子コミットとは何か:トランザクションのすべての変更動作、またはすべて発生するか、1つも発生しないか)メモリに送信し、apply()を非同期でディスクにコミットします.commit()は、ディスクに同期してコミットされます.メモリストレージはすべてMapを更新する値です(具体的には以下のソースコードを参照).
2.再分析の優劣
a.効率的には、apply()はcommit()よりも効率的である.複数回コミットされた場合、書き込みディスクに時間がかかり、commit()は同期書き込みであるため、前のcommit()が実行されなかった場合、後の待機が必要である(データ書き込みの過程で、データ書き込みの正確性を保証するために、同期ロックでデータの安全性を保証する)b.しかしcommit()は書き込みデータの成功性を保証することができるため、apply()は書き込みを呼び出すだけで返されます.アプリケーションの再起動などの極端な場合、apply()はデータの書き込みに失敗する可能性がありますが、失敗した場合はわかりません.まとめcolor{red}{まとめ}まとめ:結果に厳しい場合はcommit()を使用します.結果に強く要求しないが、パフォーマンスを重視する場合はapply()を使用します.
次は関連するソースコードです.
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);
}