上篇文章已经介绍了如何使用SharedPreferences存储键值对形式的轻量级数据,对于那些相同结构的多组数据,类似于存储Java中定义的类的多个对象属性值,如果按照键值对的形式一条条读写,需要分别定义每条数据对应的key值,是相当繁琐的。而如果可以使用数据库保存就会方便很多。

正因此,Android系统提供了对SQLite数据库的支持,在应用中创建的数据库,默认也是保存在应用程序的内部存储空间中的,这样也只有当前应用程序内部可以访问其数据库中数据。

使用纯粹的SQLiteDatabase类操作数据库

在Android系统中可以使用android.database.sqlite.SQLiteDatabase数据库类,直接操作SQLite数据库。同时借助android.database.sqlite.SQLiteOpenHelper数据库帮助类,来获取数这里的据库类。

定义数据库结构类

一般要保存的类结构与数据库结构保持一致即可,以学生信息为例,下面创建的Student类即可直接作为数据库结构类,只需按照Student类中的属性名一一对应,定义数据库中的字段名。

public final class Student {
private String name;
private String birthday;
private int level;
private Student() {} public static final String TABLE_NAME = "student";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_BIRTHDAY = "birthday";
public static final String COLUMN_LEVEL = "level";
}

在定义数据库中的字段名时,通常会定义值为 _id 的字段作为数据表中的自增长字段,这是为了在读取数据表时使用android.widget.CursorAdapter适配器子类可以正常创建其实例化对象。否则在使用CursorAdapter适配器实例化对象时可能会抛出java.lang.IllegalArgumentException异常。

创建数据库

与数据库中包含数据表的结构相对应,这里定义继承自SQLiteOpenHelper的子类处理数据表间关系,并在自定义子类中实现onCreate(SQLiteDatabase db)onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)方法。

通常该类的构造方法继承自其父类SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version),参数 context 为使用该数据库的上下文环境;参数 name 为数据库文件的名字;参数 factory 为访问数据库使用的游标工厂,通常传入 null 即可;参数 version 为数据表的版本号。

该类实现的onCreate(SQLiteDatabase db)方法会在对象创建后,数据库文件首次创建时调用,因此可以在该方法中执行数据表的创建操作,参数 db 即当前数据库对象,可调用该对象的相关方法操作数据库。

onUpdate(SQLiteDatabase db, int oldVersion, int newVersion)方法会在该类对象创建后,数据库文件存在但数据库版本升级时调用,因此在该方法中可以执行数据表的更新操作。其中参数 db 为当前数据库对象,同样调用该对象的相关方法可操作数据库;参数 oldVersion 为数据库版本升级之前的旧版本号;参数 newVersion 为数据库版本升级之后的新版本号。

以上文创建Student学生类对应的数据库为例,示例代码如下。当首次创建StudentDbHelper对象时,其对应数据库版本号为10,且数据库文件需要首次创建,因此会执行该对象的onCreate()方法,在数据库中执行SQL_CREATE_STUDENT定义的sql语句,创建不包含 birthday 字段的数据表。而如果在以后需要更新数据表时,想增加 birthday 字段,只需要在创建StudentDbHelper对象时,将其对应数据库版本号改为20,并在onUpdate()方法中做版本号的判断,一旦判断符合条件,即可执行SQL_ADD_BIRTHDAY定义的sql语句。

public class StudentDbHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION_FIRST = 10;
public static final int DATABASE_VERSION_SECONDDATABASE_VERSION_SECOND = 20; public static final String DATABASE_NAME = "students.db"; private static final String SQL_CREATE_STUDENT =
"CREATE TABLE " + Student.TABLE_NAME + " (" +
Student.COLUMN_ID + " INTEGER PRIMARY KEY," +
Student.COLUMN_NAME + " TEXT," +
Student.COLUMN_LEVEL + " TEXT)"; private static final String SQL_ADD_BIRTHDAY =
"ALTER TABLE " + Student.TABLE_NAME +
" ADD COLUMN " + Student.COLUMN_BIRTHDAY + " TEXT"; public StudentDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION_FIRST);
//super(context, DATABASE_NAME, null, DATABASE_VERSION_SECOND);
} public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_STUDENT);
} public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(newVersion==DATABASE_VERSION_SECOND){
db.execSQL(SQL_DELETE_BIRTHDAY);
}
} }

操作数据库

上边在SQLiteDbHelper子类中已经对SQLiteDatabase类有所了解,除此之外,也可以在需要获取数据库对象的地方通过SQLiteDbHelper对象的getWritableDatabase()方法获取可读写数据库和getReadableDatabase()方法获取可读式数据库。

在获取到SQLiteDatabase数据库对象之后,可通过其相关方法分别执行数据库的增删改查等操作。

调用该对象的insert(String table, String nullColumnHack, ContentValues values)系列方法,可以在数据库中插入一条数据。返回 long 类型的结果表示插入数据在数据表中的id序列,如果插入失败则返回 -1 。其中参数 table 为要插入的数据表名;参数 nullColumnHack 可以指定要插入的字段名,通常为null时忽略,使用后边参数中所包含的字段数据;参数 values 指定要插入的数据,同样使用 key-value 键值对的形式存取数据。

调用该对象的delete(String table, String whereClause, String[] whereArgs)方法,可以删除数据库中指定的数据。返回 int 类型的结果表示删除的数据条数。其中参数 table 同样为要删除的数据表名;参数 whereClause 为指定删除条件,其符合sql语句,但变量参数可用?代替,在后边参数中指定具体参数值;参数 whereArgs 即为参数值数组,长度与参数 whereClause 中的?符合数量一致。如果删除某个数据表中的所有内容,只需将参数二和参数三均置为null即可。

调用该对象的update(String table, ContentValues values, String whereClause, String[] whereArgs)方法,可以更新数据库中指定的数据。返回 int 类型的结果表示更新的数据条数。其中参数 table 同样为要更新的数据表名;参数 values 指定要更新的字段数据;参数 whereClause 可以指定更新条件;参数 whereArgs 对应指定更新条件中的参数值。这里如果参数三和参数四均为null,则会更新数据表中所有数据条目。

调用该对象的query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)系列方法,可以查询数据库中的指定数据。返回android.database.Cursor类型的游标对象,可以暂存多条结果。其中参数 table 为要查询的数据表名;参数 columns 为返回的结果中所包含的字段,如果为null则返回所有字段;参数 selection 为查询条件,同样符合sql语句,但变量参数用?代替;参数 selectionArgs 对应于查询条件中变量参数的值所组成的数组;参数 groupBy 与sql语句中的 GROUP BY 一致,可以指定返回的数据中以某个字段为分组依据,如果为null则不会分组;参数 having 同样与sql语句中的 HAVING 一致,指定返回的数据中是否包含某个字段,如果为null则包含所有数据;参数 orderBy 同样与sql语句中的 ORDER BY 一致,可以指定根据某个字段排序,如果为null则不会排序;参数 limit 与sql语句中的 LIMIT 一致,可以分页查找。

对于query()方法返回的Cursor类型,可以使用isX()系列方法判断当前状态X,使用moveX()系列方法将当前游标移动到某条数据对应位置,使用getX()系列方法获取游标当前位置对应条目数据的各字段及对应值。在使用完游标结果之后,一定要使用close()方法关闭当前游标,否则在下次查询数据时将依然返回当前的游标结果。

以上四种增删改查对应的操作方法,都可以使用原生的sql语句实现,所以可以直接调用SQLiteDatabase对象的execSQL (String sql)方法,传入一条已经定义好的sql语句即可。该方法在上文创建数据库时已有使用示例,可支持大多数sql语句。

在数据库中有事务的概念,也就是将多个增删改查操作线性执行看成一个整体的操作。同样在Android中,通过调用SQLiteDatabase对象的begainTransaction()方法可以启动一次事务,在所有事务操作执行结束后,再调用setTransactionSuccessful()方法标志当前事务操作以完成,如果不调用该方法,当前事务即便被提交也不会执行。最终再调用endTransaction()方法以结束当前事务,并判断在调用上述setTransactionsuccessful()标志方法条件下提交并执行当前事务。

释放数据库资源

在对数据库的所有操作结束之后,一般是在使用SQLiteDbHelper对象所在的组件生命周期结束之前,要调用SQLiteDbHelper对象的close()方法,以释放应用程序对数据库的资源占有。

借助更便捷的Room框架

为了在开发中更聚焦于业务代码逻辑,而简化数据库的开关流程,像Room这种开发级框架也就应运而生了。Room框架是有官方提供的推荐框架,除此之外,还有其他开发者或组织提供的优秀框架,包括但不限于GreenDao、LitePal、OrmLite等。由于开发级框架使用便捷,虽性能各有优劣,但使用大同小异,这里不再赘述。


简单开发中对数据库的使用只集中在增删改查的简单操作中,尤其是查询数据往往取出结果后会做进一步的过滤处理,如果能在查询操作时巧妙的借助 GROUP BY 这种子语句,其效率定能更快一步,这里多是开发人员容易忽略的一点。总之合理使用数据库,对大量相同结构数据的存储是很高效的,同时如果想进一步提高数据库性能,建议多学习下sql语句相关内容。

Android系统编程入门系列之应用内数据保存数据库的更多相关文章

  1. Android系统编程入门系列之应用内键值对数据的简单保存

    在应用程序间及与用户的通信交互过程中,会产生并传递一系列数据.针对这些数据,有部分是只在应用程序中使用的缓存数据,还有一部分是在不同位置多次或长时间使用的持久化数据. 对于缓存数据来说,通常以代码中定 ...

  2. Android系统编程入门系列之加载界面Activity

    上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...

  3. Android系统编程入门系列之应用环境及开发环境介绍

        作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...

  4. Android系统编程入门系列之界面Activity绘制展示

    上篇文章介绍了界面Activity的启动方式和生命周期,本篇将继续介绍在界面Activity中的内容是如何绘制展示给用户的. 在Android系统上运行新创建的界面Activtiy,给用户展示的是空白 ...

  5. Android系统编程入门系列之界面Activity交互响应

    在上篇文章中已经了解到界面Activity的绘制完全依赖其加载的视图组件View,不仅如此,用户的每次触摸操作都可以在界面Activity内接收并响应,也可以直接传递给其中的某个视图View响应.本文 ...

  6. Android系统编程入门系列之界面Activity响应丝滑的传统动画

    上篇文章介绍了应用程序内对用户操作响应的相关方法位置,简单的响应逻辑可以是从一个界面Activity跳转到另一个界面Activity,也可以是某些视图View的相对变化.然而不管是启动一个界面执行新界 ...

  7. Android系统编程入门系列之界面Activity响应多元的属性动画

    在响应丝滑动画一篇文章中,分别介绍了作用于普通视图.绘制视图的绘制对象.和界面这三种对象的动画效果,但是都有一些使用的局限性.比如这些动画都只是以屏幕上绘制更新的方式绘制动画,并没有真实改变作用对象的 ...

  8. Android系统编程入门系列之加载服务Service

    之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始 ...

  9. Android系统编程入门系列之服务Service齐头并进多线程任务

    在上篇文章中初步了解了Android系统的四大组件之一的服务Service,在服务内可以执行无用户交互的耗时操作任务,但是包括之前关于界面系列文章在内,生命周期方法都是在主线程内被系统回调的.如果直接 ...

随机推荐

  1. SAS 常用字符串函数

    原文链接:https://www.cnblogs.com/snoopy1866/p/15085466.html CAT(item-1 <, -, item-n>) : 在保留首尾空格的情况 ...

  2. Centos8 Nginx 开机自启配

    第一步:创建 service文件 vim /lib/systemd/system/nginx.service /lib 与 /usr/lib 我这里配置时是一样的,在那个文件夹配置都可以 第二步:编写 ...

  3. 2019-07-06 sql 连续出现次数

    由手机通讯记录界面想到的问题 SELECT CASE WHEN AA.num=1 THEN AA.Tel ELSE AA.Tel+'('+CASt(AA.num AS VARCHAR(4))+')' ...

  4. Mol Cell丨吕志民团队揭示琥珀酰化介导的肿瘤细胞氧化应激调控新机制

    蛋白质琥珀酰化修饰 (succinylation) ,作为赖氨酸酰化修饰家族的重要一员,于2011年由芝加哥大学赵英明教授团队在Nature Chemical Biology 发文被首次报道,并被评为 ...

  5. TCP 才不傻!

    大家好,我是小林. 之前收到个读者的问题,对于 TCP 三次握手和四次挥手的一些疑问: 第一次握手,如果客户端发送的SYN一直都传不到被服务器,那么客户端是一直重发SYN到永久吗?客户端停止重发SYN ...

  6. RationalRose使用

    UML 概述 什么是 UML? Unified Modeling Language (UML)又称统一建模语言或标准建 模语言,是始于 1997 年一个 OMG 标准,它是一个支持模型化 和软件系统开 ...

  7. 【笔记】偏差方差权衡 Bias Variance Trade off

    偏差方差权衡 Bias Variance Trade off 什么叫偏差,什么叫方差 根据下图来说 偏差可以看作为左下角的图片,意思就是目标为红点,但是没有一个命中,所有的点都偏离了 方差可以看作为右 ...

  8. Sqli-Labs less46-53

    less-46 前置基础知识: select * from users order by 1 desc ;使用降序(倒序)排列 select * from users order by 1 asc ; ...

  9. 常见的六种容错机制:Fail-Over、Fail-Fast、Fail-Back、Fail-Safe,Forking 和 Broadcast

    目录 1.Fail-Over:故障转移 2.Fail-Fast:快速失败 3.Fail-Back:失效自动恢复 4.Fail-Safe:失效安全 5.Forking:并行调用多个服务 6.Broadc ...

  10. 阿里云rds分区

    SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'xw_user_appl ...