Android 中的数据存储

以下是Android中最主要的三个数据存储方案:

1、在sharedpreferences文件中存储简单数据类型的键值对。
2、在Android文件系统中存储2进制文件。
3、用SQLite管理的数据库。

一、存储键值对集合
SharedPreferences sharedPref = context.getSharedPreferences(
        getString(R.string.preference_file_key), Context.MODE_PRIVATE);
如果只需要一个sharedpreferences文件,可以使用getPreferences()方法
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
写入数据:
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score), newHighScore);
editor.commit();
读取数据:
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);

二、存储文件

在Android中,存储分为内置和外置存储,二者的比较如下:

Internal storage:

  • It's always available.
  • Files saved here are accessible by only your app by default.
  • When the user uninstalls your app, the system removes all your app's files from internal storage.

Internal storage is best when you want to be sure that neither the user nor other apps can access your files.

External storage:

  • It's not always available, because the user can mount the external storage as USB storage and in some cases remove it from the device.
  • It's world-readable, so files saved here may be read outside of your control.
  • When the user uninstalls your app, the system removes your app's files from here only if you save them in the directory from getExternalFilesDir().

External storage is the best place for files that don't require access restrictions and for files that you want to share with other apps or allow the user to access with a computer.


提示:默认情况下,应用装在内置存储上,但是可以通过设置参数android:installLocation指定安装到SD卡。

应用对外置存储的读写不受限制,在清单文件中声明相应的权限即可。
getExternalFilesDir()方法得到应用的外置存储目录。

2.1、往内置存储上存储文件

相关的两个方法:
getFileDir(): 
Returns the absolute path to the directory on the filesystem where files created with   openFileOutput are stored.
getFileCache():

Returns the absolute path to the application specific cache directory on the filesystem. These files will be ones that get deleted first when the device runs low on storage. There is no guarantee when these files will be deleted. 

  Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, such as 1 MB, for the amount of space you consume with cache files, and prune(删除) those files when exceeding that space.

新建文件的典型方法:
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();
}
如果要缓存某个文件:
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.2、往外置存储上存储文件

由于外置存储状态不可靠,所以使用前要判断状态:
/* 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;
}
外部存储被可以被用户和其他应用程序 修改 ,有两种类型的文件可以保存:
Public files:
文件完全开放,即使应用被卸载,文件仍然可以被其它应用或用户访问。
Private files
文件只属于你自己的应用,应用被卸载时该文件应该被删除。虽然可以被用户和其它的应用访问到
(因为它们在外置存储上)但是确实不对它们提供任何价值。

生成Public file文件:getExternalStroagePublicDirectiory(),该方法有一个参数,指定文件的类型,可以从逻辑上组织公共文件。
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;
}
创建Private File:getExternalFilesDir(),传入一个指定File类型的值(或者为Null代表根目录)

For example, here's a method you can use to create a directory for an individual photo album:

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;
}
建议用API提供的静态值来指定目录类型,比如Environment.DIRECTORY_RINGTONES会被系统媒体扫描器归类为铃声,而不是音乐。

2.3、查询可用空间

public long getFreeSpace ()
Added in API level 9

Returns the number of free bytes on the partition containing this path. Returns 0 if this path does not exist.

Note that this is likely to be an optimistic over-estimate and should not be taken as a guarantee your application can actually write this many bytes.


public long getTotalSpace ()
Added in API level 9

Returns the total size in bytes of the partition containing this path. Returns 0 if this path does not exist.


在你明确知道你要写入多少数据时,可以使用上述两个方法,否则还是直接写入在空间不够的时候catch
IO异常比较好点。

2.4、删除文件
直接调用File.delete()
或者文件在内置存储上时,context.deleteFile(fileName)

三、用SQL数据库存储数据

Android中与SQLite相关的API在android.datebase.sqlite包下;

3.1、首先创建数据库的schema,就是用来描述数据库结构和表的组成部分的一个类,我是第一次见。

public final class FeedReaderContract {
    // To prevent someone from accidentally instantiating the contract class,
    // give it an empty constructor.
    public FeedReaderContract() {}

    /* Inner class that defines the table contents */
    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";
        ...
    }
}
BaseColumns接口中有    public static final String _ID = "_id";
 public static final String _COUNT = "_count"; 两个成员,创建表的时候就不用重重复的写了。
3.2、写创建表的语句,和创建数据库
创建和删除表的典型语句如下:
private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
    "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
    FeedEntry._ID + " INTEGER PRIMARY KEY," +
    FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
    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 " + FeedEntry.TABLE_NAME;

3.3、继承SQliteOpenHelper创建数据库
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, int newVersion) {
        // 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, int newVersion) {
        onUpgrade(db, oldVersion, newVersion);
    }
}

To access your database, instantiate your subclass of SQLiteOpenHelper:

FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
3.4、向数据库中存入数据
// 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(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);

// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
         FeedEntry.TABLE_NAME,
         FeedEntry.COLUMN_NAME_NULLABLE,
         values);
其中insert()方法的第二个参数,FeedEntry.COLUMN_NAME_NULLABLE,的作用是:如果values为null
系统就向表中插入空的列名,如果此参数置为Null,则当values为空时,将不向表中插入数据。

3.5、从数据库中读数据
SQLiteDatabase db = mDbHelper.getReadableDatabase();

// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
    FeedEntry._ID,
    FeedEntry.COLUMN_NAME_TITLE,
    FeedEntry.COLUMN_NAME_UPDATED,
    ...
    };

// How you want the results sorted in the resulting Cursor
String sortOrder =
    FeedEntry.COLUMN_NAME_UPDATED + " DESC";

Cursor c = db.query(
    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
    );
c.moveToFirst();
long itemId = cursor.getLong(
    cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
 另外常用的方法:while(cursor.moveToNext())
3.6、从数据库中删除数据
// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);
3.7、更新数据库表
SQLiteDatabase db = mDbHelper.getReadableDatabase();

// New value for one column
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);

// Which row to update, based on the ID
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };

int count = db.update(
    FeedReaderDbHelper.FeedEntry.TABLE_NAME,
    values,
    selection,
    selectionArgs);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值