Google Android开发者文档系列-数据存储之通过SQL数据库保存数据

原创 2016年05月30日 16:01:06

Saving Data in SQL Databases(通过SQL数据库保存数据)

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能错译的误区。在此感谢http://android.xsoftlab.net/提供的镜像,希望转载者注明出处http://blog.csdn.net/u014031072/article/details/51538673方便查看最新博客

Saving data to a database is ideal for repeating or structured data, such as contact information. This class assumes that you are familiar with SQL databases in general and helps you get started with SQLite databases on Android. The APIs you’ll need to use a database on Android are available in the android.database.sqlite package.
数据库是重复或结构化数据的理想保存场所,如联系人信息。这次课程假定您熟悉一般的SQL数据库,并帮助您开始使用Android上的SQLite数据库。你需要在Android上使用数据库的API是在android.database.sqlite包下封装的。

Define a Schema and Contract(定义一个架构和协议)

One of the main principles of SQL databases is the schema: a formal declaration of how the database is organized. The schema is reflected in the SQL statements that you use to create your database. You may find it helpful to create a companion class, known as a contract class, which explicitly specifies the layout of your schema in a systematic and self-documenting way.
SQL数据库的一个主要原则就是架构:一份关于该数据库是如何组织的正式声明。该架构体现在您用于创建数据库的SQL语句中。通过系统和自定义的方式去明确定义你的数据库架构的布局,你可能会发现非常有助于去创建其衍生类,称之为协议类。

A contract class is a container for constants that define names for URIs, tables, and columns. The contract class allows you to use the same constants across all the other classes in the same package. This lets you change a column name in one place and have it propagate throughout your code.
协议类是关于URI的定义名称、表、列的常量的容器。协议类允许你在位于同一个包下的所有其他类使用与之相同的常量。这使您可以在一个地方更改列名,而在你的所有代码得到同步。

A good way to organize a contract class is to put definitions that are global to your whole database in the root level of the class. Then create an inner class for each table that enumerates its columns.
组织一个协议类的一个好方法是把你的整个数据库的全局定义放在该类的根层级下。然后创建一个关于每个表的内部类来枚举它的列。

Note: By implementing the BaseColumns interface, your inner class can inherit a primary key field called _ID that some Android classes such as cursor adaptors will expect it to have. It’s not required, but this can help your database work harmoniously with the Android framework.
注:通过实现BaseColumns接口,你的内部类可以继承一个诸如cursor适配器类型的Android类所期望的主键字段,称为_ID。它不是必需的,但是它有助于您的数据库在Android框架下协调的工作。

For example, this snippet defines the table name and column names for a single table:

例如,下面的代码片段定义了一个单独表的表名和列名:

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

Create a Database Using a SQL Helper(通过SQL Helper创建数据库)

Once you have defined how your database looks, you should implement methods that create and maintain the database and tables. Here are some typical statements that create and delete a table:
一旦你定义了你的数据库的样子,你应该实现创建和维护数据库和表的方法。下面是创建和删除表中的一些典型的语句:

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;

Just like files that you save on the device’s internal storage, Android stores your database in private disk space that’s associated application. Your data is secure, because by default this area is not accessible to other applications.
就像您在设备的内部存储保存的文件一样,Android将您的数据库保存在了程序关联的私有磁盘空间中。您的数据是安全的,因为默认情况下这个区域是其他应用程序访问不到的。

A useful set of APIs is available in the SQLiteOpenHelper class. When you use this class to obtain references to your database, the system performs the potentially long-running operations of creating and updating the database only when needed and not during app startup. All you need to do is call getWritableDatabase() or getReadableDatabase().
在SQLiteOpenHelper类中有许多有用并且可用的API。当你使用这个类来获取数据库的引用时,只有在需要时系统才会执行潜在的创建和更新的耗时操作,而不是在应用程序一启动时就执行。所有你需要做的就是调用getWritableDatabase()或getReadableDatabase()。

Note: Because they can be long-running, be sure that you call getWritableDatabase() or getReadableDatabase() in a background thread, such as with AsyncTask or IntentService.
注:因为他们可以长期运行(耗时任务),请确保您调用getWritableDatabase()或getReadableDatabase()时是在后台线程中,如AsyncTask的或IntentService。

To use SQLiteOpenHelper, create a subclass that overrides the onCreate(), onUpgrade() and onOpen() callback methods. You may also want to implement onDowngrade(), but it’s not required.
要使用SQLiteOpenHelper,需要创建子类去覆盖onCreate(),onUpgrade()和的OnOpen()等回调方法。您可能还想去实现onDowngrade(),但它不是必需的。

For example, here’s an implementation of SQLiteOpenHelper that uses some of the commands shown above:
例如,下面是一个使用一些上面命令的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:
要访问数据库,实例化SQLiteOpenHelper的子类:

FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());

Put Information into a Database(向数据库中添加信息)

Insert data into the database by passing a ContentValues object to the insert() method:
通过传递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
//创建一组map值,与关键字的列名对应
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);

The first argument for insert() is simply the table name. The second argument provides the name of a column in which the framework can insert NULL in the event that the ContentValues is empty (if you instead set this to “null”, then the framework will not insert a row when there are no values).
insert()的第一个参数仅仅是表名。第二个参数提供了该框架中可以插入NULL值的列名,以免插入的ContentValues是空的(如果将其设置为“空”,则该框架将不会插入一行值)。

Read Information from a Database(从数据库中读取信息)

To read from a database, use the query() method, passing it your selection criteria and desired columns. The method combines elements of insert() and update(), except the column list defines the data you want to fetch, rather than the data to insert. The results of the query are returned to you in a Cursor object.
若要从数据库中读取信息,使用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 = {
    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 WHERE语句
    selectionArgs,                            // The values for the WHERE clause WHERE语句中对应的值
    null,                                     // don't group the rows 不使用group语句
    null,                                     // don't filter by row groups 不使用groups的filter语句
    sortOrder                                 // The sort order 排序(分类)方式
    );

To look at a row in the cursor, use one of the Cursor move methods, which you must always call before you begin reading values. Generally, you should start by calling moveToFirst(), which places the “read position” on the first entry in the results. For each row, you can read a column’s value by calling one of the Cursor get methods, such as getString() or getLong(). For each of the get methods, you must pass the index position of the column you desire, which you can get by calling getColumnIndex() or getColumnIndexOrThrow(). For example:
在你开始阅读返回游标中的数据行之前,你应该先使用光标移动的方法来移动到这一行。通常情况下,你应该先调用moveToFirst(),来使读取位置移动到返回结果的第一行。对于每一行,你可以通过调用光标的get方法,如getString()或getLong之()中任何一个来读取列的值。对于每一个get方法,你必须传递你期望查询列的索引位置,索引位置可以通过调用getColumnIndex()或getColumnIndexOrThrow()得到。 例如:

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

Delete Information from a Database(删除数据库中的信息)

To delete rows from a table, you need to provide selection criteria that identify the rows. The database API provides a mechanism for creating selection criteria that protects against SQL injection. The mechanism divides the selection specification into a selection clause and selection arguments. The clause defines 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. Because the result isn’t handled the same as a regular SQL statement, it is immune to SQL injection.
从表中删除行,您需要提供目标行的选择标准。该数据库API提供了创建选择标准并防止SQL注入的机制。该机制把选择规范成一个选择条款和选择参数。该条款规定了所关注的列,也允许你和列测试结合起来。该参数值是要测试的绑定子句对应的值。因为对结果的处理不同于常规的SQL语句,所以它不受SQL注入攻击。

// Define 'where' part of query.
//定义查询语句的where部分
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
//指定占位符对应的参数。
String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
//执行SQL语句
db.delete(table_name, selection, selectionArgs);

Update a Database(更新数据库信息)

When you need to modify a subset of your database values, use the update() method.
当您需要修改数据库子集的值时,使用update()方法。

Updating the table combines the content values syntax of insert() with the where syntax of delete().
更新表融合了inset()插入contentvalues值的语法()与delete()删除值中的where语法()。

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
//通过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);

Google Android开发者文档系列-创建有内容分享特性的应用之发送简单数据到其它应用程序

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-创建有内容分享特性的应用之接收其它应用程序发送的简单数据

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-创建有内容分享特性的应用之获取文件信息

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-开发企业App

Building Apps for Work(开发企业App)该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有...

Google Android开发者文档系列-创建有内容分享特性的应用之共享文件

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-与其他应用程序交互(序言)

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-创建有内容分享特性的应用之文件共享(序言)

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-创建有内容分享特性的应用之请求共享文件

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-与其他应用程序交互之获取Activity返回的结果

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...

Google Android开发者文档系列-创建有内容分享特性的应用之添加一个简单的共享action

该系列文章是我在学习Google开发者文档时结合谷歌翻译和自身理解编写的,希望对学习Android开发的朋友带来些便利,由于个人翻译水平有限,所以内容包含原文和译文,希望浏览者结合理解,以免步入我可能...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Google Android开发者文档系列-数据存储之通过SQL数据库保存数据
举报原因:
原因补充:

(最多只允许输入30个字)