【Android API Guides 简译(三)】Data Storage--Storage Options

Android提供了几种永久储存手机数据的选项,而我们选择存储的方式依据于我们存储的不同的特定需求,比如你的数据是否需要只对自己公开,数据是否可以被其他应用得到或者你想要储存多大的数据。
数据存储的方式如下:
Shared Preferences
通过xml类型的键值对,存储私密的原始数据。
Internal Storage 内部存储
通过手机内存存储私密数据
External Storage 外部存储
在设备外部共享里存储公开的数据
SQLite Databases Android 原生内部数据库
在私有数据库里存储结构化的数据
Network Connection 网络连接
在网络服务器上存储数据
Android 还提供了一种将私有的数据公开化的组件–Content-providers,详见Content-providers参考文档。

一、使用Shared Preferences
SharedPreferences类提供了一个完整的框架用来通过键值对的形式,永久地储存私有信息。我们可以使用SharedPreferences类储存任意一种类型的数据,包括booleans, floats, ints, longs, and strings。而且这些数据将会在整个会话阶段一直保存,即使你的应用被关闭。
得到SharedPreferences对象的两种方式:
1、getSharedPreferences() - 如果你想要得到一个通过键名来区分的笼统的Preferences对象,使用这种方法。
2、getPreferences(int) - 如果你的整个Activity只需要一个Preferences,因此你不需要提供键名。使用这种方法。
写入Value值的方式:
1、使用edit()方法得到一个 SharedPreferences.Editor对象。
2、通过类似putBoolean() 和 putString() 的方法添加值。
3、将编辑器的值和SharedPreferences对象的值相关联。
读取Value值,通过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();
    }
}

二、使用Internal Storage
你可以直接将数据存储在内部存储里,但一般情况下,内部存储的数据对于本程序是私有的,其他程序是无法访问到的,也就是说当本程序被卸载时,该数据会一起被移除。我们一般将内部文件放在Data/data/相应的应用目录。
创建或者向内部存储写入一个文档的过程如下:
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();

MODE_PRIVATE将会创建或者取代相同名字的文件,而且这个文件只对本程序可用。其他的模式有:MODE_APPEND, MODE_WORLD_READABLE, 和 MODE_WORLD_WRITEABLE。
如果我们有读取一个内容固定不变的文件,可以在编译的时候,在R.raw目录下保存你想要访问的文件,然后调用 openRawResource(),参数是R.raw.,返回一个 InputStream 对象,通过这个流,读取你想要读取的内容。(但是你不可以对这个文件进行写入操作。)
保存临时文件
如果你并不想永久的保存某些数据,你可以通过调用getCaheDir()方法,在系统目录里创建打开一个文件,用来保存临时数据。方法返回值是保存临时文件的路径。
当系统的内部存储快满了时,系统会自动清理临时文件,但是你不能依靠系统自动来清理临时文件,需要自己设置临时文件的大小上限,定时删除临时文件。当使用者卸载应用时,临时数据都会被删除。
其他有用的方法
getFilesDir()
得到保存文件的绝对路径。
getDir()
创建或者打开一个存在的内部存储文件。
deleteFile()
删除一个保存在内部存储的文件。
fileList()
返回应用的目录下的文件的清单。

三、使用外部存储
任何一个Android兼容性的手机都支持共享你保存在“外部存储”的文件。所谓”外部存储“,既可以保存在可移除的SD卡,也包含不可移除的内部存储里。而且当我们通过USB连接电脑时,我们可以修改这些文件。
注意:当我们在电脑上加载外部存储时,手机内不可访问相应的文件。存储在外部存储的文件不受安全性保护,用户可以任意的增加修改或者删除该文件。
访问到外部存储
你必须拥有 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 权限,才能访问或写入外部存储的文件。
在工程的Manifest.xml里修改:

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

当我们既想读取又想写入时,只需要得到 WRITE_EXTERNAL_STORAGE 权限就可以。
注意:从4.4版本后,如果只是访问和写入对本应用私有的文件,不需要获得上述权限。
检查媒体的可用性
在我们使用外部存储的文件之前,都必须检查文件的可用性,即文件是否只读,隐藏或者其他状态。我们会用getExternalStorageState(),返回一个String对象。通过将String值与MEDIA_MOUNTED,MEDIA_MOUNTED_READ_ONLY等来确认当前文件的状态。下面提供了两种检查文件的可用性的方法:

/* 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;
}

保存可被其他应用共享的文件
我们通常把想要共享的文件放在具有共享属性的文件目录下,那么怎么创建具有共享属性的文件目录呢?调用getExternalStoragePublicDirectory()创建一个文件目录,通过参数目录类型和目录名称,设置文件目录的属性和名称。
实例代码:

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()方法来创建隐藏文件目录,同时可以通过设置参数的值来标示该目录的类型,比如DIRECTORY_MOVIES,标明该文件目录里的文件是视频类型的。
上文提到过,4.4以后无需设置权限即可访问外部存储的文件。低版本的需要如下设置,类似前面:

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

注意:当用户将应用卸载后,该文件会一起被移除。因为该文件不会被文件系统扫描到,所以通过content provider组件是无法访问到这些文件的。因此,如果当用户在此程序生成的文件不能保存在私有目录下,否则用户无法通过其他应用找到这些文件。
有时候,设备会将内部存储划分一部分当做外部存储使用,于是在4.3及以下版本时,调用 getExternalFilesDir() 方法不能访问到被划作外部存储的内部存储的文件,但在4.4版本以后,调用getExternalFilesDir() 方法,我们可以访问到两部分的文件。这时候getExternalFilesDir() 方法返回一个文件名条目,第一个条目就是被划作外部存储的目录。而且此目录是基本目录,除非在该目录已满或者无法访问的情况下,否则优先使用这部分存储。
当然如果你不喜欢这种设计的API,你可以使用support library里的静态方法ContextCompat.getExternalFilesDirs()。
注意:尽管私有目录下的文件不可被content provider组件使用,但是如果想要完全保密的话,还是要存储在内部存储里,因为私有目录里文件可以被具有 READ_EXTERNAL_STORAGE权限的应用访问到。
保存临时文件
同内部存储里保存临时文件一样,可以调用getExternalCacheDir()创建临时文件。也同样的,被卸载时会被移除。

四、使用数据库
Android自带 SQLite 数据库,但只能在创建该数据库的应用中使用,其他应用不能使用。
创建数据库的推荐方法是创建继承SQLiteOpenHelper的类,并重写OnCreate()方法。
示例如下:

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() and getReadableDatabase()方法来得到 SQLiteDatabase对象,通过对这个对象进行操作来完成数据库的功能。
SQLiteDatabase对象可以通过调用query()进行大部分的查询,更复杂的查询比如得到列名,可以通过 SQLiteQueryBuilder对象进行查询。
每个SQLite查询都会得到Cursor。Cursor即索引,只想每一个想要查询的数据。
数据库调试
Android SDK包含一个叫作 sqlite3的数据库,我们可以进行试操作。

五、使用网络连接
我们还可以通过网上的服务器储存和恢复数据,这里不再详述。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。