为SQLiteDatabase使用Singleton设计模式

时间:2011-08-01 23:09:32

标签: java android sqlite singleton android-loadermanager

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

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

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

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

否则,更好的选择是什么?我已经阅读了有关使用内容提供商的信息,但这对此来说太过分了,除此之外我对与其他活动共享数据不感兴趣。我确实读过这个post并发现它很有用。

2 个答案:

答案 0 :(得分:96)

Click here to see my blog post on this subject.


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

方法#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课程需要ContentProvider,因此如果您希望活动或片段实现LoaderManager.LoaderCallbacks<Cursor> CursorLoader(我建议您利用,这很神奇!),你需要为你的应用程序实现ContentProvider。此外,您不必担心使用ContentProviders创建Singleton数据库帮助程序。只需从Activity中调用getContentResolver(),系统就会为您处理所有事情(换句话说,不需要设计Singleton模式来防止创建多个实例)。

希望这有帮助!

答案 1 :(得分:20)

我从未读过使用单例访问android上的数据库。您是否介意提供相关链接。

在我的应用程序中,我使用简单的dbhelper对象,而不是单例,我认为这更像是sql引擎的工作,以确保db不被锁定,而不是你的android类的工作,它对我的​​工作非常好最大的应用程序,中等大小。

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

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

与使用java中的同步方法使用正确的线程同步相比,此解决方案更容易实现。实际上我认为应该更多地强调android文档中关于这个问题的地方,并且可以鼓励使用单例db帮助程序。

感谢您提出这个不错的问题和后续工作。