Android 面試(六):你已經用 SharedPrefrence 的 apply() 替換 commit() 了嗎?

這是 面試系列 的第六期。本期我們將來探討一個有趣的東西 —— SharePrefrence 的兩種提交方式 apply()commit()。

往期內容傳遞:
Android 面試(一):說說 Android 的四種啟動模式
Android 面試(二):如何理解 Activity 的生命周期
Android 面試(三):用廣播 BroadcastReceiver 更新 UI 界面真的好嗎?
Android 面試(四):Android Service 你真的能應答自如了嗎?
Android 面試(五):探索 Android 的 Handler

開始

其實非常有趣,我們經常在開發中使用 SharePrefrence 保存一些輕量級數據,比如判斷是否是首次啟動,首次啟動進入引導頁,否則直接到主頁面,或者是其它的一些應用場景。

而我們也耳熟能詳這樣的寫法。

  • 根據 Context 獲取 SharedPreferences 對象
  • 利用 edit() 方法獲取 Editor 對象。
  • 通過 Editor 對象存儲 key-value 鍵值對數據。
  • 通過 commit() 方法提交數據。
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() 直接提交的時候會直接報黃色警告。

nanchen

commit() 和 apply() 到底有什么異同?

先說說相同點:

  • 二者都是提交 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() 方法不會有任何失敗的提示。

那到底使用 commit() 還是 apply()?

大多數情況下,我們都是在同一個進程中,這時候的 SharedPrefrence 都是單實例,一般不會出現并發沖突,如果對提交的結果不關心的話,我們非常建議用 apply() ,當然需要確保操作成功且有后續操作的話,還是需要用 commit() 的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 0.寫在前面 (全文約4k字,已經投稿 鴻洋 老師的公眾號[https://mp.weixin.qq.com/s/...
    普通的程序員閱讀 6,716評論 9 65
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學已經沒多少時間了。班主任說已經安排了三個家長分享經驗。 放學鈴聲...
    飄雪兒5閱讀 7,575評論 16 22
  • 今天感恩節哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會,身份的轉變要...
    迷月閃星情閱讀 10,616評論 0 11
  • 可愛進取,孤獨成精。努力飛翔,天堂翱翔。戰爭美好,孤獨進取。膽大飛翔,成就輝煌。努力進取,遙望,和諧家園??蓯塾巫?..
    趙原野閱讀 2,778評論 1 1
  • 在妖界我有個名頭叫胡百曉,無論是何事,只要找到胡百曉即可有解決的辦法。因為是只狐貍大家以訛傳訛叫我“傾城百曉”,...
    貓九0110閱讀 3,349評論 7 3