注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/basics/data-storage/databases.html


在数据库中保存数据,对于重复性的或者结构化的数据来说是很理想的,比如:联系人信息。这节课我们假定你对SQL数据库有一个大致的了解,并且帮助你在Android上开始使用SQLite数据库。你在Android的数据库上需要使用的APIs在android.database.sqlite包中。

一). 定义一个架构(Schema)和契约(Contract)

SQL数据库的主要核心之一是:一个数据库是如何组织的正式声明。架构所对应的就是你用来创建数据库的SQL语句声明。你会发现创建一个辅助类(companion class),即所谓的合同类(contract class),它通过一个系统的和自文档化的方式来显示地指定你的架构布局。

一个合同类是一个容器,它包含了那些定义了URI,表和列的名称的常量。合同类允许你在同一个包内所有类之间使用相同的名字。这样可以使你想要改变列名时只需在一个地方修改,就能影响到所有使用到它的代码。

一个良好的组织合同类的方式是:在类的根位置处,放置那些你的数据库的全局定义。然后为每一个表创建一个内部类,来枚举它的列。

Note:

通过实现基列(BaseColumns)接口,你的内部类可以继承一个主键字段,叫做:“_ID”。一些Android类,比如光标适配器(cursor adaptors)会期望它能够拥有这个。虽然这个不是必须的,但是它能够帮助你的数据库和Android更协同地工作。

例如,下例为一个简单的表定义了表名和列名:

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

 二). 使用SQL助手创建一个数据库

一旦你定义了你的数据库,你应该实现一些方法来创建和维护你的数据库及表。下例是一些标准的创建和删除数据库的声明:

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;

就好像在设备内存(internal storage)中所存储的文件一样,Android会将你的数据库存储在一个和应用有关联的私有磁盘空间中。你的数据将是安全的,因为默认情况下这些数据不会被其他应用访问到。

一个有用的APIs集合在SQLiteOpenHelper类中。当你使用这个类来获取你的数据库的引用时,系统会仅在需要时(不在应用启动时)执行一些可能需要消耗较长时间的操作,如:创建,更新数据库。所有你需要的是调用getWritableDatabase()或者getReadableDatabase()

Note:

因为它们可能会消耗比较长的时间,所以请确保你在一个后台线程调用getWritableDatabase()或者getReadableDatabase(),比如:AsyncTask或者IntentService

要使用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 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()方法的第一个参数就是表名。第二个参数提供了一个列名,当ContentValues为空时,框架会插入一个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 = {
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
);

为了查询cursor中的一行,使用Cursor中的一个移动方法,这个方法你必须在开始读数据时一直调用。一般地,你应该从调用moveToFirst()开始,这样将读取位置放置到结果的第一个记录。对于每一行,你可以你可以读取某一列的值,通过调用Cursor的一个get方法,比如:getString()或者getLong()。对于每个get方法,你必须传入你期望的列的索引号,你可以通过调用getColumnIndex()或者getColumnIndexOrThrow()来得到索引号。

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

五). 从数据库中删除数据

为了从数据库中删除一行数据,你需要提供一个选择标准来指定一行。数据库的API提供了一个创建选择标准的机制来防止SQL注入攻击。这个机制将选择语句分为了选择命令段(selection clause)和选择参数。命令段指定了要寻找的列,并且允许你可以结合一些列测试。参数是要测试的值,它是和命令段相对应的。因为这个结果和通常的SQL语句声明处理起来不一样,所以能够方式SQL注入。

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

六). 更新一个数据库

当你需要修改一个数据库值的子集,可以使用update()方法。

更新表结合了insert()的内容语法和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
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) }; int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);

【Android Developers Training】 26. 在SQL数据库中保存数据的更多相关文章

  1. Android - 数据存储 -在SQL数据库中保存数据

    对于重复的或结构化的数据,保存到数据库中是很好的选择,比如联系人信息.这里假设你对SQL数据库大体上了解然后帮助你学习Android上的SQLite数据库.在Android数据库上需要用到的API可以 ...

  2. 【Android Developers Training】 97. 序言:访问通讯录数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 100. 使用Intent修改联系人数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 31. 序言:共享简单数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 23. 序言:保存数据

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. SQL语句:把Excel文件中数据导入SQL数据库中的方法

    1.从Excel文件中,导入数据到SQL数据库情况一.如果接受数据导入的表不存在 select * into jd$ from OPENROWSET('MICROSOFT.JET.OLEDB.4.0' ...

  7. 【Android Developers Training】 60. 在你的UI中显示位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. Android学习笔记——保存数据到SQL数据库中(Saving Data in SQL Databases)

    知识点: 1.使用SQL Helper创建数据库 2.数据的增删查改(PRDU:Put.Read.Delete.Update) 背景知识: 上篇文章学习了保存文件,今天学习的是保存数据到SQL数据库中 ...

  9. 【Android Developers Training】 106. 创建并检测地理围栏

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. Linux防火墙的关闭和开启

    1) 重启后生效 开启: chkconfig iptables on 关闭: chkconfig iptables off 2) 即时生效,重启后失效 开启: service iptables sta ...

  2. ConcurrentSkipListMap深入分析

    1.前言 ConcurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下,ConcurrentHashMap 存取速度是ConcurrentSki ...

  3. mongodb新人扫盲

    前言 数据库基本命令 集合(表)命令 增加数据 删除数据 更新数据 使用update()更新 使用save()命令实现upsert 自动更新信息 查询数据 mongoose的使用 前言 mongodb ...

  4. 三、 添加视图View(ASP.NET MVC5 系列)

    在这一章节我们可以修改HelloWorldController类,通过使用视图模板来封装处理产生给客户端的HTML响应. 我们将使用Razor View engine来创建视图文件.基于Razor的视 ...

  5. MySQL主从搭建

    主服务器配置 1.编辑配置文件 # 如果不存在,就手动创建一个 vim /etc/my.cnf 在配置文件加入如下值: [mysqld] # 唯一的服务辨识号,数值位于 1 到 2^32-1之间. # ...

  6. 在eclipse-jee-juno中配置Aptana对jQuery代码自动提示

    主要问题 在Aptana的Web Project中打开js文件有JavaScript的自动提示,但是在JavaEE项目中却没有. 版本 eclipse-jee-juno,即Eclipse 4.2的Ja ...

  7. Spring学习笔记——01 控制反转

    想一下之前学的Java,如果某个类需要引用某个对象,则需要手动new一个出来.这样带来的一个问题就是,若被引用的类发生改动或被删除,则引用它的所有类都会报错.因为两个类耦合在一起了.解决的办法就是不由 ...

  8. TCP:三次握手、四次握手、backlog及其他

    TCP是什么 首先看一下OSI七层模型: 然后数据从应用层发下来,会在每一层都加上头部信息进行封装,然后再发送到数据接收端,这个基本的流程中每个数据都会经过数据的封装和解封的过程,流程如下图所示: 在 ...

  9. Activity常用的方法

    1. View findViewById(int id) //根据组件ID取得组件对象setContentView(int LayoutResID) //设置布局文件,设置显示组件 2. TextVi ...

  10. std::forward_list

    forward_list相比list来说空间利用率更好,与list一样不支持随机访问,若要访问除头尾节点的其他节点则时间复杂度为线性. 在forward_list成员函数里只能访问头节点以及向头节点插 ...