文章目录

  • 零、学习目标
  • 一、SQLite数据库概述
    • 1、SQLite构成
    • 2、SQLite数据类型
    • 3、SQLite数据库特点
  • 二、SQLite数据库管理工具
    • (一)数据库控制台管理工具 - sqlite3
      • 1、下载sqlite3
      • 2、解压缩到指定目录
      • 3、使用sqlite3操作数据库及表
    • (二)数据库可视化管理工具 - Navicat
      • 1、利用Navicat访问sqlite3数据库及表
      • 2、新建查询,进行查询操作
  • 三、使用SQLiteDatabase类操作数据库
    • (一)运行效果
    • (二)实现步骤
      • 1、创建安卓应用【CreateDeleteDB】
      • 2、将背景图片拷贝到drawable目录
      • 3、主布局资源文件activity_main.xml
      • 4、字符串资源文件strings.xml
      • 5、主界面类 - MainActivity
      • 6、启动应用,查看效果
  • 四、使用SQLiteDatabase类操作数据表
    • (一)运行结果
    • (二)实现步骤
      • 1、创建安卓应用【OperateTable】
      • 2、将背景图片拷贝到drawable目录
      • 3、主布局资源文件activity_main.xml
      • 4、字符串资源文件strings.xml
      • 5、主界面类 - MainActivity
        • (1)编写代码创建或打开数据库
        • (2)编写代码创建表
        • (3)编写代码添加表记录
        • (4)编写代码更新表记录
        • (5)编写代码显示全部表记录
        • (6)编写代码删除全部表记录
        • (7)编写代码删除表
        • (8)编写代码删除数据库
      • 6、查看主界面完整代码
      • 7、SQLiteDatabase小结
        • (1)Activity对象提供操作数据库的方法
        • (2)SQLiteDatabase对象提供了操作数据表的方法
        • (3)SQLiteDatabase还提供了一组对表进行增删改查的方法
  • 五、使用SQLiteDatabaseHelper类操作数据库与表
    • (一)运行效果
    • (二)涉及知识点
      • 1、利用SQLiteOpenHelper类创建与升级数据库
      • 2、游标与列表的绑定
    • (三)实现步骤
      • 1、创建安卓应用【SQLiteContacts】
      • 2、将背景图片拷贝到drawable目录
      • 3、主布局资源文件activity_main.xml
      • 4、创建自定义数据库助手类 - DBHelper
        • (1)构造方法:创建数据库
        • (2)onCreate方法:创建数据表并添加表记录
        • (3)onUpgrade方法:升级数据库时会调用
        • (4)query方法:对外提供表记录查询服务,返回游标对象
        • (5)delete方法:对外提供表记录删除服务,返回删除记录数
        • (6)update方法:对外提供表记录更新服务,返回更新记录数
        • (7)insert方法:对外提供表记录插入服务,返回插入记录数
        • (8)查看数据库助手类完整代码
      • 5、主界面类 - MainActivity
        • (1)声明变量与常量
        • (2)通过资源标识符获取控件实例
        • (3)实例化数据库助手
        • (4)查询全部联系人,返回游标,作为数据源
        • (5)创建简单游标适配器
        • (6)给列表控件设置适配器
        • (7)给列表控件注册监听器
        • (8)启动应用,查看效果
        • (9)给列表控件添加上下文菜单
        • (10)主界面完整源代码
  • 六、课后作业
    • 任务:完成联系人应用中的编辑功能

零、学习目标

  1. 学会利用sqlite3来创建以及操作数据库
  2. 能利用SQLiteDatabase操作数据库与表
  3. 能利用SQLiteOpenHelper操作数据库与表

一、SQLite数据库概述

SQLite是D. Richard Hipp用C语言编写的开源嵌入式数据库引擎。它支持大多数的SQL92标准,并且可以在所有主要的操作系统上运行。

1、SQLite构成

SQLite由SQL编译器、内核、后端以及附件几个部分构成。SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),使得调试、修改和扩展SQLite的内核变得更加方便,所有SQL语句都被编译成易读的、可以在SQLite虚拟机中执行的程序集。SQLite的整体结构图如下:

2、SQLite数据类型

概括来讲,SQLite支持NULL、INTEGER、REAL、TEXT和BLOB数据类型,分别代表空值、整型值、浮点值、字符串文本、二进制对象。

3、SQLite数据库特点

  • 值得一提的是,袖珍型的SQLite竟然可以支持高达2TB大小的数据库,每个数据库都是以单个文件的形式存在,这些数据都是以B-Tree的数据结构形式存储在磁盘上。
  • 在事务处理方面,SQLite通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只有一个可以写入数据。在某个进程或线程想数据库执行写操作之前,必须获得独占锁。在获得独占锁之后,其他的读或写操作将不会再发生。
  • SQLite采用动态数据类型,当某个值插入到数据库时,SQLite将会检查它的类型,如果该类型与关联的列不匹配,SQLite则会尝试将该值转换成该列的类型,如果不能转换,则该值将作为本身的类型存储,SQLite称这为“弱类型”。但有一个特例,如果是INTEGER PRIMARY KEY,则其他类型不会被转换,会报一个“datatype missmatch”的错误。
  • ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。

二、SQLite数据库管理工具

(一)数据库控制台管理工具 - sqlite3

1、下载sqlite3

  • 下载网址:http://www.sqlite.org/download.html

  • 在Pecompiled Binaries for Windows下载 sqlite-tools-win32-x86-3340000.zip (1.76 MiB)

2、解压缩到指定目录

  • 解压缩到D盘根目录

  • 修改一下目录名 - D:\sqlite3

3、使用sqlite3操作数据库及表

  • 创建学生数据库 - student.db
  • 如果数据库存在,那么sqlite3 <数据库名>就是打开数据库,否则就是新建数据库
  • 查看全部数据库
  • 创建学生表 - stu
  • 查看表结构
  • 插入表记录
  • 查看表记录
  • 更新表记录 - 将“李红云”改成“李小云”
  • 删除表记录 - 删除id为2的记录
  • 删除学生表
  • 帮助命令
  • 重新创建学生表并插入记录

(二)数据库可视化管理工具 - Navicat

1、利用Navicat访问sqlite3数据库及表

2、新建查询,进行查询操作

三、使用SQLiteDatabase类操作数据库

(一)运行效果

(二)实现步骤

1、创建安卓应用【CreateDeleteDB】


2、将背景图片拷贝到drawable目录

3、主布局资源文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/background"android:gravity="center"android:orientation="vertical"tools:context=".MainActivity"><Buttonandroid:id="@+id/btnCreateDB"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doCreateDB"android:text="@string/create_db"android:textSize="20dp" /><Buttonandroid:id="@+id/btnDeleteDB"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doDeleteDB"android:text="@string/delete_db"android:textSize="20dp" />
</LinearLayout>

4、字符串资源文件strings.xml

<resources><string name="app_name">创建和删除数据库</string><string name="create_db">创建数据库</string><string name="delete_db">删除数据库</string>
</resources>

5、主界面类 - MainActivity

  • 声明变量和常量

  • 获取应用当前数据库个数

  • 编写代码创建数据库

  • 编写代码删除数据库

  • 查看主界面源代码

package net.hw.create_delete_db;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private static final String DB_NAME_PREFIX = "student"; // 数据库名前缀private static final int MODE = Context.MODE_PRIVATE; // 文件访问模式private int count; // 数据库计数器private SQLiteDatabase db; // SQLite数据库@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 利用布局资源文件设置用户界面setContentView(R.layout.activity_main);// 获取应用当前数据库个数count = databaseList().length;}/*** 创建数据库* 数据库位置:data/data/net.hw.create_delete_db/databases** @param view*/public void doCreateDB(View view) {// 数据库计数器累加count++;// 定义数据库名String dbname = DB_NAME_PREFIX + count + ".db";try {// 打开或创建数据库db = openOrCreateDatabase(dbname, MODE, null);// 提示用户创建成功Toast.makeText(this, "恭喜,数据库【" + dbname + "】创建成功!", Toast.LENGTH_SHORT).show();} catch (Exception e) {// 提示用户创建失败Toast.makeText(this, "遗憾,数据库【" + dbname + "】创建失败!", Toast.LENGTH_SHORT).show();}}/*** 删除数据库(删除全部数据库)** @param view*/public void doDeleteDB(View view) {// 获取数据库名数组String[] dbnames = databaseList();// 判断是否有数据库可删除if (dbnames.length > 0) {// 遍历数组,删除对应的数据库for (int i = 0; i < dbnames.length; i++) {// 按照名称删除数据库deleteDatabase(dbnames[i]);}// 数据库计数器清零count = 0;// 提示用户删除成功Toast.makeText(this, "恭喜,数据库全部被删除!", Toast.LENGTH_SHORT).show();} else {// 提示用户没有数据库可删除Toast.makeText(this, "遗憾,没有数据库可删除!", Toast.LENGTH_SHORT).show();}}
}

6、启动应用,查看效果

  • 创建5个数据库,然后全部删除,最后又创建了三个数据库
  • 打开DDMS的File Explorer

  • 利用adb shell对相应的目录授权
  • 查看刚才创建的数据库

四、使用SQLiteDatabase类操作数据表

上一个案例,我们利用openOrCreateDatabase()方法创建或打开数据库,利用deleteDatabase()方法删除数据库。这两个方法是谁的方法?就是当前窗口提供的方法。另外还有一个方法:databaseList(),返回应用所有数据库名称构成的数组。下面,我们继续讲解如何在数据库里创建表和删除表,以及对表记录进行增、删、改、查操作。

(一)运行结果

(二)实现步骤

1、创建安卓应用【OperateTable】


2、将背景图片拷贝到drawable目录

3、主布局资源文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/background"android:gravity="center"android:orientation="vertical"android:padding="10dp" ><Buttonandroid:id="@+id/btnCreateOrOpenDB"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doCreateOrOpenDB"android:text="@string/create_or_open_db" /><Buttonandroid:id="@+id/btnCreateTable"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doCreateTable"android:text="@string/create_table" /><Buttonandroid:id="@+id/btnAddRecord"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doAddRecord"android:text="@string/add_record" /><Buttonandroid:id="@+id/btnUpdateRecord"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doUpdateRecord"android:text="@string/update_record" /><Buttonandroid:id="@+id/btnDisplayAllRecords"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doDisplayAllRecords"android:text="@string/display_all_records" /><Buttonandroid:id="@+id/btnDeleteAllRecords"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doDeleteAllRecords"android:text="@string/delete_all_records" /><Buttonandroid:id="@+id/btnDeleteTable"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doDeleteTable"android:text="@string/delete_table" /><Buttonandroid:id="@+id/btnDeleteDB"android:layout_width="200dp"android:layout_height="wrap_content"android:onClick="doDeleteDB"android:text="@string/delete_db" />
</LinearLayout>

4、字符串资源文件strings.xml

<resources><string name="app_name">利用SQLiteDatabase操作数据表</string><string name="create_or_open_db">创建或打开数据库</string><string name="create_table">创建表</string><string name="add_record">添加表记录</string><string name="update_record">更新表记录</string><string name="display_all_records">显示全部表记录</string><string name="delete_all_records">删除全部表记录</string><string name="delete_table">删除表</string><string name="delete_db">删除数据库</string>
</resources>

5、主界面类 - MainActivity

  • 声明常量与变量

(1)编写代码创建或打开数据库

  • 启动应用,查看效果

(2)编写代码创建表

  • 启动应用,查看效果

(3)编写代码添加表记录

  • 启动应用,查看效果

(4)编写代码更新表记录

  • 修改第一条记录,名字改为“张晓芸”,性别改为“女” 三个层面的判断:数据库–>表–>记录

  • 启动应用,查看效果

(5)编写代码显示全部表记录

  • 启动应用,查看效果

(6)编写代码删除全部表记录

  • 启动应用,查看效果

(7)编写代码删除表

  • 启动应用,查看效果

(8)编写代码删除数据库

  • 启动应用,查看效果

6、查看主界面完整代码

package net.hw.operate_table;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private final String DB_NAME = "student.db"; // 数据库名private final String TABLE_NAME = "student"; // 表名private final int MODE = Context.MODE_PRIVATE; // 访问模式private SQLiteDatabase db; // SQLite数据库private int id; // 学号@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}/*** 创建或打开数据库** @param view*/public void doCreateOrOpenDB(View view) {// 判断数据库是否存在if (databaseList().length == 0) {// 创建数据库db = openOrCreateDatabase(DB_NAME, MODE, null);// 提示用户数据库创建成功Toast.makeText(this, "恭喜,数据库【" + DB_NAME + "】创建成功!", Toast.LENGTH_LONG).show();} else {// 打开数据库db = openOrCreateDatabase(DB_NAME, MODE, null);// 提示用户数据库打开成功Toast.makeText(this, "恭喜,数据库【" + DB_NAME + "】打开成功!", Toast.LENGTH_LONG).show();}}/*** 创建表** @param view*/public void doCreateTable(View view) {// 判断数据库对象是否为空if (db == null) {// 判断数据库是否存在if (databaseList().length == 0) {Toast.makeText(this, "请创建数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();} else {Toast.makeText(this, "请打开数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();}} else {// 判断表是否存在if (isTableExisted(TABLE_NAME)) {// 弹出吐司提示用户表已存在Toast.makeText(this, "表【" + TABLE_NAME + "】已经存在!", Toast.LENGTH_LONG).show();} else {try {// 定义SQL字符串String strSQL = "CREATE TABLE " + TABLE_NAME + "(id integer, name text, gender text)";// 执行SQL语句db.execSQL(strSQL);// 提示用户创建表成功Toast.makeText(this, "创建表成功!", Toast.LENGTH_LONG).show();} catch (SQLException e) {// 提示用户创建表失败Toast.makeText(this, "创建表失败!", Toast.LENGTH_LONG).show();}}}}/*** 判断表是否存在** @param tableName* @return true 表存在;false 表不存在*/private boolean isTableExisted(String tableName) {// 定义SQL字符串String strSQL = "SELECT * FROM sqlite_master WHERE type = ? AND name = ?";// 执行SQL查询,返回游标Cursor cursor = db.rawQuery(strSQL, new String[]{"table", tableName});// 判断游标里是否有记录if (cursor.getCount() > 0) {return true;} else {return false;}}/*** 添加表记录** @param view*/public void doAddRecord(View view) {// 判断数据库对象是否为空if (db == null) {// 判断数据库是否存在if (databaseList().length == 0) {Toast.makeText(this, "请创建数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();} else {Toast.makeText(this, "请打开数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();}} else {// 判断表是否存在if (isTableExisted(TABLE_NAME)) {// 获取新记录的学号id = getNewId(TABLE_NAME);// 创建内容值对象ContentValues values = new ContentValues();// 以键值对方式添加字段数据values.put("id", id);values.put("name", "学生" + id);values.put("gender", id % 2 == 1 ? "男" : "女");// 将数据插入表中long count = db.insert(TABLE_NAME, null, values);if (count != -1) {// 弹出吐司提示用户添加成功Toast.makeText(this, "恭喜,表记录添加成功!", Toast.LENGTH_LONG).show();} else {// 弹出吐司提示用户添加失败Toast.makeText(this, "恭喜,表记录添加失败!", Toast.LENGTH_LONG).show();}} else {// 提示用户先创建表Toast.makeText(this, "表【" + TABLE_NAME + "】不存在,请先创建!", Toast.LENGTH_LONG).show();}}}/*** 获取新记录的学号** @param tableName* @return*/private int getNewId(String tableName) {// 判断表是否存在if (isTableExisted(tableName)) {// 查询全部表记录,返回游标Cursor cursor = db.query(tableName, null, null, null, null, null, null);// 移到最后一条记录if (cursor.moveToLast()) {// 获取最后一条记录的idint id = cursor.getInt(0);// 返回新记录的idreturn id + 1;}}return 1;}/*** 更新表记录** @param view*/public void doUpdateRecord(View view) {// 判断数据库对象是否为空if (db == null) {// 判断数据库是否存在if (databaseList().length == 0) {Toast.makeText(this, "请创建数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();} else {Toast.makeText(this, "请打开数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();}} else {// 判断表是否存在if (isTableExisted(TABLE_NAME)) {// 判断是否有表记录if (getRecordCount(TABLE_NAME) > 0) {// 定义SQL字符串String strSQL = "UPDATE " + TABLE_NAME + " SET name = ?, gender = ? WHERE id = ?";try {// 执行SQL,返回更新表记录数db.execSQL(strSQL, new Object[]{"张晓芸", "女", 1});// 提示用户更新记录成功Toast.makeText(this, "恭喜,表记录更新成功!", Toast.LENGTH_LONG).show();} catch (SQLException e) {// 提示用户更新记录失败Toast.makeText(this, "遗憾,表记录更新失败!", Toast.LENGTH_LONG).show();}} else {// 弹出吐司提示用户没有表记录Toast.makeText(this, "没有表记录可更新,请先添加表记录!", Toast.LENGTH_LONG).show();}} else {// 提示用户先创建表Toast.makeText(this, "表【" + TABLE_NAME + "】不存在,请先创建!", Toast.LENGTH_LONG).show();}}}/*** 返回表记录数** @param tableName* @return 表记录数*/private int getRecordCount(String tableName) {// 定义SQL字符串String strSQL = "SELECT * FROM " + tableName;// 执行SQL,返回游标Cursor cursor = db.rawQuery(strSQL, null);// 返回记录数return cursor.getCount();}/*** 显示全部表记录** @param view*/public void doDisplayAllRecords(View view) {// 判断数据库对象是否为空if (db == null) {// 判断数据库是否存在if (databaseList().length == 0) {Toast.makeText(this, "请创建数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();} else {Toast.makeText(this, "请打开数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();}} else {// 判断表是否存在if (isTableExisted(TABLE_NAME)) {// 判断表里是否有记录if (getRecordCount(TABLE_NAME) > 0) {// 定义SQL字符串String strSQL = "SELECT * FROM " + TABLE_NAME;// 执行SQL,返回游标Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null);// 定义字符串生成器StringBuilder builder = new StringBuilder();// 遍历游标对象(记录集)while (cursor.moveToNext()) {// 将每条记录信息组合之后添加到字符串生成器builder.append(cursor.getInt(0) + " " + cursor.getString(1) + " " + cursor.getString(2) + "\n");}// 弹出吐司显示全部学生记录Toast.makeText(this, "全部表记录\n\n" + builder.toString(), Toast.LENGTH_LONG).show();} else {// 弹出吐司提示用户没有表记录Toast.makeText(this, "没有表记录可显示,请先添加表记录!", Toast.LENGTH_LONG).show();}} else {// 提示用户先创建表Toast.makeText(this, "表【" + TABLE_NAME + "】不存在,请先创建!", Toast.LENGTH_LONG).show();}}}/*** 删除全部表记录(三个层面的判断)** @param view*/public void doDeleteAllRecords(View view) {// 判断数据库对象是否为空if (db == null) {// 判断数据库是否存在if (databaseList().length == 0) {Toast.makeText(this, "请创建数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();} else {Toast.makeText(this, "请打开数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();}} else {// 判断表是否存在if (isTableExisted(TABLE_NAME)) {// 判断是否有表记录if (getRecordCount(TABLE_NAME) > 0) {// 定义SQL字符串String strSQL = "DELETE FROM " + TABLE_NAME;try {// 执行SQL,删除表记录db.execSQL(strSQL);// 提示用户删除表记录成功Toast.makeText(this, "全部表记录已删除!", Toast.LENGTH_LONG).show();} catch (SQLException e) {// 提示用户删除表记录失败Toast.makeText(this, "删除表记录失败!", Toast.LENGTH_LONG).show();}} else {// 弹出吐司提示用户没有表记录Toast.makeText(this, "没有表记录可删除,请先添加表记录!", Toast.LENGTH_LONG).show();}} else {// 提示用户先创建表Toast.makeText(this, "表【" + TABLE_NAME + "】不存在,请先创建!", Toast.LENGTH_LONG).show();}}}/*** 删除表** @param view*/public void doDeleteTable(View view) {// 判断数据库对象是否为空if (db == null) {// 判断数据库是否存在if (databaseList().length == 0) {Toast.makeText(this, "请创建数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();} else {Toast.makeText(this, "请打开数据库【" + DB_NAME + "】。", Toast.LENGTH_LONG).show();}} else {// 判断表是否存在if (isTableExisted(TABLE_NAME)) {// 定义SQL字符串String strSQL = "DROP TABLE " + TABLE_NAME;try {// 执行SQL,删除表db.execSQL(strSQL);// 提示用户表删除成功Toast.makeText(this, "表删除成功!", Toast.LENGTH_LONG).show();} catch (SQLException e) {// 提示用户表删除失败Toast.makeText(this, "表删除失败!", Toast.LENGTH_LONG).show();}} else {// 提示用户先创建表Toast.makeText(this, "表【" + TABLE_NAME + "】不存在,请先创建!", Toast.LENGTH_LONG).show();}}}/*** 删除数据库** @param view*/public void doDeleteDB(View view) {// 判断数据库是否存在if (databaseList().length == 0) {// 提示用户没有数据库Toast.makeText(this, "没有数据库可删除!", Toast.LENGTH_LONG).show();} else {// 判断数据库删除是否成功if (deleteDatabase(DB_NAME)) {// 提示用户删除成功Toast.makeText(this, "数据库【" + DB_NAME + "】删除成功!", Toast.LENGTH_LONG).show();} else {// 提示用户删除失败Toast.makeText(this, "数据库【" + DB_NAME + "】删除失败!", Toast.LENGTH_LONG).show();}}}
}

7、SQLiteDatabase小结

(1)Activity对象提供操作数据库的方法

  • databaseList()
  • openOrCreateDatabase()
  • deleteDatabase()

(2)SQLiteDatabase对象提供了操作数据表的方法

  • executeSQL(),需要传入一个操作数据标的字符串参数。
  • rawQuery()方法要返回一个Cursor对象,有点类似于JDBC里的结果集(ResultSet)。
  • Cusor对象提供了一些移动记录指针的方法:moveToFirst()、moveToLast、moveToNext()、moveToPrevious()、move()、moveToPosition()。
  • 如果我们要遍历游标集,那么我们会利用while循环与moveToNext()方法来处理。

(3)SQLiteDatabase还提供了一组对表进行增删改查的方法

  • insert():db.insert(TABLE_NAME, null, values);
  • delete():db.delete(TABLE_NAME, null, null);
  • update():db.update(TABLE_NAME, values, “id = ?”, new String[] { “1” });
  • query():cursor = db.query(TABLE_NAME, null, null, null, null, null, null);

五、使用SQLiteDatabaseHelper类操作数据库与表

(一)运行效果

(二)涉及知识点

1、利用SQLiteOpenHelper类创建与升级数据库

这个类是一个抽象类,必须继承该类创建一个子类,实现里面的两个抽象方法:
(1)public void onCreate(SQLiteDatabase db);
(2)public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);

这两个方法什么时候会调用呢?

  • 如果数据库不存在,那么就会调用onCreate方法来创建数据库、表以及视图。
  • 如果数据库存在但是没有升级,那么两个方法都不会被调用,什么事情也不做。
  • 如果数据库存在并且进行了升级,那么就会调用onUpgrade方法来完成升级服务。

2、游标与列表的绑定

数据表查询的结果放在游标集里,作为数据源,如何把数据源和展示控件(ListView)绑定到一起呢?这就需要一个适配器——SimpleCursorAdapter(简单游标适配器)。利用游标适配器,可以将游标里的数据呈现到列表控件。

(三)实现步骤

1、创建安卓应用【SQLiteContacts】


2、将背景图片拷贝到drawable目录

3、主布局资源文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/background"android:orientation="vertical"android:padding="15dp"tools:context=".MainActivity"><ListViewandroid:id="@+id/lvContact"android:layout_width="match_parent"android:layout_height="wrap_content">        </ListView>
</LinearLayout>

4、创建自定义数据库助手类 - DBHelper

  • 继承SQLiteOpenHelper类
  • 声明变量与常量

(1)构造方法:创建数据库

(2)onCreate方法:创建数据表并添加表记录

  • 创建数据表
  • 添加表记录

(3)onUpgrade方法:升级数据库时会调用

  • onUpgrade方法会在数据库需要升级的时候调用。可以用来增删表或者其他任何操作。如果你想添加新的列你可以使用ALTER TABLE 插入表中。如果需要重命名或者删掉列,可以使用ALTER TABLE 重命名旧表,然后创建新的表,并将旧表数据添加到新表中。如果抛出异常,将自动回滚。
  1. 帮助文档里说的“数据库升级”是指什么?
    你开发了一个程序,当前是1.0版本。该程序用到了数据库。到1.1版本时,你在数据库的某个表中增加了一个字段。那么软件1.0版本用的数据库在软件1.1版本就要被升级了。
  2. 数据库升级应该注意什么?
    软件的1.0版本升级到1.1版本时,老的数据不能丢。那么在1.1版本的程序中就要有地方能够检测出来新的软件版本与老的数据库不兼容,并且能够有办法把1.0软件的数据库升级到1.1软件能够使用的数据库。换句话说,要在1.0软件的数据库的那个表中增加那个字段,并赋予这个字段默认值。
  3. 程序如何知道数据库需要升级?
    SQLiteOpenHelper类的构造函数有一个参数是int version,它的意思就是指数据库版本号。比如在软件1.0版本中,我们使用SQLiteOpenHelper访问数据库时,该参数为1,那么数据库版本号1就会写在我们的数据库中。
    到了1.1版本,我们的数据库需要发生变化,那么我们1.1版本的程序中就要使用一个大于1的整数来构造SQLiteOpenHelper类,用于访问新的数据库,比如2。
    当我们的1.1新程序读取1.0版本的老数据库时,就发现老数据库里存储的数据库版本是1,而我们新程序访问它时填的版本号为2,系统就知道数据库需要升级。
  4. 何时触发数据库升级?如何升级?
    当系统在构造SQLiteOpenHelper类的对象时,如果发现版本号不一样,就会自动调用onUpgrade函数,让你在这里对数据库进行升级。根据上述场景,在这个函数中把老版本数据库的相应表中增加字段,并给每条记录增加默认值即可。新版本号和老版本号都会作为onUpgrade函数的参数传进来,便于开发者知道数据库应该从哪个版本升级到哪个版本。升级完成后,数据库会自动存储最新的版本号为当前数据库版本号。

(4)query方法:对外提供表记录查询服务,返回游标对象

(5)delete方法:对外提供表记录删除服务,返回删除记录数

(6)update方法:对外提供表记录更新服务,返回更新记录数

(7)insert方法:对外提供表记录插入服务,返回插入记录数

(8)查看数据库助手类完整代码

package net.hw.sqlite_contacts;import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;/*** 功能:数据库助手类* 作者:华卫* 日期:2020年12年15日*/
public class DBHelper extends SQLiteOpenHelper {private Context context; // 上下文环境private static final String DB_NAME = "contact.db"; // 数据库名private static final int DB_VERSION = 1; // 数据库版本号private static final String TABLE_NAME = "contact"; // 表名/*** 构造方法(上下文、数据库名、游标工厂、数据库版本号)* @param context*/public DBHelper(Context context) {super(context, DB_NAME, null, DB_VERSION);}/*** 创建回调方法,只有当数据库不存在时才会被调用* @param db*/@Overridepublic void onCreate(SQLiteDatabase db) {// 创建数据表createTable(db, TABLE_NAME);// 添加表记录addRecords(db, TABLE_NAME);}/*** 创建数据表** @param db* @param tableName*/private void createTable(SQLiteDatabase db, String tableName) {// 定义SQL字符串String strSQL = "create table " + tableName + "(_id text, name text, gender text, age integer, telephone text)";try {// 执行SQL,创建数据表db.execSQL(strSQL);} catch (SQLException e) {Toast.makeText(context, "遗憾,建表失败!", Toast.LENGTH_SHORT).show();}}/*** 添加表记录** @param db* @param tableName*/private void addRecords(SQLiteDatabase db, String tableName) {// 创建内容值对象ContentValues values = new ContentValues();// 将第1条记录信息放入内容值对象values.put("_id", "2020001");values.put("name", "李小文");values.put("gender", "男");values.put("age", 19);values.put("telephone", "15878786780");// 利用数据库对象的插入方法,插入第1条记录db.insert(tableName, null, values);// 将第2条记录信息放入内容值对象values.put("_id", "2020002");values.put("name", "韩玉玲");values.put("gender", "女");values.put("age", 20);values.put("telephone", "15845678907");// 利用数据库对象的插入方法,插入第2条记录db.insert(tableName, null, values);// 将第3条记录信息放入内容值对象values.put("_id", "2020003");values.put("name", "唐语涵");values.put("gender", "女");values.put("age", 18);values.put("telephone", "13978789089");// 利用数据库对象的插入方法,插入第3条记录db.insert(tableName, null, values);// 将第4条记录信息放入内容值对象values.put("_id", "2020004");values.put("name", "董翔宇");values.put("gender", "男");values.put("age", 20);values.put("telephone", "15823234567");// 利用数据库对象的插入方法,插入第4条记录db.insert(tableName, null, values);// 将第5条记录信息放入内容值对象values.put("_id", "2020005");values.put("name", "郑文佳");values.put("gender", "女");values.put("age", 18);values.put("telephone", "13978781234");// 利用数据库对象的插入方法,插入第5条记录db.insert(tableName, null, values);// 将第6条记录信息放入内容值对象values.put("_id", "2020006");values.put("name", "伍子胥");values.put("gender", "男");values.put("age", 20);values.put("telephone", "15878786780");// 利用数据库对象的插入方法,插入第6条记录db.insert(tableName, null, values);// 将第7条记录信息放入内容值对象values.put("_id", "2020007");values.put("name", "南怀瑾");values.put("gender", "男");values.put("age", 18);values.put("telephone", "13956567862");// 利用数据库对象的插入方法,插入第7条记录db.insert(tableName, null, values);// 将第8条记录信息放入内容值对象values.put("_id", "2020008");values.put("name", "李文华");values.put("gender", "女");values.put("age", 18);values.put("telephone", "15956567845");// 利用数据库对象的插入方法,插入第8条记录db.insert(tableName, null, values);// 将第9条记录信息放入内容值对象values.put("_id", "2020009");values.put("name", "吴文渊");values.put("gender", "男");values.put("age", 20);values.put("telephone", "13978784560");// 利用数据库对象的插入方法,插入第8条记录db.insert(tableName, null, values);// 将第10条记录信息放入内容值对象values.put("_id", "2020010");values.put("name", "陈燕文");values.put("gender", "女");values.put("age", 18);values.put("telephone", "15890903456");// 利用数据库对象的插入方法,插入第10条记录db.insert(tableName, null, values);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 暂时不升级,不需要写代码}/*** 查询方法** @param tableName* @param columns* @param selection* @param selectionArgs* @return 游标对象*/public Cursor query(String tableName, String[] columns, String selection, String[] selectionArgs) {// 获取只读数据库SQLiteDatabase db = getReadableDatabase();// 执行数据库查询方法,返回游标对象return db.query(tableName, columns, selection, selectionArgs, null, null, null, null);}/*** 删除方法** @param tableName* @param whereClause* @param whereArgs* @return 删除记录数*/public int delete(String tableName, String whereClause, String[] whereArgs) {// 获取可写数据库SQLiteDatabase db = getWritableDatabase();// 执行数据库删除方法,返回删除记录数return db.delete(tableName, whereClause, whereArgs);}/*** 更新方法** @param tableName* @param values* @param whereClause* @param whereArgs* @return 更新记录数*/public int update(String tableName, ContentValues values, String whereClause, String[] whereArgs) {// 获取可写数据库SQLiteDatabase db = getWritableDatabase();// 执行数据库更新方法,返回更新记录数return db.update(tableName, values, whereClause, whereArgs);}/*** 插入方法** @param tableName* @param values* @return 插入记录数*/public long insert(String tableName, ContentValues values) {// 获取可写数据库SQLiteDatabase db = getWritableDatabase();// 执行数据库插入方法,返回插入记录数return db.insert(tableName, null, values);}
}

5、主界面类 - MainActivity

(1)声明变量与常量

(2)通过资源标识符获取控件实例

(3)实例化数据库助手

(4)查询全部联系人,返回游标,作为数据源

(5)创建简单游标适配器

(6)给列表控件设置适配器

(7)给列表控件注册监听器

(8)启动应用,查看效果

(9)给列表控件添加上下文菜单

  • 给列表控件注册上下文菜单
  • 创建上下文菜单
  • 对上下文菜单进行事件处理
  • 启动应用,查看效果

(10)主界面完整源代码

package net.hw.sqlite_contacts;import android.content.DialogInterface;
import android.database.Cursor;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private static final int EDIT_MENU_ITEM = 1; // 编辑菜单项private static final int DELETE_MENU_ITEM = 2; // 删除菜单项private ListView lvContact; // 联系人列表控件private SimpleCursorAdapter adapter; // 简单游标适配器private Cursor cursor; // 游标(数据源)private DBHelper dbHelper; // 数据库助手private int position; // 当前列表项位置@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 利用布局资源文件设置用户界面setContentView(R.layout.activity_main);// 通过资源标识符获取控件实例lvContact = findViewById(R.id.lvContact);// 实例化数据库助手dbHelper = new DBHelper(this);// 查询全部联系人,返回游标,作为数据源cursor = dbHelper.query("contact", null, null, null);// 创建简单游标适配器adapter = new SimpleCursorAdapter(this, // 参数1:上下文android.R.layout.simple_expandable_list_item_2, // 参数2:列表项模板cursor, // 参数3:游标(数据源)new String[]{"name", "telephone"}, // 参数4:字段列表new int[]{android.R.id.text1, android.R.id.text2}, // 参数5:控件标识列表SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER // 参数6:简单游标适配标识);// 给列表控件设置适配器lvContact.setAdapter(adapter);// 给列表控件注册监听器lvContact.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {// 将游标指针定位到选定记录cursor.moveToPosition(position);// 获取游标当前记录各个字段值String _id = cursor.getString(cursor.getColumnIndex("_id"));String name = cursor.getString(cursor.getColumnIndex("name"));String gender = cursor.getString(cursor.getColumnIndex("gender"));int age = cursor.getInt(cursor.getColumnIndex("age"));String telephone = cursor.getString(cursor.getColumnIndex("telephone"));// 创建字符串生成器StringBuilder builder = new StringBuilder();// 将各个字段值添加到字符串生成器中builder.append("联系人详细信息\n\n").append("编号:" + _id + "\n").append("姓名:" + name + "\n").append("性别:" + gender + "\n").append("年龄:" + age + "\n").append("电话:" + telephone + "\n");// 生成当前联系人记录信息String contactInfo = builder.toString();// 通过吐司显示当前联系人详情Toast.makeText(MainActivity.this, contactInfo, Toast.LENGTH_SHORT).show();}});// 给列表控件注册上下文菜单registerForContextMenu(lvContact);}/*** 创建上下文菜单** @param menu* @param v* @param menuInfo*/@Overridepublic void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {super.onCreateContextMenu(menu, v, menuInfo);// 获取适配器上下文菜单信息AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo) menuInfo;// 通过适配器上下文菜单获取当前位置position = acmi.position;// 将游标指针移到用户指定位置cursor.moveToPosition(position);// 获取当前联系人姓名String name = cursor.getString(cursor.getColumnIndex("name"));// 创建上下文菜单项menu.add(1, EDIT_MENU_ITEM, 1, "编辑【" + name + "】记录");menu.add(1, DELETE_MENU_ITEM, 2, "删除【" + name + "】记录");// 设置上下文菜单标题行menu.setHeaderTitle("表记录操作");}/*** 上下文菜单项选择事件处理** @param item* @return*/@Overridepublic boolean onContextItemSelected(@NonNull MenuItem item) {// 判断用户选择了哪个菜单项switch (item.getItemId()) {case EDIT_MENU_ITEM:// 课后作业Toast.makeText(this, "此功能尚待完成!", Toast.LENGTH_SHORT).show();break;case DELETE_MENU_ITEM:// 创建警告对话框生成器AlertDialog.Builder builder = new AlertDialog.Builder(this);// 设置、创建并显示警告对话框builder.setIcon(R.mipmap.ic_launcher) // 设置图标.setTitle("删除表记录") // 设置标题.setMessage("您真要删除当前记录吗?") // 设置消息正文.setPositiveButton("是", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// 将游标指针移到当前选定位置cursor.moveToPosition(position);// 获取当前联系人的编号String _id = cursor.getString(cursor.getColumnIndex("_id"));// 按编号删除联系人int count = dbHelper.delete("contact", "_id = ?", new String[] {_id});// 判断是否删除成功if (count > 0) {// 提示用户删除成功Toast.makeText(MainActivity.this, "恭喜,记录删除成功!", Toast.LENGTH_SHORT).show();// 刷新列表控件,显示删除之后的联系人记录cursor.requery();// 通知列表控件数据源已发生变化lvContact.deferNotifyDataSetChanged();} else {// 提示用户删除失败Toast.makeText(MainActivity.this, "遗憾,记录删除失败!", Toast.LENGTH_SHORT).show();}}}) // 设置肯定按钮.setNegativeButton("否", null) // 设置否定按钮.create() // 创建警告对话框.show(); // 显示警告对话框break;}return true;}
}

六、课后作业

任务:完成联系人应用中的编辑功能

安卓学习笔记29:使用SQLite数据库相关推荐

  1. 2020年安卓学习笔记目录

    文章目录 一.讲课笔记 二.安卓案例 三.安卓实训项目 四.学生安卓学习博客 五.安卓课后作业 (一)界面设计练习 1.制作登录界面 2.制作部队管理界面 3.制作灭火救援界面 4.制作交付界面 5. ...

  2. oracle强制拉库跳过recovery,学习笔记:Oracle坏块 数据库recover恢复时遇到坏块的解决思路案例...

    天萃荷净 recover遇到坏块处理本质探讨,记录一次在Oracle数据库recover恢复过程中,遇到数据库坏块无法恢复的解决思路案例 如果在还原出来的数据文件中有坏块,而归档日志和联机日志是正常的 ...

  3. 安卓学习笔记07:事件处理、窗口跳转与传递数据

    文章目录 零.学习目标 一.三个基本控件 1.标签控件(TextView) 2.编辑框控件(EditText) 3.按钮控件(Button) 二.安卓事件处理机制 (一)安卓事件处理概述 (二)安卓事 ...

  4. Vue + Spring Boot 学习笔记02:引入数据库实现用户登录功能

    Vue + Spring Boot 学习笔记02:引入数据库实现用户登录功能 在学习笔记01里,我们利用跨域打通了前端的Vue与后端的Spring Boot,实现了用户登录功能,但是后台的登录控制器在 ...

  5. JDBC学习笔记——Java语言与数据库的鹊桥

    JDBC学习笔记--Java语言与数据库的鹊桥     JDBC(Java DataBase Connectivity):SUN公司提供的 一套操作数据库的标准规范,说白了就是用Java语言来操作数据 ...

  6. C#学习笔记----C#连接MySQL数据库

    C#学习笔记----C#连接MySQL数据库 using System.Linq; using System.Text; using System.Data;// 引用表的命名空间 using Sys ...

  7. 很low的安卓学习笔记(一、实用技巧)

    很low的安卓学习笔记(一.实用技巧) 一.学习了几天的实用技巧小总结: 1.规范的定义内容的格式: 2.一些快捷键 3.将xxx.xml布局改为Activity中可以调用的View视图 4.当左下角 ...

  8. 安卓学习笔记3——登录界面UI

    安卓学习笔记3--登录界面UI 一.登录界面UI 1.根据需求写UI 2.主活动 3.主活动调用的读写文件的工具类 4.效果展示 二.总结与改进 不足: 1.密码分割采用字符串:当密码和用户名包含该字 ...

  9. 安卓学习笔记之骚扰拦截

    安卓学习笔记之骚扰拦截 1.监听电话状态 2.检测来电号码是否匹配拦截条件 3.若匹配,则挂断电话 实例代码: 获取TelephonyManager 对象,并监听来电状态 TelephonyManag ...

最新文章

  1. keepalived mysql集群_keepalived + Mysql(主主)实现高可用集群
  2. 找到IIS Express配置/配置数据库文件在哪里?
  3. fgets和scanf的区别
  4. 维纳滤波原理(Wiener Filter)
  5. eclipse怎么创建web项目html,eclipse入门之创建第一个web程序(jsp测试环境)
  6. DLL回调EXE里的函数
  7. set集合和深浅拷贝
  8. centos 安装trace_前期的准备工作-MacOS Mojave 10.14.3 下安装CentOS 7及Bochs 002
  9. 把一张合成图分拆出各个小图
  10. php layui table,Layui table组件相关介绍
  11. cad在布局怎么调比例_大神们都在用的9个CAD制图技巧,你会用几个?
  12. 9年120亿,美的数字化转型纪实
  13. Android 音视频深入 十三 OpenSL ES 制作音乐播放器,能暂停和调整音量(附源码下载)...
  14. Vue默认插槽、具名插槽、作用域插槽及使用作用域插槽删除列表项
  15. centos下编译安装Openssl
  16. C语言编程实例(一)
  17. 爬虫之路——DAY2
  18. http://www.bluecoat.com.cn/resources/overview
  19. html鼠标经过状态,30种炫酷html5鼠标滑过图片标题显示效果
  20. 毫秒为单位产生随机数

热门文章

  1. 有了MDL锁视图,业务死锁从此一目了然
  2. 【华为云技术分享】云小课 | SAP容灾一点通
  3. C语言提前结束for循环,[新人求指教]51C语言编程可否用中断令循环结束提早结束...
  4. Think in Java第四版 读书笔记10 第16章 数组
  5. java生成三角网_源码:基于离散点的构TIN算法(三角网)
  6. dw上的php代码如何预览在浏览器_13个面向开发人员的JavaScript代码编辑器和IDE
  7. linux mysql df_Linux基础:df命令总结
  8. 小程序开发代码_企业为什么要选择小程序定制开发?
  9. python中dtypes_Dataframe创建及index,columns,values,dtypes等属性介绍
  10. Linux、Ubuntu、CentOS安装和配置zsh