在创建与SQLite数据库交互的方法/活动时,我应该多么小心使用线程安全性?

时间:2010-09-20 22:10:05

标签: android sqlite

我正在创建一个应用程序,允许从Activities(最多~25)启动许多不同的TabActivity。大多数活动都需要来自sqlite数据库的数据,因此当onCreate运行时,AsyncTask会创建一个SQLiteOpenHelper对象(它将打开一个可读/可写的数据库),运行一个查询,检索数据,然后一切都关闭了。

我只是在测试乱搞,看看我是否可以破坏某些东西,所以我将每个Activity添加到TabActivity's TabHost。然后我开始尽快将每个标签混合。

我注意到很快我开始在LogCat中看到:Caused by: android.database.sqlite.SQLiteException: database is locked: BEGIN EXCLUSIVE;并且应用程序继续死亡。

TabHost通常只有大约4-6个标签(我可以只限制用户)。我没有能够用少量标签来破坏任何东西,但是我仍然担心我可能会以糟糕的方式访问数据库。

如何防止我的SQLiteDatabase对象导致锁定?

如果我创建ContentProvider将消除数据库锁定的可能性?

对于我从SQLiteDatabase

访问数据所做的更改,您有什么建议吗?

我最终采用了使用Application类并存储1 SQLiteOpenHelper并尝试保持同步的方法。这似乎工作得很好 - 我将我的所有25项活动都放在TabHost中并且没有错误地将它们捣碎。

我在我的活动中的每个((SQLiteDbApplication)getApplication()).setDbHelper(new DBHelper(this, Constants.DB_NAME, null, Constants.DB_VERSION_CODE));中调用onCreate()方法(如下所示)

对此方法或使用此Application类所做的更改的任何进一步建议?

import android.app.Application;
import android.database.sqlite.SQLiteDatabase;

public class SQLiteDbApplication extends Application {
    private DBHelper dbHelper;
    private SQLiteDatabase db;
    public synchronized DBHelper getDbHelper() {
        db = dbHelper.getDatabase();//returns the already opened database object
        while(db.isDbLockedByCurrentThread() || db.isDbLockedByOtherThreads());
        return dbHelper;
    }
    public synchronized void closeDb() {
        if(null != dbHelper)
            dbHelper.close();
        if(null != db)
            db.close();
    }

    @Override
    protected void finalize() throws Throwable {
        if(null != dbHelper)
            dbHelper.close();
        if(null != db)
            db.close();
        super.finalize();
    }
    public synchronized void setDbHelper(DBHelper dbHelper) {
        if(null == this.dbHelper) {
            this.dbHelper = dbHelper;
            this.dbHelper.setDb(this.dbHelper.getWritableDatabase());//creates and sets the database object via getWritableDatabase()
        }
    }
}

2 个答案:

答案 0 :(得分:2)

所有活动回调都发生在主线程上,因此在您描述的场景中,无论您有多少活动或标签,都不会进行多线程。

ContentProvider不提供任何锁定。事实上,它可以引入多线程,你不会拥有它,因为它允许其他进程调用你自己的进程,当发生这种情况时,调用将从你进程中的一个单独的线程调度(而不是在主UI上)线程)。

当然,如果你创建自己的线程,那么你也将进行多线程。

答案 1 :(得分:2)

如果您担心所有数据库连接,请尝试将自己限制为一个SqliteOpenHelper,并确保围绕它包装同步层。

您可以扩展application类,然后调用getApplication并将您获得的对象转换为您的应用程序。现在,您可以在此应用程序类中存储SqliteOpenHelper,并为数据库连接构建自己的线程安全访问方法。

如果您在所有onCreate方法中使用AsyncTask并且遇到许多选项卡问题,这些问题也可能发生在速度较慢的设备,更快的用户或在使用期间变大的数据库中。

根据您的应用程序的使用情况,您可以采用保存方式并完成线程和锁定的所有工作和痛苦,或者您可以使用许多从未产生错误的选项卡发布应用程序并确保捕获数据库异常并向自己发送通知(例如通过谷歌分析)来测试线程问题是否确实发生在应用程序的实际使用中。