SharedPreferences

一、简介

在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 的唯一首选项文件,因此无需提供名称。

存储数据时,

  1. 调用 edit() 以获取 SharedPreferences.Editor

  2. 使用 putBoolean()putString() 等方法添加值。

  3. 使用 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并不适合存储大量数据和频繁改变数据。只能由于轻量的存储。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容