跟Google学习Android开发-起始篇-保存数据(3)

来源:互联网 发布:淘宝联盟高佣怎么设置 编辑:程序博客网 时间:2024/05/17 08:56

5.3将数据保存在SQL数据库


对于重复或结构化的数据,如联系人信息,将它们保存到数据库是理想选择。这节课假定您熟悉一般的SQL数据库,并帮助您开始在Android上使用SQLite数据库。在Android上,你需要使用数据库的API都在 android.database.sqlite包提供。


定义一个模式(Schema和合同(Contract


SQL数据库的主要原则之一是模式:数据库是如何组织的正式声明。该模式体现在你用来​​创建数据库的SQL语句中。您可能会发现它有利于创造一个同伴(companion)类,作为合同类为人所知,后者用系统和自文档(self-documentint)的方式明确指定您的模式的布局。

合同类是定义URI、表和列名等常量的一个容器。合同类,允许您在同一个包中的其它所有类里使用相同的常量。这可以让你在一个地方改变某个列名,它就传遍你的代码。

组织​​合同类的一个好方法就是把你的整个数据库的全局定义放到类的根层次。然后为每个枚举列的表创建一个内部类。

注:通过实现BaseColumns接口,内部类可以继承一个称为_ID主键字段,某些Android类,如光标适配器,会期望你的内部类有这个字段。它不是必需的,但这个可以帮你的数据库与Android框架和谐地工作。

例如,这个片段定义为一个单一的表的表名和列名:

publicstatic abstractclass FeedEntryimplements BaseColumns{
    public staticfinal String TABLE_NAME= "entry";
    public staticfinal String COLUMN_NAME_ENTRY_ID= "entryid";
    public staticfinal String COLUMN_NAME_TITLE= "title";
    public staticfinal String COLUMN_NAME_SUBTITLE= "subtitle";
    ...
}

为了防止有人意外地实例化合同类,给它一个空的构造方法。

// Prevents the FeedReaderContract class from beinginstantiated.
private FeedReaderContract(){}


使用SQL Helper创建数据库


一旦你定义完你的数据库的样子,你应该实现创建和维护数据库和表的方法。下面是一些典型的创建和删除一个表的语句:

privatestatic finalString TEXT_TYPE =" TEXT";
private staticfinal String COMMA_SEP= ",";
private staticfinal String SQL_CREATE_ENTRIES=
    "CREATETABLE " + 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 staticfinal String SQL_DELETE_ENTRIES=
    "DROPTABLE IF EXISTS " + TABLE_NAME_ENTRIES;

就像您保存在设备内部存储的文件那样,Android的存储你的数据库在与应用程序关联的私有磁盘空间。您的数据是安全的,因为默认情况下,这个区域对其他应用程序是不可访问的。

一组有用的API,可在SQLiteOpenHelper类中找到。当你使用这个类来获取到你的数据库的引用时,系统执行潜在的长时间运行的创建和更新数据库的操作,只会在需要的时候,而不是在应用程序启动时。你所要做的全部就是调用getWritableDatabase() getReadableDatabase() 

注:因为他们可以长时间运行,确保您是在后台线程调用getWritableDatabase()getReadableDatabase(),比如用AsyncTaskIntentService

要使用 SQLiteOpenHelper,创建一个子类重写onCreate() onUpgrade()  onOpen()回调方法。您可能还想要实现onDowngrade()方法,但它不是必需的。

 

例如,这里是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());

将信息存入数据库


通过传递一个ContentValues 对象到 insert() 方法,可以把数据插入到数据库中:

// Gets the data repository in write modeSQLiteDatabase db = mDbHelper.getWritableDatabase();// Create a new map of values, where column names are the keysContentValues 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 rowlong newRowId;newRowId = db.insert(         FeedReaderContract.FeedEntry.TABLE_NAME,         FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE,         values);

 insert()方法的第一个参数很简单就是表名。第二个参数提供列名,如果 ContentValues为空(empty)框架会为该列插入NULL (如果你把列名设为"null",那么当它没有值时框架将不会插入一行).


从数据库中读取信息


使用query() 方法从数据库中读取,传递你的选择子句和所需的列。该方法结合了insert() update()元素,除了那些列是定义你想获取的数据,而不是要插入的数据。查询结果在一个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 CursorString 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 的移动方法,在开始读取值之前你必须始终调用这些方法。一般来说,你应该从调用moveToFirst()开始,让“读取位置”定位到结果中的第一项。对于每一行,你可以通过调用一个Cursor get方法来读取列的值,如 getString()getLong()。对于每一个get方法,你必须传递你想要的列的索引位置,你可以通过调用getColumnIndex() getColumnIndexOrThrow()得到列的索引。例如:

cursor.moveToFirst();long itemId = cursor.getLong(    cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID));

从数据库中删除信息


要删除表中的行,你需要提供的选择条件来确定哪些行。数据库API提供了一种机制来创建可防止SQL注入的选择条件。该机制将选择规范分解成一个选择子句和选择参数。子句定义列,也允许你组合列来试验。参数是试验绑定到子句的值。(原文:The clausedefines the columns to look at, and also allows you to combine column tests.The arguments are values to test against that are bound into the clause.因为结果与一个常规的SQL语句处理不一样,它对SQL注入是免疫的。

// Define 'where' part of query.String selection = FeedReaderContract.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);

更新数据库


当你需要修改你的数据库数值的一个子集时,使用 update() 方法。更新表内容结合使用insert() 方法的语法和带wheredelete()方法的语法。(原文:Updating the table combines thecontent values syntax of insert()with the where syntax ofdelete()

SQLiteDatabase db = mDbHelper.getReadableDatabase();// New value for one columnContentValues values = new ContentValues();values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);// Which row to update, based on the IDString selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";String[] selectionArgs = { String.valueOf(rowId) };int count = db.update(    FeedReaderDbHelper.FeedEntry.TABLE_NAME,    values,    selection,    selectionArgs);
原创粉丝点击