本文所有代码均存放于
https://github.com/MADMAX110/Starbuzz
在Android世界里,通常可以把数据安全地存放在SQLite数据库中。
回到之前创建地Starbuzz应用,这个应用允许用户通过一系列屏幕导航查看Starbuzz提供的饮料。接下来让它从SQLite数据库获取数据。
一、Android使用SQLite数据库持久存储数据
所有应用都需要存储数据,Android世界中存储数据的主要方法就是使用SQLite数据库。
1、SQLite是轻量级的。 大多数数据库系统都需要一个特殊的数据库服务器进程才能工作。SQLite并不需要这样一个服务器进程,SQLite数据库实际上就是一个文件。如果没有用到数据库,它不会占用任何处理器时间,这对于移动设备尤其重要。
2、针对单个用户优化。 只是这个应用要与数据库交互,所以不必使用用户名和口令来识别我们的身份。
3、它很稳定而且速度很快。 SQLite数据库极其稳定,可以处理数据库事务,这说明你在更新多个数据,突然出现故障,SQLite可以回滚数据。另外读写数据的代码时用优化的C语言编写的,所以不仅速度很快,而且还能减少所需要的处理器功耗。
Android会自动为各个应用创建一个文件夹来存储应用的数据库。为Starbuzz应用创建数据库时,它会把数据库存储在设备上的以下文件夹中:
/data/data/com.hfad.starbuzz/databases
应用可以在这个文件夹中存储多个数据库,每个数据由两个文件组成。
第一个文件是数据库文件,与数据库同名,例如这个文件就名为starbuzz。这是SQLite数据库文件。所有数据都存放在这个文件中。
第二个是journal文件,它也是与数据库同名,另外有一个-journal后缀。它包含对数据库的所有修改。
Android提供了一些SQLite类
Android使用了一组类,可以利用这些类管理SQLite数据库,这个工作主要由3类对象来完成。
1、SQLite帮助器。利用SQLite帮助器可以创建和管理数据库,要扩展SQLiteOpenHelper类来创建SQLite帮助器。
2、SQLite数据库。 可以利用SQLiteDatabases类访问数据库。这就像JDBC中的SQLConnection。
3、游标。可以利用Cursor读写数据库。这就像JDBC中的ResultSet。
二、修改应用来使用数据库
这里将使用一个SQLite帮助器创建将在Startbuzz应用中使用的SQLite数据库。下面要把Drink Java类替换为一个数据库,所以这个SQLite帮助器要完成下面的工作:
1、创建数据库
首先要让SQLite帮助器创建Starbuzz数据库的第一个版本。
2、创建Drink表,并填充饮料信息
有了数据库后,可以在这个数据库中创建一个表。表结构要反映当前Drink类的属性,所以这个表应当能存储各个饮料的名字、描述和图像资源ID。然后再在这个表中增加3个饮料。
SQLite帮助器管理数据库
SQLiteOpenHelper类可以帮助你创建和维护SQLite数据库。可以把它想成一个个人助理,专门负责处理日常的数据库维护工作。它可以
1、创建数据库
第一次安装一个应用时,数据库文件并不存在,SQLite帮助器会确保正确地创建这个数据库文件,要有正确地文件名,而且要安装正确地表结构。
2、访问数据库
我们的应用不需要了解数据库文件位置的详细信息,所以SQLite帮助器会提供一个易于使用的数据库对象,这样我们就库在需要利用这个数据库对象访问数据库。
3、保持数据库井然有序
数据库结构可能会随时间改变,可以依赖SQLite帮助器将一个老版本的数据库转换为一个闪亮的新版本,包含它需要的所有最新的数据库结构。
创建SQLite帮助器
可以写一个类扩展SQLiteOpenHelper类来创建SQLite帮助器。为此必须覆盖onCreate和onUpgrade方法,这两个方法时必不可少的。
第一次在设备上创建数据库时会调用onCreate方法。这个方法应当包含为应用创建数据库表所需要的代码。
数据库需要升级时会调用onUpgrade方法,举例来说,如果需要在发布数据库之后对数据库中的表做一些修改,就要在这个方法中完成。
在com.hfad.starbuzz包中新建一个名为StarbuzzDatabaseHelper的Java类。
指定数据库
要创建数据库,SQLite帮助器需要两个信息。
首先,我们需要为数据库指定一个名字。通过为数据库指定一个名字,可以确保数据库关闭时它还保存在设备上。如果没有指定数据库名,就只会在内存中创建这个数据库,所以一旦数据库关闭,它就会消失。
需要提供的第二个信息是数据库版本。数据库版本必须是一个整数值,从1开始。SQLite帮助器使用这个版本号来确定数据库是否需要升级。
指定数据库名和版本时,要把它们传递到SQLiteOpenHelper超类的构造方法。我们指定这个数据库名为starbuzz,因为这是这个数据库的第一个版本,所以版本号为1。
SQLite的存储形式和查询方式几乎与SQL相同。
创建数据库时会调用onCreate方法,SQLite帮助器负责创建SQLite数据库。第一次需要使用数据库时,会在设备上创建一个空的数据库,然后调用SQLite帮助器的onCreate方法。
onCreate方法有一个参数,这是一个SQLiteDatabse对象,表示所创建的数据库。
可以使用SQLiteDatabase execSQL方法在这个数据库上执行SQL命令。这个方法有一个参数,就是你想要执行的SQL命令。
db.execSQL("CREATE TABLE DRINK (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "DESCRIPTION TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER)");
使用insert方法插入数据
要在SQLite数据库中的一个表中插入数据,先要指定想在这个表中插入什么值。为此首先创建一个ContentValues对象。ContentValues对象描述一个数据集。通常要为想要创建的每个数据行创建一个新的ContentValues对象。可以使用put方法为其增加数据。这个方法需要数据的名/值对。
public static void insertDrink(SQLiteDatabase db, String name, String description, int resourceID){
ContentValues drinkValues = new ContentValues();
drinkValues.put("NAME", name);
drinkValues.put("DESCRIPTION", description);
drinkValues.put("IMAGE_RESOURCE_ID", resourceID);
db.insert("DRINK", null, drinkValues);
}
完整的StarbuzzDatabaseHelper代码:
package com.hfad.starbuzz;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class StarbuzzDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "starbuzz";
private static final int DB_VERSION = 1;
public StarbuzzDatabaseHelper(@Nullable Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE DRINK (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "DESCRIPTION TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER)");
insertDrink(db, "Latte", "Espresso and steamed milk", R.drawable.latte);
insertDrink(db, "Cappuccino", "Espresso, hot milk and steamed-milk foam", R.drawable.cappuccino);
insertDrink(db, "Filter", "Our best drip coffee", R.drawable.filter);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public static void insertDrink(SQLiteDatabase db, String name, String description, int resourceID){
ContentValues drinkValues = new ContentValues();
drinkValues.put("NAME", name);
drinkValues.put("DESCRIPTION", description);
drinkValues.put("IMAGE_RESOURCE_ID", resourceID);
db.insert("DRINK", null, drinkValues);
}
}
三、升级数据库
SQLite帮助器通过查看版本号来区分这个SQLite数据库是否需要更新,通过在SQLiteOpenHelper超类构造方法中传入版本号,可以在SQLite帮助器中指定数据库的版本。
使用onUpgrade升级数据库,使用onDowngrade降级数据库。
假设需要升级数据库,为DRINK表增加一个新列。由于我们希望所有用户都能得到这个修改,所以要确保onCreate和onUpgrade方法都包含这个修改。
onCreate方法会确保所有新用户得到这个新列,onUpgrade方法会确保所有现有的用户也能得到这个新列。
package com.hfad.starbuzz;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class StarbuzzDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "starbuzz";
private static final int DB_VERSION = 2;
public StarbuzzDatabaseHelper(@Nullable Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
//第一次创建数据库时会调用onCreate
public void onCreate(SQLiteDatabase db) {
updateMyDatabase(db, 0, DB_VERSION);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
updateMyDatabase(db, oldVersion, newVersion);
}
public static void insertDrink(SQLiteDatabase db, String name, String description, int resourceID){
ContentValues drinkValues = new ContentValues();
drinkValues.put("NAME", name);
drinkValues.put("DESCRIPTION", description);
drinkValues.put("IMAGE_RESOURCE_ID", resourceID);
db.insert("DRINK", null, drinkValues);
}
private void updateMyDatabase(SQLiteDatabase db, int oldVersion, int newVersion){
if (oldVersion < 1){
db.execSQL("CREATE TABLE DRINK (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "DESCRIPTION TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER)");
insertDrink(db, "Latte", "Espresso and steamed milk", R.drawable.latte);
insertDrink(db, "Cappuccino", "Espresso, hot milk and steamed-milk foam", R.drawable.cappuccino);
insertDrink(db, "Filter", "Our best drip coffee", R.drawable.filter);
}
if (oldVersion < 2){
db.execSQL("ALTER TABLE DRINK ADD COLUMN FAVORITE NUMERIC;");
}
}
}