探讨SQLiteDatabase的优雅使用

本文探讨了在Android应用中优雅地使用SQLite数据库的方法,对比了几种常见的方式,并提出了一种结合单例模式与计数器的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不少人在使用SQLiteDatabase数据库时都很纠结,到底如何使用才算优雅?本文就此问题进行探讨。   

使用SQLiteDatabase,不外乎下面几种方式:

1. 在每个CRUD方法开始时调用getWritableDatabase()取得数据库,方法结束时close db

2. 在每个activity、service等生命周期开始时new一个新db对象,取得数据库连接;然后在destroy时close db

3. 在Application定义一个全局的数据库对象

4. 单例模式

先看第一种。缺点一大堆:代码臃肿;每次查询都要打开关闭数据库,性能方面也受到影响;最致命的一点是,有时候查询需要返回一个Cursor对象到其他地方使用,比如ListView,但是db又在查询方法结束时close了,导致运行直接抛异常。所以这种方式最好不用。

第二种方式和第一种类似,只是把打开关闭db的位置挪了一下,使db对象的生存范围扩大了一点。如果在onDestroy()中关闭,又会带来另外一个问题:打开新activity时,老activity只是被隐藏了,还在,导致打开的db越来越多,显然不可取。不过这种方式可以改进一下,改在onResume()中生成db,onPause()中关闭db,这样能保证系统中不会有多余的db实例,但仍不是很优雅。

第三种方式保证系统在运行中仅持有一个db实例,但是问题来了,在哪里close db呢?onTerminate()?不行,系统开始运行时会执行application的onCreate(),但是退出时不会执行onTerminate(),不信的话可以试一下。

最后讨论一下本文的重头戏,单例。

普通的单例模式,在我看来,和第三种application模式本质上是相同的,没区别,当然也就存在application方式的问题。而且,还会有其他问题。在创建SQLiteOpenHelper时需要传递一个Context进去,假如Activity A创建了这个db,然后其他Activity也在使用这个单例对象,而Activity A又需要被销毁,但是由于单例对象持有这个Context,导致Activity A不能被有效销毁。

怎么办?

完美解决

还是使用单例,不过需要改进一下。

首先,针对close问题,我们设一个计数器,在activity的onCreate()方法get单例实例,计数器加1,在onDestroy()方法释放,计数器减1,当计数器为0时,close db。

其次,创建SQLiteOpenHelper不使用activity的context,改用application的context。

DbAdaptor代码如下:

public class DbAdaptor {
    
    private static final String DATABASE_CREATE =
            "create table users (_id integer primary key autoincrement, " +
            "account text not null, password text not null);";
    private static final String DATABASE_NAME = "test";
    private static final int DATABASE_VERSION = 2;
    
    private static int count;
    private static DbAdaptor dbAdaptor = null;
    private SQLiteDatabase mDb; 

    class DbHelper extends SQLiteOpenHelper{

        public DbHelper(Context context) {
            super(context.getApplicationContext(), DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(DATABASE_CREATE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS users");
            onCreate(db);
        }
    }
    
    private DbAdaptor(Context ctx){
        DbHelper help = new DbHelper(ctx);
        mDb = help.getWritableDatabase();
    }
    
    public static DbAdaptor getInstance(Context ctx){
        if(null == dbAdaptor){
            dbAdaptor = new DbAdaptor(ctx);
        }        
        count++;
        
        return dbAdaptor;
    }
    
    public void release(){
        count--;
        if(count == 0){
            mDb.close();
            dbAdaptor = null;
        }
    }
}
注意一定要使用application的context;release时不仅仅要close db,还要将dbAdapter设为null。

每个需要使用数据库的activity都要在onCreate()中调用getInstance(),在onDestroy()中调用release(),注意保证这两个方法都只调用一次,否则count计数器不能正确增减。这些代码没必要在每个activity都写一遍,定义一个基类就可以了,子activity通过调用getDataBase()来使用db,代码如下:

public class BaseActivity extends Activity{

    private DbAdaptor db;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        db = DbAdaptor.getInstance(this);
    }
    
    @Override
    protected void onDestroy() {        
        super.onDestroy();
        
        db.release();
    }
    
    public DbAdaptor getDataBase(){
        return db;
    }
}
这就是单例加计数器模式,优雅而华丽!

SQLite是一种轻型的关系型数据库管理系统,它是基于磁盘文件的数据库,不需要独立的服务器进程,也不需要配置。它可以在大多数操作系统上运行,包括Windows、Linux、Unix等。SQLite提供了一个简单易用的API,开发者可以很容易地将其集成到应用程序中。Android平台提供了一个名为SQLiteDatabase的类,用于在应用程序中使用SQLite数据库。 首先,需要在Android项目中添加SQLite库的依赖: ```groovy implementation 'androidx.sqlite:sqlite:2.1.0' ``` 然后,在代码中创建或打开数据库,可以如下所示: ```java SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("test.db", null); ``` 其中,第一个参数指定了数据库的名称,第二个参数可以指定一个CursorFactory,如果不需要可以设置为null。 接下来,可以使用SQLiteDatabase对象执行SQL语句,例如创建表、插入数据、更新数据、查询数据等。例如,创建一个名为user的表,包含id、name和age三个字段: ```java db.execSQL("CREATE TABLE IF NOT EXISTS user(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER)"); ``` 插入一条数据: ```java db.execSQL("INSERT INTO user(name, age) VALUES('Tom', 20)"); ``` 更新数据: ```java db.execSQL("UPDATE user SET age=21 WHERE name='Tom'"); ``` 查询数据: ```java Cursor cursor = db.rawQuery("SELECT * FROM user WHERE age>20", null); if (cursor != null) { while (cursor.moveToNext()) { int id = cursor.getInt(cursor.getColumnIndex("id")); String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); Log.d(TAG, "id: " + id + ", name: " + name + ", age: " + age); } cursor.close(); } ``` 最后,记得在不需要使用数据库时关闭它: ```java db.close(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值