注:本文翻译自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. 一次基于Vue.Js用户体验的优化

    .mytitle { background: #2B6695; color: white; font-family: "微软雅黑", "宋体", "黑 ...

  2. CodeBlocks

  3. Linux-Zabbix 邮件报警设置

    系统环境 Ubuntu 16.04 在Zabbix服务器端 安装sendmail sudo apt install sendmail 测试发送邮件 echo "正文!" | mai ...

  4. Pandas日期数据处理:如何按日期筛选、显示及统计数据

    前言 pandas有着强大的日期数据处理功能,本期我们来了解下pandas处理日期数据的一些基本功能,主要包括以下三个方面: 按日期筛选数据 按日期显示数据 按日期统计数据 运行环境为 windows ...

  5. Smart.coder每日站立会议08

    站立会议内容: 完善小程序的查找功能,打算考虑一下信息自动输入分类的功能. 1.站立会议照片: 2.任务展板 3.燃尽图

  6. Django学习报错记录

    1. 运行manage.py任务  makemigrations时,报错: doesn't declare an explicit app_label and isn't in an applicat ...

  7. Generating Sankey Diagrams from rCharts

    A couple of weeks or so ago, I picked up an inlink from an OCLC blog post about Visualizing Network ...

  8. Sampling Distributions and Central Limit Theorem in R(转)

    The Central Limit Theorem (CLT), and the concept of the sampling distribution, are critical for unde ...

  9. 初学JVM

    最近在读周志明的<深入理解Java虚拟机:JVM高级特性与最佳实践>,从中学到了很多,有些人可能会问为什么我们要学习JVM,他有什么用?在这里我想说一下,并不是这本书是大家都推荐的说有用处 ...

  10. javaCV开发详解之6:本地音频(话筒设备)和视频(摄像头)抓取、混合并推送(录制)到服务器(本地)

    javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...