在 Android 应用开发中,数据持久化是至关重要的一环,SQLite 作为 Android 内置的轻量级关系型数据库,因其占用资源少、性能优异、无需独立服务器进程而被广泛采用,它允许开发者以结构化的方式存储、查询和管理应用数据,例如用户信息、设置项、缓存数据等,掌握如何在 Android 中创建和管理 SQLite 数据库,是每一位 Android 开发者的必备技能。
核心概念:SQLiteOpenHelper
Android SDK 提供了一个非常重要的辅助类 android.database.sqlite.SQLiteOpenHelper
,它极大地简化了数据库的创建和版本管理,开发者无需直接编写复杂的文件创建和版本检查逻辑,只需继承这个类并实现其核心方法即可。SQLiteOpenHelper
主要负责两个关键任务:
- 创建数据库:当应用首次访问数据库,且数据库文件不存在时,它会自动触发创建过程。
- 升级数据库:当应用版本更新,数据库结构需要变更时(如添加新表、修改列),它会提供一个安全的升级通道。
SQLiteOpenHelper
包含两个必须重写的抽象方法和两个常用的实例方法:
onCreate(SQLiteDatabase db)
:当数据库首次被创建时调用,这里是执行创建表(CREATE TABLE
)等初始化语句的最佳位置。onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
:当数据库需要升级时调用,开发者可以在这里根据旧版本号oldVersion
和新版本号newVersion
来执行相应的数据库结构变更逻辑,如ALTER TABLE
或DROP TABLE
。getReadableDatabase()
:获取一个可读的数据库对象,如果磁盘空间满,它会以只读方式打开数据库。getWritableDatabase()
:获取一个可读写的数据库对象,这是最常用的方法,它会尝试以读写方式打开数据库。
创建 SQLite 数据库的详细步骤
下面将通过一个完整的实例,展示如何创建一个名为 user.db
的数据库,并在其中创建一张存储用户信息的 users
表。
第一步:创建数据库辅助类
创建一个继承自 SQLiteOpenHelper
的 Java 或 Kotlin 类,这个类将封装所有与数据库创建和升级相关的逻辑。
// DatabaseHelper.java import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DatabaseHelper extends SQLiteOpenHelper { // 数据库名称 private static final String DATABASE_NAME = "user.db"; // 数据库版本,每次升级时需要增加此值 private static final int DATABASE_VERSION = 1; // 表名和列名常量,避免硬编码 public static final String TABLE_USERS = "users"; public static final String COLUMN_ID = "id"; public static final String COLUMN_NAME = "name"; public static final String COLUMN_AGE = "age"; // 创建表的 SQL 语句 private static final String SQL_CREATE_TABLE_USERS = "CREATE TABLE " + TABLE_USERS + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_NAME + " TEXT NOT NULL, " + COLUMN_AGE + " INTEGER" + ")"; // 构造函数 public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // 当数据库被创建时,执行创建表的 SQL db.execSQL(SQL_CREATE_TABLE_USERS); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 简单的升级策略:删除旧表,然后重新创建 // 注意:此操作会丢失所有数据,实际项目中应使用更安全的迁移策略 db.execSQL("DROP TABLE IF EXISTS " + TABLE_USERS); onCreate(db); } }
在上述代码中,我们定义了数据库名称、版本号、表名、列名以及创建表的 SQL 语句,构造函数通过 super()
调用父类,传入必要的参数。onCreate
方法执行了 CREATE TABLE
命令。
第二步:在 Activity 中使用数据库
创建好 DatabaseHelper
后,就可以在应用的其他组件(如 Activity、Service)中获取并使用数据库了。
// MainActivity.java import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.Bundle; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private DatabaseHelper dbHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 1. 初始化 DatabaseHelper 实例 dbHelper = new DatabaseHelper(this); // 2. 获取可写的数据库对象 // 第一次调用此方法时,如果数据库不存在,会触发 DatabaseHelper 的 onCreate 方法 SQLiteDatabase db = dbHelper.getWritableDatabase(); // 3. 数据库已创建并可以使用了 Toast.makeText(this, "数据库创建成功或已存在!", Toast.LENGTH_SHORT).show(); // 此处可以进行增删改查(CRUD)操作... // 插入一条数据 // ContentValues values = new ContentValues(); // values.put(DatabaseHelper.COLUMN_NAME, "张三"); // values.put(DatabaseHelper.COLUMN_AGE, 25); // long newRowId = db.insert(DatabaseHelper.TABLE_USERS, null, values); } @Override protected void onDestroy() { super.onDestroy(); // 4. 在不需要时关闭数据库连接(可选,但推荐) // dbHelper.close(); } }
当 MainActivity
启动并调用 dbHelper.getWritableDatabase()
时,系统会检查 /data/data/<your.package.name>/databases/
目录下是否存在 user.db
文件,如果不存在,就会调用 DatabaseHelper
的 onCreate
方法来创建它。
最佳实践与注意事项
- 异步操作:数据库操作(尤其是查询和大量数据写入)可能是耗时的,直接在 UI 线程执行可能导致应用无响应(ANR),应始终在后台线程(如使用
AsyncTask
、ExecutorService
或 Kotlin 协程)中执行数据库操作。 - 常量定义:将表名、列名等定义为
public static final
常量,可以有效避免因字符串拼写错误导致的运行时异常,并提高代码的可维护性。 - 数据库版本管理:
DATABASE_VERSION
是数据库升级的关键,当你需要修改表结构(在users
表中添加一个email
列)时,应该将DATABASE_VERSION
增加(从 1 改为 2),并在onUpgrade
方法中编写相应的ALTER TABLE
语句,而不是简单地删除旧表,以保留用户数据。
现代替代方案:Room 持久性库
虽然直接使用 SQLiteOpenHelper
和 SQLiteDatabase
功能强大,但代码量较大,容易出错(如 SQL 语句编译时无法检查),Google 推出了 Room 持久性库作为现代 Android 应用的首选方案,Room 在 SQLite 之上提供了一个抽象层,它:
- 简化了数据库操作:通过注解(如
@Entity
,@Dao
,@Database
)大大减少了模板代码。 - 编译时 SQL 验证:在编译时检查 SQL 语句的正确性,避免运行时崩溃。
- 与 LiveData/RxJava/Kotlin Flow 无缝集成:轻松实现响应式数据编程。
对于新项目,强烈推荐使用 Room 库,但理解原生 SQLite 的工作原理,有助于更好地掌握 Room 的底层机制。
相关问答 (FAQs)
问题1:SQLiteOpenHelper
的 onCreate()
和 onUpgrade()
方法分别在什么时候被调用?
解答:onCreate(SQLiteDatabase db)
方法在数据库文件首次被创建时调用,当你通过 getWritableDatabase()
或 getReadableDatabase()
请求一个数据库对象,而系统发现指定名称的数据库文件尚不存在时,就会创建该文件,并立即回调 onCreate
方法,该方法在整个应用的生命周期中只会被调用一次。
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
方法在数据库需要升级时调用,当你修改了 SQLiteOpenHelper
构造函数中传入的版本号(DATABASE_VERSION
),使其大于设备上已存在的数据库文件的版本号时,系统就会调用 onUpgrade
,你可以根据 oldVersion
和 newVersion
参数来决定执行哪些升级逻辑,例如从版本 1 升级到 2 时添加一个新列,从版本 2 升级到 3 时再添加一个新表。
问题2:我应该直接使用原生 SQLite API 还是使用 Room 库?
解答:
这取决于你的项目需求和个人偏好,但总的原则是:对于新项目,优先推荐使用 Room 库。
的优点是更底层,控制力更强,不需要额外的依赖库,但缺点是代码繁琐,需要手写大量 SQL 语句和模板代码,且 SQL 错误只能在运行时发现,容易导致 android.database.sqlite.SQLiteException
。使用 Room 库 的优点非常突出:它通过注解极大地简化了代码,将开发者从繁琐的 SQL 编写和对象映射中解放出来,最重要的是,它能在编译时验证 SQL 语句的正确性,提前发现错误,它与 Android 架构组件(如
LiveData
,ViewModel
,Kotlin Flow
)完美集成,让构建响应式、健壮的数据层变得异常简单。
小编总结建议:如果你正在维护一个使用原生 SQLite 的旧项目,或者有非常特殊的数据库操作需求,可以继续使用原生 API,但对于所有新启动的 Android 项目,Room 几乎总是更好的选择,它能显著提高开发效率和代码质量。
【版权声明】:本站所有内容均来自网络,若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!
发表回复