Android保存数据的三种方法

来源:互联网 发布:小黄鸡peeper软件下载 编辑:程序博客网 时间:2024/05/21 18:32
对于大多数Android应用而言,都需要保存数据。这里介绍Android中三种最基本的数据存储方法。它们包括:
    (1)将简单数据类型的Key-Value对保存到一个共享的preference文件中;
    (2)将任意文件保存到Android文件系统中;
    (3)利用SQLite数据库来管理。
    针对以上三种方法,我们将分别介绍其用法以及适用的场景。


    1)保存Key-Value集
    利用共享的preference文件来存储少量以Key-Value对形式的信息。
    这种方法需要使用SharedPreferences API来完成。SharedPreferences对象指向一个包含Key-Value对的文件,并且提供简单的方法来读和写数据。
    注意:我们需要将SharedPreferences和Preferences API区分开。Preferences API用于为你的app设置提供用户接口。
    (1)获得SharedPreferences的句柄
    通过如下两个方法可以创建一个共享的preference文件或者访问某个已经存在的preference文件。
    a)getSharedPreferences():如果需要由名字来区分的多个共享preferences文件,可以指定第一个参数来获得。
    b)getPreferences():如果仅需要一个共享的preference文件可以利用该方法,它会自动获取属于该Activity的默认共享preference文件,不需要指定其名字。
    以下是利用getSharedPreferences()方法来获得某个共享preference文件的示例用法。
Context context = getActivity(); SharedPreferences sharedPref = context.getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE);
    以下是利用getPreferences()方法来获得默认的共享preference文件的示例用法。
SharedPreferences sharedPref =getActivity().getPreferences(Context.MODE_PRIVATE);
     (2)从共享的Preference中读取数据
    可以调用getInt()和getString()方法来从共享的Preference中读取数据,如果某个key不存在则会返回一个默认值。例如:
SharedPreferences sharedPref =getActivity().getPreferences(Context.MODE_PRIVATE); int defaultValue =getResources().getInteger(R.string.saved_high_score_default); long highScore =sharedPref.getInt(getString(R.string.saved_high_score),defaultValue);


    2)保存文件
    保存文件到系统中,例如存储大量长数据序列。
    所有的Android设备都包含两个文件系统区域:内部和外部存储。因此我们将分别介绍这两种情况下的文件存储。
    (1)将文件存储在内部存储器上
    通常需要采用如下两个方法来获得File目录结构。
    a)getFilesDir():它返回你app所在的内部存储器的目录结构 
    b)getCacheDir():它返回你app临时缓存文件的内部存储器的目录结构。当采用这种方法时应该记住当你的应用不需要这些文件的时候应该删除掉,并且指定一个有限的大小空间,例如1MB。因为如果系统的存储太低时会自动删除你的缓存文件而不给出任何提示和警告。
    如下示例所示将新建一个文件在内部存储器上。
File file = new File(context.getFilesDir(), filename);
    通过openFileOutput()和FileOutputStream可以将内容写入到内部存储器中某个目录下的文件中。例如:
String filename = "myfile"; String string = "Hello world!"; FileOutputStream outputStream;try {     outputStream = openFileOutput(filename, Context.MODE_PRIVATE);    outputStream.write(string.getBytes());      outputStream.close(); } catch (Exception e) {     e.printStackTrace(); }
    利用createTempleFile()方法可以新建一个临时文件。例如:
public File getTempFile(Context context, String url) {     File file;    try {        String fileName = Uri.parse(url).getLastPathSegment();        file = File.createTempFile(fileName, null,context.getCacheDir()};    }    catch (IOException e) {        // Error while creating file     }     return file;}
    (2)将文件存储在外部存储器上
    将将文件存储在外部存储器上首先我们必须获得外部存储器的权限。要想获得写入外部存储器的权利,需要在你的manifest文件中取得WRITE_EXTERNAL_STORAGE权限。例如:
...>     android:name="android.permission.WRITE_EXTERNAL_STORAGE" />      ... 
    对于目前来说所有app都有读取外部存储器的权限,其实也有READ_EXTERNAL_STORAGE权限,但是当指定了WRITE_EXTERNAL_STORAGE权限后,默认就有READ_EXTERNAL_STORAGE的权限了。
    考虑到外部存储器并不总是可用,所以通常我们在使用它之前需要查询外部存储器的状态,通过getExternalStorageState()可以得到,如果状态等于MEDIA_MOUNTED则表示外部存储器可用。例如:
public boolean isExternalStorageWritable() {     String state = Environment.getExternalStorageState();     if (Environment.MEDIA_MOUNTED.equals(state)) {        return true;     }     return false; } public boolean isExternalStorageReadable() {     String state = Environment.getExternalStorageState();    if (Environment.MEDIA_MOUNTED.equals(state) ||Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {         return true;    }    return false;}
    通常我们存储在外部存储器上的文件分为两种类型:Public文件和Private文件
    a)Public文件
    对于Public文件它可以供其他app使用,当用户卸载你的app后,该文件还存在,例如通过你的app拍摄的照片或者其他下载文件。可以使用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; }
    b)Private文件
    而Private文件则只属于你的app,当用户卸载你的app后该文件也一同被删除了,例如你app需要的额外资源文件或者临时媒体文件等。可以使用getExternalFilesDir()来获得内部存储器的目录结构。例如:
public File getAlbumStorageDir(Context context, String albumName) { // Get the directory for the app's private pictures directory.     File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), albumName);     if (!file.mkdirs()) {        Log.e(LOG_TAG, "Directory not created");     }    return file; }
    如果没有为要保存的文件指定子目录名称,可以调用不含参数的getExternalFilesDir()或者传null值,这时它会返回你的app在外部存储器上的根目录。如果调用上述两种方法新建子目录结构,命名方式应该规范,例如DIRECTORY_PICTURES,这样使得系统能够正确的对待这些目录。
    (3)查询剩余空间
    为了避免出现IOException,我们可以调用getFreeSpace()和getTotalSpace()方法来分别获取存储器的当前剩余的空间和总空间大小。当然我们也没有必要必须调用该方法,可以在写入文件的时候捕获IOException异常来解决。
    (4)删除文件
    对于不需要的文件,我们应该调用delete()方法将其删除掉。例如:
myFile.delete();  
    如果文件位于内部存储器上,可以通过Context来定位,调用deleteFile()来删除该文件。例如:
myContext.deleteFile(fileName);
    注意:当用户卸载掉你的APP后,所有保存在内部存储器上的文件和通过getExternalFilesDir()方法保存在外部存储器上的文件都将被删除。而通过getCacheDir()方法生成的临时文件你自己应该在不想要它们时手动删除掉。


    3)将数据保存在SQL数据库中
    利用SQLite数据库来读和写结构化数据。需要用到android.database.sqlite包。
    (1)定义一个架构和Contract
    SQL数据库最主要的一个原则是架构,它是对数据库是如何组织的一个正式的声明。架构是通过创建数据库的SQL语句来体现的。通常会创建一个伴随类,即contract类,它显示的说明了你所定义的架构的布局。contract类用于存放定义URIs、表和列的常量。它允许你使用任何来自同一包中的其他类的常量。如下的片段代码通过实现BaseColumes接口定义了一个单一表的表名和列名。
public static abstract class FeedEntry implements BaseColumns {     public static final String TABLE_NAME = "entry";    public static final String COLUMN_NAME_ENTRY_ID = "entryid";     public static final String COLUMN_NAME_TITLE = "title";     public static final String COLUMN_NAME_SUBTITLE = "subtitle";     ... }
    为了防止意外实例化contract类,可以定义一个私有的空构造函数,例如:
// Prevents the FeedReaderContract class from being instantiated. private FeedReaderContract() {}
    (2)利用SQL Helper来创建数据库
    一旦定义好了数据库,我们需要实现一些方法来创建和维护数据库和表。如下示例了建立和删除一个表:
private static final String TEXT_TYPE = " TEXT";private static final String COMMA_SEP = ","; private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " +   FeedReaderContract.FeedEntry.TABLE_NAME + " (" +FeedReaderContract.FeedEntry._ID +    " INTEGER PRIMARY KEY," +FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE +   COMMA_SEP + FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE +TEXT_TYPE + COMMA_SEP +    ... // Any other options for the CREATE command " )";private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + TABLE_NAME_ENTRIES;
    就像保存在设备的内部存储器上的文件一样,Android将数据库保存在伴随应用的内部存储空间里。通过使用SQLiteOpenHelper类,可以获得数据库的引用。然后调用getWriteableDatabase()或者getReadableDatabase()方法。考虑到它们一直运行,因此要确保这两个方法在后台线程中运行,例如AsyncTask或者IntentService。
    为了使用SQLiteOpenHelper类,可以创建一个子类并覆写onCreate()、onUpgrade()和onOpen()回调函数。如下为一个示例:
public class FeedReaderDbHelper extends SQLiteOpenHelper {     // If you change the database schema, you must increment the database version.     public static final int DATABASE_VERSION = 1;     public static final String DATABASE_NAME = "FeedReader.db";    public FeedReaderDbHelper(Context context) {         super(context, DATABASE_NAME, null, DATABASE_VERSION);     }    public void onCreate(SQLiteDatabase db) {          db.execSQL(SQL_CREATE_ENTRIES);    }    public void onUpgrade(SQLiteDatabase db, int oldVersion, intnewVersion) {         // This database is only a cache for online data, so its upgrade policy is        // to simply to discard the data and start over        db.execSQL(SQL_DELETE_ENTRIES);        onCreate(db);     }    public void onDowngrade(SQLiteDatabase db, int oldVersion, intnewVersion) {        onUpgrade(db, oldVersion, newVersion);     } }
    通过实例化SQLiteOpenHelper的子类,可以访问你的数据库。
    (3)将信息录入数据库
    通过传递一个ContentValues对象到insert()方法中可以将数据插入到数据库中,如下所示:
// Gets the data repository in write mode SQLiteDatabase db = mDbHelper.getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues();values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID, id);values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT,content); // Insert the new row, returning the primary key value of the new row long newRowId;newRowId = db.insert( FeedReaderContract.FeedEntry.TABLE_NAME,FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE, values);
    insert()函数第一个参数是表名,第二个参数指明列是否可以为空,第三个参数为插入的行值。
    (4)从数据库中读取信息
    通过传递选择的标准和想要的列参数,利用query()方法来读取数据库。查询的结果返回一个Cursor对象。
SQLiteDatabase db = mDbHelper.getReadableDatabase(); // Define a projection that specifies which columns from the database // you will actually use after this query. String[] projection = { FeedReaderContract.FeedEntry._ID,     FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE,     FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED,      ... }; // How you want the results sorted in the resulting Cursor String sortOrder = FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED+ " DESC"; Cursor c = db.query( FeedReaderContract.FeedEntry.TABLE_NAME, // The table to query     projection, // The columns to return     selection, // The columns for the WHERE clause     selectionArgs, // The values for the WHERE clause     null, // don't group the rows      null, // don't filter by row groups     sortOrder // The sort order);
    获得Cursor对象后,需要调用其move方法。通常,首先应该调用moveToFirst()方法将其定位到第一行。对于每一行,可以调用get方法,例如getString()或者getLong()方法来读取列的值。而每一个get方法都需要传递你想要读取的列的下标,通常调用getColumnIndex()或者getColumnIndexOrThrow()。例如:
cursor.moveToFirst(); long itemId = cursor.getLong(     cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID));
    (5)删除数据库中的信息
    删除表中的行,需要提供一个选择准则来确定行。例如:
// Define 'where' part of query. String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID+ " LIKE ?";// Specify arguments in placeholder order. String[] selelectionArgs = { String.valueOf(rowId) }; // Issue SQL statement. db.delete(table_name, selection, selectionArgs);
    (6)更新数据库
    调用update()方法可以更新数据库。例如:
SQLiteDatabase db = mDbHelper.getReadableDatabase(); // New value for one column ContentValues values = new ContentValues();values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title); // Which row to update, based on the ID String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; String[] selelectionArgs = { String.valueOf(rowId) };int count = db.update( FeedReaderDbHelper.FeedEntry.TABLE_NAME,    values,     selection,   selectionArgs);

    至此,关于保存数据的三种方法就介绍完了,针对数据的需求,我们应该选择正确的方法来执行数据的存储。
0 0
原创粉丝点击