• Android开发-API指南-数据存储


    Storage Options

    英文原文:http://developer.android.com/guide/topics/data/data-storage.html
    采集日期:2015-02-06

    存储方式概述

    • 用于简单数据的 Shared Preference
    • 用于私有数据的内部存储
    • 用于大型公开数据的外部存储
    • 用于结构化数据的 SQLite 数据库

    在本文中

    1. 使用 Shared Preference
    2. 使用内部存储
    3. 使用外部存储
    4. 使用数据库
    5. 使用网络连接

    参阅

    1. Content Provider 和 Content Resolver

    Android 为永久性保存数据提供了多种方案。 请根据需求来选择存储方式,比如数据是否为应用程序私有的,还是可以供其他应用(用户)访问的,需要多大的存储空间等等。

    数据存储方案包括以下几种:

    Shared Preferences
    以键-值对(key-value pairs)的形式保存私有的简单(primitive)类型数据。
    内部存储
    在设备的内部存储中保存私有数据。
    外部存储
    在公用的外部存储中保存公共数据。
    SQLite 数据库
    在私有的数据库中保存结构化数据。
    网络连接
    在自己的 Web 服务器上存放数据

    如果需要向其他应用程序公开私有数据, Android 提供了一种途径—— Content Provider 。根据对数据的访问受限需求,Content Provider 可以自由设定读/写权限。 关于 Content Provider 的更多信息,请参阅 Content Providers 的文档。

    使用 Shared Preferences


    SharedPreferences 类提供了一种存储方式,可以用键-值对的方式读写简单类型的数据。用 SharedPreferences 可以保存任何简单类型的数据:boolean、float、int、long 和 string 。 这些数据是持久保存的,可以跨越用户会话(即使应用程序被杀死了也没关系)。

    获得 SharedPreferences 对象的方法有两种:

    • getSharedPreferences() —— 如果需要用到多个配置文件,就用这个方法,第一个参数指定了文件的名称。
    • getPreferences() —— 如果只需为 Activity 定义一个配置文件,就用本方法。因为该文件对于 Activity 而言是唯一的,所以不需要命名。

    写入数据:

    1. 调用 edit() 获得一个 SharedPreferences.Editor
    2. 使用 putBoolean()putString() 之类的方法添加数据。
    3. commit() 提交新数据。

    读取数据是通过 SharedPreferencesgetBoolean()getString() 之类的方法来完成的。

    下面给出了一个把计算器的静音模式保存为配置文件的例子:

     1 publicclassCalcextendsActivity{
     2     publicstaticfinalString PREFS_NAME ="MyPrefsFile";
     3 
     4     @Override
     5     protectedvoid onCreate(Bundle state){
     6        super.onCreate(state);
     7        ...
     8 
     9        // 恢复配置
    10        SharedPreferences settings = getSharedPreferences(PREFS_NAME,0);
    11        boolean silent = settings.getBoolean("silentMode",false);
    12        setSilent(silent);
    13     }
    14 
    15     @Override
    16     protectedvoid onStop(){
    17        super.onStop();
    18 
    19       // 需要一个 Editor 对象来修改配置。
    20       // 所有对象都来自于 android.context.Context
    21       SharedPreferences settings = getSharedPreferences(PREFS_NAME,0);
    22       SharedPreferences.Editor editor = settings.edit();
    23       editor.putBoolean("silentMode", mSilentMode);
    24 
    25       // 提交修改内容
    26       editor.commit();
    27     }
    28 }

    使用内部存储


    文件是可以直接保存在内部存储中的。 默认情况下,保存在内部存储中的文件是应用程序的私有数据,其他应用程序是无法访问的(其他用户也不可以)。 当用户卸载该应用时,这些文件将会被删除。

    请按照以下步骤在内部存储中创建并写入私有文件:

    1. 调用 openFileOutput() ,参数为文件名和操作模式。返回值是一个 FileOutputStream 对象。
    2. write() 写入文件。
    3. close() 关闭流。

    示例:

    1 String FILENAME ="hello_file";
    2 Stringstring="hello world!";
    3 
    4 FileOutputStream fos = openFileOutput(FILENAME,Context.MODE_PRIVATE);
    5 fos.write(string.getBytes());
    6 fos.close();

    MODE_PRIVATE 模式将创建文件(或替换同名文件) 并使其成为应用程序的私有数据。 其他可用的模式还有: MODE_APPENDMODE_WORLD_READABLEMODE_WORLD_WRITEABLE

    从内部存储中读取文件:

    1. 调用 openFileInput() ,参数为要读取的文件名称。返回值为一个 FileInputStream 对象。
    2. read() 从文件中读取若干字节。
    3. close() 关闭流。

    提示: 如果在编译时就需要保存静态文件,请存放到项目的 res/raw/ 目录下。 可以用 openRawResource() 打开这些文件,参数是 R.raw.<filename> 的资源 ID 。返回值是一个 InputStream 对象,可用它来读取文件(但是无法在原始文件中写入数据)。

    保存缓存文件

    如果某些数据不需要持久保存,而只是临时缓存一下,请使用 getCacheDir() 打开一个 File 即可,此目录是应用程序保存临时文件的内部目录。

    如果设备的内部存储空间不足, Android 可能会删除这些缓存文件以释放空间。 不过,请不要依赖系统来清理这些临时文件。而是应该自己管理好缓存文件,使得它们仅占用必需的空间即可,比如 1MB。 当用户卸载应用时,这些文件将会被删除。

    其他常用方法

    getFilesDir()
    获取内部文件的绝对路径
    getDir()
    在内部存储中创建(或打开已有)目录。
    deleteFile()
    删除内部存储中的文件。
    fileList()
    返回应用已保存的文件列表数组。

    使用外部存储


    所有 Android 设备都支持可用于保存文件的共享“外部存储”。 这可以是可卸载的存储介质(比如 SD 卡),也可以是内置(不可卸载的)存储。 保存在外部存储上的文件是全局可读(world-readable)的,并且在启用 USB 存储模式(USB mass storage)与电脑传输文件时可以被修改。

    警告: 当用户将外部存储挂接到电脑上,或者介质被卸载时,外部存储就会成为不可用状态,并且无法在外部存储文件上施加任何安全保护措施。 所有应用程序均可读写外部存储中的文件,用户也可以随时将它们删除。

    获得外部存储的访问权限

    读写外部存储必须申请 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 权限。例如:

    <manifest ...>
        <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        ...
    </manifest>

    如果既要读取又要写入文件,则只需申请 WRITE_EXTERNAL_STORAGE 权限即可,因为它同时隐含了读取权限请求。

    注意: 自 Android 4.4 开始,如果只是读写应用程序私有的文件,则不再需要申请上述权限了。 详情请参阅后续章节 保存应用程序私有的文件

    检查存储介质的可用性

    在使用外部存储之前,请务必调用 getExternalStorageState() 来检查介质的可用性。 存储介质可能是被挂接到电脑上了、已被移除、处于只读状态,或是其他状况。 以下给出了两个可用于检查介质可用性的方法示例:

     1 /* 检查外部存储是否可读写 */
     2 publicboolean isExternalStorageWritable(){
     3     String state =Environment.getExternalStorageState();
     4     if(Environment.MEDIA_MOUNTED.equals(state)){
     5         returntrue;
     6     }
     7     returnfalse;
     8 }
     9 
    10 /* 检查外部存储是否至少是可读的 */
    11 publicboolean isExternalStorageReadable(){
    12     String state =Environment.getExternalStorageState();
    13     if(Environment.MEDIA_MOUNTED.equals(state)||
    14         Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)){
    15         returntrue;
    16     }
    17     returnfalse;
    18 }

    getExternalStorageState() 方法返回的状态还包括其他类型,比如是否处于共享状态(连接到电脑上)、已被移除、未能正常卸载等等。 当应用程序需要访问存储介质时,可以利用这些状态来把详细信息告知用户。

    保存可共享文件

    通常,用户创建的文件应该保存在设备的“公共”区域,这是其他应用程序可以访问的区域,用户也很容易从设备上拷走这些文件。 可以使用公共的目录,比如 Music/Pictures/Ringtones/

    调用 getExternalStoragePublicDirectory() 可以获取一个代表公共目录的 File ,参数是目录的类型,比如 DIRECTORY_MUSICDIRECTORY_PICTURESDIRECTORY_RINGTONES 等等。只要将文件保存到合适的目录中,系统的 Media Scanner 就可以对它们进行正确归类(比如, 铃声文件就会出现在系统设置的铃声列表中,而不会被视为音乐文件)。

    比如,以下给出了在公共的图片目录下新建一个相册目录的示例:

    1 publicFile getAlbumStorageDir(String albumName){
    2     // 获得用户公共图片目录
    3     File file =newFile(Environment.getExternalStoragePublicDirectory(
    4             Environment.DIRECTORY_PICTURES), albumName);
    5     if(!file.mkdirs()){
    6         Log.e(LOG_TAG,"Directory not created");
    7     }
    8     return file;
    9 }

    保存应用程序私有的文件

    如果文件不会给其他应用程序使用(比如仅供本应用使用的图形纹理或声效文件),请使用外部存储中的私有存储目录,调用 getExternalFilesDir() 即可。该方法也有一个指定目录类型的 type 参数(如 DIRECTORY_MOVIES )。如果目录不需要指定多媒体类型,传入 null 即可返回应用程序私有目录的根目录。

    自 Android 4.4 开始,读写应用程序私有目录不再需要申请 READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE 权限了。因此可以仅当处于低版本 Android 时才声明这两个权限请求,这通过添加 maxSdkVersion 属性即可实现:

    <manifest ...>
        <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"
                         android:maxSdkVersion="18"/>
        ...
    </manifest>

    注意: 当用户卸载应用程序时,该私有目录及其中的内容都将会被删除。 并且该目录下的文件不会被系统的 Media Scanner 读取,也就不会被 Content Provider MediaStore 访问到。因此,请勿在私有目录中存放用户的多媒体文件,比如通过本应用拍摄或编辑的照片、通过本应用购买的音乐等, 这些文件都应该保存到公共目录中去

    有时,某些设备会申请一块内部存储区域作为外部存储来使用,且被视为一张 SD 卡。 这种设备如果运行 Android 4.3 及以下版本时, getExternalFilesDir() 方法只会访问内部存储上的分区,应用程序就无法读写 SD 卡了。 不过,自 Android 4.4 开始, getExternalFilesDirs() 对这两块区域都可以访问到,并会返回包含两块存储内容的 File 数组。数组的第一个成员为外部存储中的文件,只要空间充足且可用,一般应该使用这个区域。 如果想在 Android 4.3 以下版本中也能同时访问这两个区域,请使用 support library 的静态方法 ContextCompat.getExternalFilesDirs() 。它也会返回一个 File 数组,但在 Android 4.3 以下版本时此结果数组中只会包含一个成员。

    警告: 虽然由 getExternalFilesDir()getExternalFilesDirs() 得到的目录无法被 Content Provider MediaStore 访问,但拥有 READ_EXTERNAL_STORAGE 权限的其他应用是可以访问外部存储中的所有文件的,当然也包括这两个目录。 如果需要完全控制对文件的访问,请把文件写入内部存储

    保存缓存文件

    调用 getExternalCacheDir() ,可以打开存放缓存文件的外部存储目录 File。 当用户卸载应用程序时,这些文件都将被自动删除。

    类似于上面的 ContextCompat.getExternalFilesDirs() ,可以通过 ContextCompat.getExternalCacheDirs() 访问到两种外部存储(如果可用的话)中的缓存目录。

    提示: 为了节省空间及维持程序性能,在应用程序的整个生命周期中,都应该对缓存文件进行很好地管理,及时删除无用文件。

    使用数据库


    Android 实现了对 SQLite 数据库的 数据库的完整支持。 应用程序中的所有类都可以按照名称访问本应用创建的数据库,但其他应用程序则无法访问。

    推荐通过新建 SQLiteOpenHelper/code> 的一个子类来创建 SQLite 数据库。请覆盖其 onCreate() 方法,以便执行建立数据表的 SQLite 命令。例如:

     1 publicn>classDictionaryOpenHelperextendsSQLiteOpenHelper{
     2 
     3     privatestaticfinalint DATABASE_VERSION =2;
     4     privatestaticfinalString DICTIONARY_TABLE_NAME ="dictionary";
     5     privatestaticfinalString DICTIONARY_TABLE_CREATE =
     6                 "CREATE TABLE "+ DICTIONARY_TABLE_NAME +" ("+
     7                 KEY_WORD +" TEXT, "+
     8                 KEY_DEFINITION +" TEXT);";
     9 
    10     DictionaryOpenHelper(Context context){
    11         super(context, DATABASE_NAME,null, DATABASE_VERSION);
    12     }
    13 
    14     @Override
    15     publicvoid onCreate(SQLiteDatabase db){
    16         db.execSQL(DICTIONARY_TABLE_CREATE);
    17     }
    18 }

    然后,可以获得一个包含上述构造方法的 SQLiteOpenHelper 实例,根据对数据库的读写需求分别调用其 getWritableDatabase()getReadableDatabase() 方法。这两个方法都返回代表数据库的 SQLiteDatabase 对象,其中包含了一些 SQLite 操作的方法。

    通过 SQLiteDatabasequery() 方法,可以执行 SQLite 查询。该方法可以传入各种查询参数,比如表名、projection、Select 语句、字段名、分组等等。 如果要进行复杂的查询,比如用到了字段别名,请使用 SQLiteQueryBuilder/code> ,它提供了很多便于构建查询的方法。

    每个 SQLite 查询都会返回一个 Cursor ,它指向所有符合查询条件的记录。 Cursor 是遍历数据库查询结果并读取行列数据的唯一方式。

    在 Android 中使用 SQLite 数据库的应用示例,请参阅 Note PadSearchable Dictionary

    数据库调试

    Android SDK 中包含了一个 sqlite3 数据库工 数据库工具,可以用来浏览数据表、运行 SQL 命令及执行其他 SQLite 数据库维护工作。 关于此工具的使用方法,请参阅 在远程 Shell 中管理 sqlite3 数据库

    使用网络连接


    在网络可用时,可以通过网络在自建的 Web 端服务中保存和读取数据。 有关网络的操作,请使用下列包中的类:

  • 相关阅读:
    OpenCvSharp 识别颜色
    树莓派 Raspberry Pi 4,.net core 3.0 ,Avalonia UI 开发
    iis频繁奔溃,分析dump
    prerender.io 搜索引擎优化 部署成windows服务 实现开机自动开启服务
    ionic3包还原使用yarn命令执行步骤(解决ionic3懒加载报找不到 module的错误)
    firebreath 在谷歌和火狐浏览器下的调试 以及打包
    ASP.NET Web API 2 对 CORS 的支持
    .net mvc通过ucenter和 discuz的整合,nopcommerce ucenter 插件的方式实现
    EF + Mysql
    Jenkins持续集成 & .NET
  • 原文地址:https://www.cnblogs.com/popapa/p/android_Data-Storage.html
Copyright © 2020-2023  润新知