Android 存储选择

以下内容翻译自Android开发文档 Storage Options 篇,如有错误或不当之处,欢迎指出。

---------------------------------------------------------------------------------------------------------------------

Android提供了多种选择来存储持久的应用数据。你可以根据自身需求选择相应的存储方式,比如数据是否私有的,或者可以被其他应用(或用户)访问,以及你的数据需要的空间。

  • Shared Preferences:用键值对的方式存储私有的基本的数据
  • Internal Storage:存储在设备内存私有数据
  • External Storage:存储在可共享的外存上的公共数据
  • SQLite Databases:存储在私有数据库的结构化数据
  • Network Connection:存储在自己的网络服务器的数据 
    Android还提供了一种方式将你的私有数据暴露给别的应用——content provider

使用Shared Preferences

SharedPreferences类提供了通用框架来允许你保存和检索基础数据类型的永久键值对。你可以使用SharedPreferences阿狸保存基本数据:booleansfloatsintsstrings。这些数据将会随着用户会话一直保存,即使进程被杀掉(除非用户手动清除数据,或者卸载应用)。 
获取SharedPreferences对象,可以使用如下两种方法:

  • getSharedPreferences():当你需要多个preferences文件时,使用这个方法,并在第一个参数中命名你的文件
  • getPreferences():当你只需要一个preferences文件时,使用这个方法,会使之成为唯一的preferences文件,你不需要提供名字。 
    写入数据:
  1. 调用edit()方法来获取一个SharedPreferences.Editor
  2. 调用诸如putBoolean()putString()方法来写入数据
  3. 调用commit()方法提交新的数据 
    读取数据,使用SharedPreferences的方法,诸如getBoolean()getString()等。 
    下面的例子时保存计算器的静音模式设置
public class Calc extends Activity {
    public static final String PREFS_NAME = "MyPrefsFile";

    @Override
    protected void onCreate(Bundle state){
       super.onCreate(state);
       . . .

       // Restore preferences
       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
       boolean silent = settings.getBoolean("silentMode", false);
       setSilent(silent);
    }

    @Override
    protected void onStop(){
       super.onStop();

      // We need an Editor object to make preference changes.
      // All objects are from android.context.Context
      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
      SharedPreferences.Editor editor = settings.edit();
      editor.putBoolean("silentMode", mSilentMode);

      // Commit the edits!
      editor.commit();
    }
}

使用the Internal Storage

你可以直接将数据保存在设备的内存中。Android默认保存在内存中的文件是你的应用私有的,其他应用不能访问(包括用户)。当用户卸载应用时,这些文件也会被删除。 
创建和写入内存中的私有文件方法

  1. 调用openFileOutput()方法,传入文件名和操作模式。这个方法会返回一个FileOutputStream
  2. 调用write()方法写入文件
  3. 调用close()方法关闭流 
    举个例子:
String FILENAME = "hello_file";
String string = "hello world!";

FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

从内存中读取文件

  1. 调用openFileInput()方法,并传入要读取的文件名。这个方法将会返回一个FileInputStream
  2. 调用read()方法读取字节
  3. 调用close()方法关闭流

    Tips:当你想要在编译时在你的应用中保存静态文件,将文件保存在项目的res/raw/目录中。你可以使用openRawResource()方法传入资源IDR.raw.<filename>来打开该文件。这个方法会返回一个InputStream`用来读取文件(但你不能写入原始文件)。

保存缓存文件

当你想要缓存某些数据时,比起永久保存,你可以使用getCacheDir()方法来打开应用用来存储临时缓存文件的目录下的一个文件。 
当设备内存空间不足时,Android可能会删除这些缓存文件来恢复空间。但是你不能以来系统为你清理这些文件。你应该时不时的清理下你的缓存文件,使之保持在内存消费的合理限制中,比如1MB。当用户卸载应用时,这些文件将会被删除。

其他可用的方法
  • getFilesDir():获取你的内部文件所在的文件系统目录的绝对路径
  • getDir():创建一个(或打开一个已经存在的)位于你的内存空间的目录
  • deleteFile():删除保存在内存中的文件
  • fileList():返回当前由你的应用保存的文件列表

使用the External Storage

每台Android兼容的设备都支持一个可共享的external storage方便你存储文件。它可以时可移除的存储媒介(比如一张SD卡)或者内存(不可移除的)。保存在外存中的文件是全世界可读的,并且当它们启用USB大容量存储在计算机上传输文件时,它们可以被用户修改。

注意:当用户在计算机上mount外存或者移除媒介时,外存会变成不可用状态,你保存到外存的文件上也并没有安全保证。所有应用可以读写外存中的文件,用户也可以移除它们。

获取访问外存权限

要在应用中读写外存中的文件,你需要READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE系统许可。如下:

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

检查媒介可用性

在对外存进行操作前,你总是需要调用getExternalStorageState()方法来检查媒介是否可用。媒介可能正挂载在一台计算机上,丢失、只读或者其他状态。如下所示,这里由集中你可以用来检查可用性的方法:

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

保存可以分享给其他应用的文件

通常,用户从你的应用获取的新的文件应该被保存在公共的位置,以便其他应用可以访问,用户可以轻易拷贝。此时,你应该使用可共享的公共目录,比如Music/Pictures/Rintones/等。 
调用getExternalStoragePublicDirectory(),传入你想要的目录类型,比如DIRECTORY_MUSICDIRECTORY_PICTURESDIRECTORY_RINGTONES,或其他。通过将文件保存到相应的媒体类型目录下,系统的媒体扫瞄器可以将你的文件适当归类。 
如下提供了一个在公共的图片目录下创建一个新的相册目录的方法:

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()方法来创建(或打开)外存中的私有存储目录。该方法还需要一个type参数来标识你的子目录类型(比如DIRECTORY_MOVIES)。如果你不需要标识媒体目录,传入null即可。 
从Android 4.4.开始,读写应用的私有目录不许再添加READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE许可。因此,你只需在低版本中声明该许可:

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

注意:当用户卸载你的应用时,该目录和它的所有内容都会被删除。同时,系统的媒体扫描器不再读取该目录下的文件,隐藏它们不能被MediaStorecontent provider访问。

有时候,设备分类了一部分内存来使用,同时外存也提供了SD卡槽。当一个设备运行的是Android 4.3或者更低,getExternalFilesDir()方法只能访问内存部分而不能读写SD卡。从Android 4.4开始,你可以通过调用getExternalFilesDirs()方法访问这两个位置,它会各返回一个文件列表。列表中的第一个条目就是主要的外存,你可以使用这个位置除非它满了或者不可用。如果你想要访问两个位置且又要支持Android 4.3及以下版本的,那么可以使用support library的静态方法:ContextCompat.getExternalFilesDirs()。它也会返回一个文件列表,但在Android 4.3及以下版本中,只包含一个条目。

注意:尽管这些目录由getExternalFilesDir()提供,且不能被MediaStorecontent provider访问,但是其他带有READ_EXTERNAL_STORAGE许可的应用可以访问外存的所有文件,包括这些目录。如果你要完全限制对你的文件的访问,你应该将文件写入内存中。

保存缓存文件

要打开一个外存目录中你用来存储缓存文件的File,调用getExternalCacheDir()方法。如果用户卸载了你的应用,这些文件会被自动删除掉。 
类似ContextCompat.getExternalFilesDirs(),上面的方法,你也可以通过调用ContextCompat.getExternalCacheDirs()方法来访问位于第二外存(如果可以用)中的缓存目录。

Tips:为了保留文件空间和保持应用性能,小心地管理缓存文件并且一旦不需要了就及时移除它们是很重要的。


使用Databases

Android提供了对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_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DICTIONARY_TABLE_CREATE);
    }
}

然后你可以获取你的SQLiteOpenHelper子类的实例。分别调用getWritableDatabase()getReadableDatabase()方法来读、写数据库。它们都返回一个SQLiteDatabase对象,它表示你要操作的那个数据库并提供了SQLite操作的相关方法。 
你可以使用SQLiteDatabasequery()方法来执行SQLite查询,它需要一些查询参数,诸如表名、projectionselectioncolumnsgrouping,及其他。对于复杂的查询,比如那些需要字段别名的,你应该使用SQLiteQueryBuilder,它提供了多种方便的方法来创建查询语句。 
每个SQLite查询会返回一个Cursor指向本次查询找到的行。Cursor是一种你可以从数据库查询中导航结果和读取行列的机制。

数据库调试

Android SDK包含了sqlite3数据库工具,允许你浏览表的内容,执行SQL命令,以及其他在SQLite数据库中很有用的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值