一、简介
在Android中,主要有以下几种存储方式:
1、SharedPreferences,在键值对中存储私有原始数据。
2、内部存储,在设备内存中存储私有数据。
官方示例:
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
3、外部存储,在共享的外部存储中存储公共数据。
使用外部存储,需要获取外部存储的读写权限。
外部存储主要包括存储公用文件(与其他应用共享)和不愿共享的私有文件以及缓存。
官方示例:
公有文件:以下方法在公共图片目录中创建了一个用于新相册的目录:
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
如果您正在处理的文件不适合其他应用使用(例如仅供您的应用使用的图形纹理或音效),则应该通过调用 getExternalFilesDir() 来使用外部存储上的私有存储目录。
要打开表示应该将缓存文件保存到的外部存储目录的 File,请调用 getExternalCacheDir()。 如果用户卸载您的应用,这些文件也会被自动删除。
4、sqlite数据库,在私有数据库中存储结构化数据。
创建新 SQLite 数据库的推荐方法是创建 SQLiteOpenHelper 的子类并覆盖 onCreate() 方法,在此方法中,您可以执行 SQLite 命令以创建数据库中的表。
官方示例:
public class DictionaryOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2;
private static final String DICTIONARY_TABLE_NAME = "dictionary";
private static final String DICTIONARY_TABLE_CREATE =
"CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
KEY_WORD + " TEXT, " +
KEY_DEFINITION + " TEXT);";
DictionaryOpenHelper(Context context) {
super(context, DATABASE_NAE, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DICTIONARY_TABLE_CREATE);
}
}
回到我们的重点,SharedPreferences。SharedPreferences是安卓数据存储的一个框架,它可以方便地存储和读取永久性键值对数据。SharedPreferences可以用来存储任何基本类型的数据,如String、Int等,注意它的存储是永久性的,也就是应用关闭后,它依然保留着。
二、SharedPreferences的使用
要读取SharedPreferences存储的数据,首先要获得SharedPreferences的对象:
要获取应用的 SharedPreferences 对象,请使用以下两个方法之一:
getSharedPreferences() - 如果您需要多个按名称(使用第一个参数指定)识别的首选项文件,请使用此方法。
getPreferences() - 如果您只需要一个用于 Activity 的首选项文件,请使用此方法。 由于这将是用于 Activity 的唯一首选项文件,因此无需提供名称。
存储数据时,
-
调用 edit() 以获取 SharedPreferences.Editor。
-
使用 putBoolean() 和 putString() 等方法添加值。
-
使用 commit() 提交新值(注意:在使用commit时,会出现提示:Consider using apply() instead.Commit writes its data to persistent storage immediately, whereas apply will handle it in the background
也就是说,commit是不推荐的,因为它会马上把数据写入永久存储中,而apply则会在后台(多线程)做这件事。对于apply和commit的区别,可以参考博客https://blog.csdn.net/jake9602/article/details/18414841)
示例代码:
package com.meituan.huangdanyang.practise;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import com.meituan.huangdanyang.practise.BaseActivity;
import java.util.List;
public class MainActivity extends BaseActivity {
private final static String MY_PRE_NAME = "my preferences";
private final static String MY_PRE_STRING_KEY = "KEY1";
private final static String MY_PRE_INT_KEY = "KEY2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences preferences = getSharedPreferences(MY_PRE_NAME, Context.MODE_PRIVATE);
System.out.println(MY_PRE_STRING_KEY + " " + preferences.getString(MY_PRE_STRING_KEY,
"NULL"));
System.out.println(MY_PRE_INT_KEY + " " + preferences.getInt(MY_PRE_INT_KEY, 0));
SharedPreferences.Editor editor = preferences.edit();
editor.putString(MY_PRE_STRING_KEY, this.toString());
editor.putInt(MY_PRE_INT_KEY, this.hashCode());
editor.apply();
}
@Override
protected void onStop() {
super.onStop();
SharedPreferences preferences = getSharedPreferences(MY_PRE_NAME, Context.MODE_PRIVATE);
if (preferences.contains(MY_PRE_STRING_KEY)) {
System.out.println(MY_PRE_STRING_KEY + " " + preferences.getString(MY_PRE_STRING_KEY,
"NULL"));
}
if (preferences.contains(MY_PRE_INT_KEY)) {
System.out.println(MY_PRE_INT_KEY + " " + preferences.getInt(MY_PRE_INT_KEY, 0));
}
}
@Override
protected String getName() {
return "MainActivity";
}
}
如上,存储activity的对象名字和hashcode。
三、性能
SharedPreferences读取一次小数据要花多少时间呢?
首先看看一些ui操作的耗时:
Long last = System.currentTimeMillis();
TabLayout tabLayout = findViewById(R.id.menu);
ViewPager viewPager = findViewById(R.id.view_pager);
tabLayout.setupWithViewPager(viewPager);
输出结果为:
07-31 13:52:37.569 19634-19634/com.meituan.huangdanyang.practise I/System.out: 耗时 : 1
然后再试试SharedPreference读取的耗时:
Long last = System.currentTimeMillis();
SharedPreferences preferences = getSharedPreferences(MY_PRE_NAME, Context.MODE_PRIVATE);
preferences.getString(MY_PRE_STRING_KEY,"NUlL");
System.out.println(MY_PRE_STRING_KEY + " " + preferences.getString(MY_PRE_STRING_KEY,
"NULL"));
System.out.println(MY_PRE_INT_KEY + " " + preferences.getInt(MY_PRE_INT_KEY, 0));
System.out.println("耗时 : "+ (System.currentTimeMillis() - last));
SharedPreferences.Editor editor = preferences.edit();
结果为:
07-31 13:48:56.660 19304-19304/com.meituan.huangdanyang.practise I/System.out: KEY1 com.meituan.huangdanyang.practise.MainActivity@7e242ee
KEY2 132268782
耗时 : 4
单线程在读取轻量数据的时候,SharedPreferences还是要耗费一些时间的,但耗费的量不是很大,尤其是相比于大量的渲染来说。
试试存储轻量数据耗费的时间:
Long last = System.currentTimeMillis();
SharedPreferences.Editor editor = preferences.edit();
editor.putString(MY_PRE_STRING_KEY, this.toString());
editor.putInt(MY_PRE_INT_KEY, this.hashCode());
editor.commit();
System.out.println("耗时 : "+ (System.currentTimeMillis() - last));
结果为:
07-31 13:56:23.695 19790-19790/com.meituan.huangdanyang.practise I/System.out: 耗时 : 4
和读取差不多。
但在存放大的数据库的时候(6000左右个字符):
String putStr = "strstrstr";
for (int i = 0;i < 10000;i++){
putStr += putStr;
}
Long last = System.currentTimeMillis();
SharedPreferences.Editor editor = preferences.edit();
editor.putString(MY_PRE_STRING_KEY, putStr);
editor.putInt(MY_PRE_INT_KEY, this.hashCode());
editor.commit();
System.out.println("耗时 : "+ (System.currentTimeMillis() - last));
耗时多了不少:
07-31 14:06:31.546 20566-20566/com.meituan.huangdanyang.practise I/System.out: 耗时:31
官方文档对于SharedPreferences的性能有如下解释:
This class provides strong consistency guarantees.
It is using expensive operations which might slow down an app.
Frequently changing properties or properties where loss can be tolerated should use other mechanisms.
For more details read the comments on SharedPreferences.Editor.commit() and SharedPreferences.Editor.apply().
也就是说,SharedPreference提供强大的一致性保证。它使用了消耗昂贵的操作,这些操作可能降低app运行的速度。如要频繁的修改数据或者是要存储可以丢失的数据应当使用其他机制。
所以,SharedPreferene并不适合存储大量数据和频繁改变数据。只能由于轻量的存储。
网友评论