這是 面試系列 的第六期或舞。本期我們將來探討一個有趣的東西 —— SharePrefrence 的兩種提交方式 apply()
和 commit()
哗魂。
往期內(nèi)容傳遞:
Android 面試(一):說說 Android 的四種啟動模式
Android 面試(二):如何理解 Activity 的生命周期
Android 面試(三):用廣播 BroadcastReceiver 更新 UI 界面真的好嗎勇婴?
Android 面試(四):Android Service 你真的能應答自如了嗎忱嘹?
Android 面試(五):探索 Android 的 Handler
開始
其實非常有趣,我們經(jīng)常在開發(fā)中使用 SharePrefrence 保存一些輕量級數(shù)據(jù)咆耿,比如判斷是否是首次啟動德谅,首次啟動進入引導頁爹橱,否則直接到主頁面萨螺,或者是其它的一些應用場景。
而我們也耳熟能詳這樣的寫法愧驱。
- 根據(jù) Context 獲取 SharedPreferences 對象
- 利用 edit() 方法獲取 Editor 對象慰技。
- 通過 Editor 對象存儲 key-value 鍵值對數(shù)據(jù)。
- 通過 commit() 方法提交數(shù)據(jù)组砚。
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);
// 一些業(yè)務代碼
......
SharedPreferences preferences = getSharedPreferences("name",MODE_PRIVATE);
if (preferences.getBoolean(IS_FIRST_IN,true)){
// 跳轉(zhuǎn)引導頁面
startActivity(new Intent(this,GuideActivity.class));
finish();
}else{
// 跳轉(zhuǎn)主頁面
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();
}
}
從代碼中可以看到吻商,一陣混亂操作,沒啥特別的地方糟红,但早期開發(fā)的人員應該知道艾帐,之前我們都是比較青睞 commit()
進行提交的乌叶。而現(xiàn)在 Android Studio 在我們使用 commit()
直接提交的時候會直接報黃色警告。
commit() 和 apply() 到底有什么異同柒爸?
先說說相同點:
- 二者都是提交 Prefrence 修改數(shù)據(jù)准浴;
- 二者都是原子過程。
不同點直接上源碼吧捎稚,先看看 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()
方法的注釋也就是兩點:
- 會返回執(zhí)行結(jié)果乐横。
- 如果不考慮結(jié)果并且是在主線程執(zhí)行可以考慮
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()
不一樣的地方是葡公,它使用的是異步而不是同步,它會立即將更改提交到內(nèi)存条霜,然后異步提交到硬盤催什,并且如果失敗將沒有任何提示。
總結(jié)一下不同點:
-
commit()
是直接同步地提交到硬件磁盤宰睡,因此蛆楞,多個并發(fā)的采用commit()
做提交的時候,它們會等待正在處理的commit()
保存到磁盤后再進行操作夹厌,從而降低了效率豹爹。而apply()
只是原子的提交到內(nèi)容,后面再調(diào)用apply()
的函數(shù)進行異步操作矛纹。 - 翻源碼可以發(fā)現(xiàn)
apply()
返回值為 void臂聋,而commit()
返回一個 boolean 值代表是否提交成功。 -
apply()
方法不會有任何失敗的提示或南。
那到底使用 commit() 還是 apply()孩等?
大多數(shù)情況下,我們都是在同一個進程中采够,這時候的 SharedPrefrence
都是單實例肄方,一般不會出現(xiàn)并發(fā)沖突,如果對提交的結(jié)果不關(guān)心的話蹬癌,我們非常建議用 apply()
权她,當然需要確保操作成功且有后續(xù)操作的話,還是需要用 commit()
的逝薪。