为SQLiteDatabase使用Singleton设计模式

Dan*_*Dan 71 java sqlite singleton android android-loadermanager

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

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

从我在这里和其他一些文档中读到的,这有一个问题是在同时访问db的情况下获得"db locked"异常,所以更好的方法是拥有这个db对象的单个实例所以所有组件始终使用相同的数据库连接.

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

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

Ale*_*ood 97

点击此处查看关于此主题的博文.


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

方法#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

这是我建议的方法.其一,新的CursorLoader类需要ContentProviderS,所以如果你想要一个活动或片段来实现LoaderManager.LoaderCallbacks<Cursor>CursorLoader(我建议你利用的,这是不可思议的!),你需要实现ContentProvider你的应用程序.此外,您不必担心使用ContentProviders创建Singleton数据库帮助程序.只需getContentResolver()从Activity 调用,系统就会为您处理所有事情(换句话说,不需要设计Singleton模式来防止创建多个实例).

希望这可以帮助!

  • 让`getInstance` 同步不是一个好主意吗? (3认同)

Sni*_*las 21

我从来没有读过使用单例来访问android上的数据库.你介意提供一个关于它的链接.

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

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

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

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

谢谢你这个好问题和后续行动.