這是 面試系列 的第六期。本期咱們未來探討一個有趣的東西 —— SharePrefrence 的兩種提交方式 apply()
和 commit()
。java
往期內容傳遞:
Android 面試(一):說說 Android 的四種啓動模式
Android 面試(二):如何理解 Activity 的生命週期
Android 面試(三):用廣播 BroadcastReceiver 更新 UI 界面真的好嗎?
Android 面試(四):Android Service 你真的能應答自如了嗎?
Android 面試(五):探索 Android 的 Handler面試
其實很是有趣,咱們常常在開發中使用 SharePrefrence 保存一些輕量級數據,好比判斷是不是首次啓動,首次啓動進入引導頁,不然直接到主頁面,或者是其它的一些應用場景。微信
而咱們也耳熟能詳這樣的寫法。併發
根據 Context 獲取 SharedPreferences 對象app
利用 edit() 方法獲取 Editor 對象。異步
經過 Editor 對象存儲 key-value 鍵值對數據。async
經過 commit() 方法提交數據。ide
public class SplashActivity extends AppCompatActivity { public static final String SP_KEY = "com.zxedu.myapplication.SplashActivity_SP_KEY"; public static final String IS_FIRST_IN = "com.zxedu.myapplication.SplashActivity_IS_FIRST_IN"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 一些業務代碼 ...... SharedPreferences preferences = getSharedPreferences("name",MODE_PRIVATE); if (preferences.getBoolean(IS_FIRST_IN,true)){ // 跳轉引導頁面 startActivity(new Intent(this,GuideActivity.class)); finish(); }else{ // 跳轉主頁面 startActivity(new Intent(this,MainActivity.class)); } } } public class GuideActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); getSharedPreferences(SplashActivity.SP_KEY,MODE_PRIVATE).edit().putBoolean(SplashActivity.IS_FIRST_IN,false).apply(); } }
從代碼中能夠看到,一陣混亂操做,沒啥特別的地方,但早期開發的人員應該知道,以前咱們都是比較青睞 commit()
進行提交的。而如今 Android Studio 在咱們使用 commit()
直接提交的時候會直接報黃色警告。函數
先說說相同點:ui
兩者都是提交 Prefrence 修改數據;
兩者都是原子過程。
不一樣點直接上源碼吧,先看看 commit()
方法的定義:
/** * Commit your preferences changes back from this Editor to the * {@link SharedPreferences} object it is editing. This atomically * performs the requested modifications, replacing whatever is currently * in the SharedPreferences. * * <p>Note that when two editors are modifying preferences at the same * time, the last one to call commit wins. * * <p>If you don't care about the return value and you're * using this from your application's main thread, consider * using {@link #apply} instead. * * @return Returns true if the new values were successfully written * to persistent storage. */ boolean commit();
綜合一下 commit()
方法的註釋也就是兩點:
會返回執行結果。
若是不考慮結果而且是在主線程執行能夠考慮 apply()
。
再看看 apply()
方法的定義:
/** * Commit your preferences changes back from this Editor to the * {@link SharedPreferences} object it is editing. This atomically * performs the requested modifications, replacing whatever is currently * in the SharedPreferences. * * <p>Note that when two editors are modifying preferences at the same * time, the last one to call apply wins. * * <p>Unlike {@link #commit}, which writes its preferences out * to persistent storage synchronously, {@link #apply} * commits its changes to the in-memory * {@link SharedPreferences} immediately but starts an * asynchronous commit to disk and you won't be notified of * any failures. If another editor on this * {@link SharedPreferences} does a regular {@link #commit} * while a {@link #apply} is still outstanding, the * {@link #commit} will block until all async commits are * completed as well as the commit itself. * * <p>As {@link SharedPreferences} instances are singletons within * a process, it's safe to replace any instance of {@link #commit} with * {@link #apply} if you were already ignoring the return value. * * <p>You don't need to worry about Android component * lifecycles and their interaction with <code>apply()</code> * writing to disk. The framework makes sure in-flight disk * writes from <code>apply()</code> complete before switching * states. * * <p class='note'>The SharedPreferences.Editor interface * isn't expected to be implemented directly. However, if you * previously did implement it and are now getting errors * about missing <code>apply()</code>, you can simply call * {@link #commit} from <code>apply()</code>. */ void apply();
略微有點長,大概意思就是 apply()
跟 commit()
不同的地方是,它使用的是異步而不是同步,它會當即將更改提交到內存,而後異步提交到硬盤,而且若是失敗將沒有任何提示。
總結一下不一樣點:
commit()
是直接同步地提交到硬件磁盤,所以,多個併發的採用 commit()
作提交的時候,它們會等待正在處理的 commit()
保存到磁盤後再進行操做,從而下降了效率。而 apply()
只是原子的提交到內容,後面再調用 apply()
的函數進行異步操做。
翻源碼能夠發現 apply()
返回值爲 void,而 commit()
返回一個 boolean 值表明是否提交成功。
apply()
方法不會有任何失敗的提示。
大多數狀況下,咱們都是在同一個進程中,這時候的 SharedPrefrence
都是單實例,通常不會出現併發衝突,若是對提交的結果不關心的話,咱們很是建議用 apply()
,固然須要確保操做成功且有後續操做的話,仍是須要用 commit()
的。
作不完的開源,寫不完的矯情。歡迎掃描下方二維碼或者公衆號搜索「nanchen」關注個人微信公衆號,目前多運營 Android ,盡本身所能爲你提高。若是你喜歡,爲我點贊分享吧~