174/** 175 * Commit your preferences changes back from this Editor to the 176 * {@link SharedPreferences} object it is editing. This atomically 177 * performs the requested modifications, replacing whatever is currently 178 * in the SharedPreferences. 179 * 180 * <p>Note that when two editors are modifying preferences at the same 181 * time, the last one to call commit wins. 182 * 183 * <p>If you don't care about the return value and you're 184 * using this from your application's main thread, consider 185 * using {@link #apply} instead. 186 * 187 * @return Returns true if the new values were successfully written 188 * to persistent storage. 189 */ 190booleancommit(); 191 192/** 193 * Commit your preferences changes back from this Editor to the 194 * {@link SharedPreferences} object it is editing. This atomically 195 * performs the requested modifications, replacing whatever is currently 196 * in the SharedPreferences. 197 * 198 * <p>Note that when two editors are modifying preferences at the same 199 * time, the last one to call apply wins. 200 * 201 * <p>Unlike {@link #commit}, which writes its preferences out 202 * to persistent storage synchronously, {@link #apply} 203 * commits its changes to the in-memory 204 * {@link SharedPreferences} immediately but starts an 205 * asynchronous commit to disk and you won't be notified of 206 * any failures. If another editor on this 207 * {@link SharedPreferences} does a regular {@link #commit} 208 * while a {@link #apply} is still outstanding, the 209 * {@link #commit} will block until all async commits are 210 * completed as well as the commit itself. 211 * 212 * <p>As {@link SharedPreferences} instances are singletons within 213 * a process, it's safe to replace any instance of {@link #commit} with 214 * {@link #apply} if you were already ignoring the return value. 215 * 216 * <p>You don't need to worry about Android component 217 * lifecycles and their interaction with <code>apply()</code> 218 * writing to disk. The framework makes sure in-flight disk 219 * writes from <code>apply()</code> complete before switching 220 * states. 221 * 222 * <p class='note'>The SharedPreferences.Editor interface 223 * isn't expected to be implemented directly. However, if you 224 * previously did implement it and are now getting errors 225 * about missing <code>apply()</code>, you can simply call 226 * {@link #commit} from <code>apply()</code>. 227 */ 228voidapply();
494/** 495 * Enqueue an already-committed-to-memory result to be written 496 * to disk. 497 * 498 * They will be written to disk one-at-a-time in the order 499 * that they're enqueued. 500 * 501 * @param postWriteRunnable if non-null, we're being called 502 * from apply() and this is the runnable to run after 503 * the write proceeds. if null (from a regular commit()), 504 * then we're allowed to do this disk write on the main 505 * thread (which in addition to reducing allocations and 506 * creating a background thread, this has the advantage that 507 * we catch them in userdebug StrictMode reports to convert 508 * them where possible to apply() ...) 509 */ 510privatevoidenqueueDiskWrite(final MemoryCommitResult mcr, 511final Runnable postWriteRunnable){ 512final Runnable writeToDiskRunnable = new Runnable() { 513publicvoidrun(){ 514synchronized (mWritingToDiskLock) { 515 writeToFile(mcr); 516 } 517synchronized (SharedPreferencesImpl.this) { 518 mDiskWritesInFlight--; 519 } 520if (postWriteRunnable != null) { 521 postWriteRunnable.run(); 522 } 523 } 524 }; 525 526finalboolean isFromSyncCommit = (postWriteRunnable == null); 527 528// Typical #commit() path with fewer allocations, doing a write on 529// the current thread. 530if (isFromSyncCommit) { 531boolean wasEmpty = false; 532synchronized (SharedPreferencesImpl.this) { 533 wasEmpty = mDiskWritesInFlight == 1; 534 } 535if (wasEmpty) { 536 writeToDiskRunnable.run(); 537return; 538 } 539 } 540 541 QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable); 542 }
从执行结果可以发现,使用 apply() 因为是异步操作,基本上是不耗费时间的,效率上都是 OK 的。从这个结论上来看,apply() 影响效率的地方,在 sp.edit() 方法。
那么,再看看 edit() 方法是如何实现的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
275public Editor edit(){ 276// TODO: remove the need to call awaitLoadedLocked() when 277// requesting an editor. will require some work on the 278// Editor, but then we should be able to do: 279// 280// context.getSharedPreferences(..).edit().putString(..).apply() 281// 282// ... all without blocking. 283synchronized (this) { 284 awaitLoadedLocked(); 285 } 286 287returnnew EditorImpl(); 288 }