Saving Data笔记

Saving Data笔记

SharedPreferences APIs是用来读/写键值对的,Preference APIs是用来构建app设置页面的UI(其使用SharedPreference来保存app设置)。

SharedPreferences

获取SharedPreferences引用

  • 通过Context的getSharedPreference()方法。
Context context = getActivity();
SharedPreferences sharedPref = context.getSharedPreferences(
        getString(R.string.preference_file_key), Context.MODE_PRIVATE);
  • 通过Activity的getPreferences()方法,会为Activity创建专属SharedPreferences。
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
  • 通过PreferenceManager的getDefaultSharedPreferences()方法,会为app创建专属SharedPreferences。

注意:如果使用MODE_WORLD_READABLE或MODE_WORLD_WRITEABLE创建SharedPreferences文件,其他app知道文件名即可访问数据。

向SharedPreferences写入数据

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score), newHighScore);
editor.commit();

从SharedPreferences读取数据

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);

Saving Files

内部存储和外部存储

所有Android设备都有两个文件存储:”内部”和”外部”存储。有些设备能够挂载sd卡作为外部存储;有些不能挂载sd卡的设备会把存储分成内部和外部存储,这种外部存储是不能移除的。
有关手机存储的解释:

提示:尽管app默认安装在内部存储,可以在<manifest>标签通过android:installLocation属性选择安装位置。

获取外部存储的权限

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

注意:当前,获取外部存储的写权限,同时也获得了读权限。这在之后的发布版本中可能会修改。最好明确指定 READ_EXTERNAL_STORAGE权限。

在内部存储上保存文件

获取内部存储目录的两种方法:
getFilesDir()
  返回File代表app内部存储的目录。
getCacheDir()
  返回File代表app内部存储的临时缓存目录。最好给缓存文件设置个阈值,删除不用的文件。系统在低存储的情况下坑你会删除缓存文件。

openFileOutput()
  获取内部存储文件的输出流,文件不存在会创建文件。
  

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();
}

如果需要缓存文件,可以使用createTempFile()创建文件。

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

注意:app在内部存储的文件夹名称是由包名决定的。如果没有显示的指定文件是可读或可写的,其他app不能访问这些文件。

在外部存储保存文件

因为外部存储可能不可用——比如SD卡被移除,挂载到PC,因此,在使用外部存储前先调用getExternalStorageState()检查外部存储的状态。

/* 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
  所有用户和app都可以使用。通常用来保存照片和下载文件。
Private files
  属于app的文件,卸载app文件会被删除。其他用户或app知道包名的情况下也可使用文件。
  
不管使用getExternalStoragePublicDirectory()还是getExternalFilesDir(),尽量使用API提供的目录常量,比如DIRECTORY_PICTURE。这些目录名能保证系统正确处理文件。比如,存储在DIRECTORY_RINGTONES目录会被系统媒体管理认为是铃声而不是音乐。

查询剩余空间

如果在存储数据前知道数据大小,可以调用getFreeSpace()或getTotalSpace查看空间大小。

系统并不保证可以写入和getFreeSpace()返回值一样的数据量。

注意:在存储数据前不需要检查可用空间,可以捕获IOException来做存储数据失败的操作。

删除文件

获取文件引用,调用delete()方法。

myFile.delete();

如果文件存在内部存储,可以调用Context的deleteFile()方法。

myContext.deleteFile(fileName);

注意:当卸载app,android系统会删除的文件
- 所有内部存储的文件。
- 所有用getExternalFilesDir()存在外部存储文件。

在数据库保存数据

定义Scheme和Contract

创建定义URIs、tables和columns常量的contract类,可以方便对这些常量进行统一管理。

通过实现BaseColumns接口,内部类可以继承主见字段_ID,在使用cursor adaptors很有用。

定义table和colum如下:

public final class FeedReaderContract {
    // To prevent someone from accidentally instantiating the contract class,
    // make the constructor private.
    private FeedReaderContract() {}

    /* Inner class that defines the table contents */
    public static class FeedEntry implements BaseColumns {
        public static final String TABLE_NAME = "entry";
        public static final String COLUMN_NAME_TITLE = "title";
        public static final String COLUMN_NAME_SUBTITLE = "subtitle";
    }
}

使用SQL Helper创建数据库

创建和删除table的SQL:

private static final String SQL_CREATE_ENTRIES =
    "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
    FeedEntry._ID + " INTEGER PRIMARY KEY," +
    FeedEntry.COLUMN_NAME_TITLE + " TEXT," +
    FeedEntry.COLUMN_NAME_SUBTITLE + " TEXT)";

private static final String SQL_DELETE_ENTRIES =
    "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;

数据库存在内部存储,默认情况下其他应用不能使用。

注意:getWritableDatabase()和getReadableDatabase()可能是耗时操作,最好不要在主线程调用。

继承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);
    }
}

实例化SQLiteOpenHelper子类:

FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());

向数据库插入数据

插入一条记录:

// 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_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle);

// Insert the new row, returning the primary key value of the new row
long newRowId = db.insert(FeedEntry.TABLE_NAME, null, values);

insert()的第二个参数表示,当ContentValues为空(没有放入values),参数为空,不会向表插入记录;否则,插入一条记录参数指定的列为null。

从数据库读取数据

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_SUBTITLE
    };

// Filter results WHERE "title" = 'My Title'
String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String[] selectionArgs = { "My Title" };

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

Cursor cursor = 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
    );

因为Cursor的初始位置为-1,所以在读取数据之前,要先调用move方法。用cursor读取数据:

List itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
  long itemId = cursor.getLong(
      cursor.getColumnIndexOrThrow(FeedEntry._ID));
  itemIds.add(itemId);
}
cursor.close();

从数据库删除记录

selection格式分成selection语句和selection参数两部分,这样可以防止SQL注入。

// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { "MyTitle" };
// Issue SQL statement.
db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);

更新数据库

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 title
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
String[] selectionArgs = { "MyTitle" };

int count = db.update(
    FeedReaderDbHelper.FeedEntry.TABLE_NAME,
    values,
    selection,
    selectionArgs);

保持数据库连接

由于getWritableDatabase()和getReadableDatabase()在database关闭时调用开销很高,所以尽可能保持数据库连接 状态。在Activity的onDestroy()关闭数据库是最佳时机。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值