79

我是 Android 的新手,我正在开发一个简单的应用程序以获得一些基本经验。我的应用程序非常简单,其中包括广播接收器和一些活动。两个组件都使用单个数据库,因此理论上可能会发生两者都尝试同时访问数据库的情况。

目前,我只是在每次需要时实例化 db 对象(这是一个 SQLite db 帮助器类),并执行所需的操作:查询、插入等。

从我在这里和其他一些文档中阅读的内容来看,如果同时访问数据库,则会出现“数据库锁定”异常的问题,因此更好的方法是拥有这个数据库对象的单个实例,所以所有组件始终使用相同的数据库连接。

上述推理是否正确?那么单身人士会是一个足够好的解决方案吗?我知道一些纯粹主义者可能会反对它,但请注意,这是一个相当简单的应用程序,因此我可以负担得起在其他情况下不会做的事情。

否则,更好的选择是什么?我已经阅读了有关使用内容提供程序的信息,但这样做太多了,此外我对与其他活动共享数据不感兴趣。我确实读过这篇文章,发现它很有帮助。

4

2 回答 2

101

单击此处查看我关于此主题的博客文章。


下面是一些示例代码,说明了三种可能的方法。这些将允许在整个应用程序中访问数据库。

方法 #1:让 `SQLiteOpenHelper` 成为静态数据成员

这不是完整的实现,但它应该让您了解如何DatabaseHelper正确设计类。静态工厂方法确保任何时候都只存在一个 DatabaseHelper 实例。

/**
 * create custom DatabaseHelper class that extends SQLiteOpenHelper
 */
public class DatabaseHelper extends SQLiteOpenHelper { 
    private static DatabaseHelper mInstance = null;

    private static final String DATABASE_NAME = "databaseName";
    private static final String DATABASE_TABLE = "tableName";
    private static final int DATABASE_VERSION = 1;

    private Context mCxt;

    public static DatabaseHelper getInstance(Context ctx) {
        /** 
         * use the application context as suggested by CommonsWare.
         * this will ensure that you dont accidentally leak an Activitys
         * context (see this article for more information: 
         * http://android-developers.blogspot.nl/2009/01/avoiding-memory-leaks.html)
         */
        if (mInstance == null) {
            mInstance = new DatabaseHelper(ctx.getApplicationContext());
        }
        return mInstance;
    }

    /**
     * constructor should be private to prevent direct instantiation.
     * make call to static factory method "getInstance()" instead.
     */
    private DatabaseHelper(Context ctx) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.mCtx = ctx;
    }
}

方法 #2:使用 `ContentProvider` 抽象 SQLite 数据库

这是我建议的方法。一方面,新CursorLoader类需要ContentProviders,因此如果您希望 Activity 或 FragmentLoaderManager.LoaderCallbacks<Cursor>使用 a实现CursorLoader(我建议您利用它,它很神奇!),您需要ContentProvider为您的应用程序实现 a。此外,您无需担心使用 ContentProviders 创建 Singleton 数据库助手。只需getContentResolver()从 Activity 调用,系统就会为您处理所有事情(换句话说,无需设计单例模式来防止创建多个实例)。

希望这可以帮助!

于 2012-02-14T23:55:22.683 回答
22

我从未读过有关使用单例访问 android 上的数据库的信息。你介意提供一个关于那个的链接吗?

在我的应用程序中,我使用简单的 dbhelper 对象,而不是单例,我认为这更多是 sql 引擎的工作,以确保数据库不被锁定,而不是你的 android 类的工作,它适用于我最大的应用程序中等大小。

更新#1:查看您提供的参考资料,看起来问题根本不在于使用 a 的不同实例dbhelper。即使是单个实例也可能会遇到访问数据库的问题:问题来自并发访问。因此,确保不同线程正确访问数据库的唯一方法是使用简单的线程同步机制(synchronized方法或块),这与使用单例几乎无关。

更新#2:您提供的第二个链接清楚地表明,在多个线程同时写入数据库的情况下,它们需要单例 dbhelper 对象。例如,如果您从 AsyncTasks 执行 sql 操作(插入/更新/删除),就会发生这种情况。在这种情况下,单例对象 dbhelper 将简单地将所有 sql 操作放在某种管道中并按顺序执行它们。

此解决方案可能比使用 java 中的同步方法使用适当的线程同步更容易实现。实际上,我认为应该在 android 文档的某个地方更加强调这个问题,并且可以鼓励使用单例 db 助手。

感谢这个好问题和后续行动。

于 2011-08-01T23:17:31.877 回答