前言
android中我们经常用SharedPreferences来存储数据,关于其基本用法我这里就不介绍了,下面介绍几个使用技巧
1 SharedPreferences一次性存储大量数据可以采用事务
有时我们需要一次性的存入大量的数据,比如存储500个数据,这时如果我们不采用事务,每次调用SharedPreferences.Editor 的putXxx()方法后,调用SharedPreferences.Editor 的commit()方法来提交,这样往往会导致UI线程比较慢,因为commit()是同步的,往往会比较耗时。正确的做法是采用“事务”,即先put完数据,最后一次性提交。可以参考下面的例子
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
put();
get();
}
private void put(){
SharedPreferences preferences = getSharedPreferences("test",MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
for (int i = 0 ; i < 500 ; i++){
editor.putInt("key" + i,2);
}
editor.commit();
}
private void get(){
SharedPreferences preferences = getSharedPreferences("test",MODE_PRIVATE);
for (int i = 0 ; i < 500 ; i++){
String key = "key" + i;
Log.d(TAG,"value " + i +":" +preferences.getInt(key,0));
}
}
程序运行输出结果为:
11-22 09:20:09.159 20370-20370/com.qiyei.javatest D/MainActivity: value 0:2
11-22 09:20:09.159 20370-20370/com.qiyei.javatest D/MainActivity: value 1:2
11-22 09:20:09.159 20370-20370/com.qiyei.javatest D/MainActivity: value 2:2
11-22 09:20:09.159 20370-20370/com.qiyei.javatest D/MainActivity: value 3:2
11-22 09:20:09.159 20370-20370/com.qiyei.javatest D/MainActivity: value 4:2
。。。。。。。。。。
11-22 09:20:09.175 20370-20370/com.qiyei.javatest D/MainActivity: value 497:2
11-22 09:20:09.175 20370-20370/com.qiyei.javatest D/MainActivity: value 498:2
11-22 09:20:09.175 20370-20370/com.qiyei.javatest D/MainActivity: value 499:2
如果我们把代码中的editor.putInt("key" + i,2);
改成editor.putInt("key" + i,2).commit();
就会发现,存储会耗费大量的时间,从而阻塞主线程。
2 用SharedPreferences.Editor 的apply()来代替commit()
上面的例子我们可以改成如下:
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
put();
get();
}
private void put(){
SharedPreferences preferences = getSharedPreferences("test",MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
for (int i = 0 ; i < 500 ; i++){
editor.putInt("key" + i,2).apply();
}
//editor.commit();
}
private void get(){
SharedPreferences preferences = getSharedPreferences("test",MODE_PRIVATE);
for (int i = 0 ; i < 500 ; i++){
String key = "key" + i;
Log.d(TAG,"value " + i +":" +preferences.getInt(key,0));
}
}
}
改成这样,我们运行,发现也很快,不会造成主线程阻塞。我们查看源代码发现:
/**
* 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 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();
通过注释我们发现,如果在主线程中使用commit(),android推荐我们使用apply()来代替,我们可以知道,apply()是异步的,并不会马上执行,往往是采用子线程的形式去执行的。因此上面的代码我们可以采用apply()来代替commit()
3 总结
SharedPreferences往往在Android用来保存一些配置信息或者一些用户权限等,如果要存储获取读取大量数据,需要注意阻塞主线程的问题。