【问题标题】:Database global instance数据库全局实例
【发布时间】:2011-09-01 22:04:38
【问题描述】:

所以我想为所有应用程序活动创建一个数据库实例。 我找到了以下代码:

public class MyApplication extends Application {

    private static SQLiteDatabase mDB = null;

    @Override
    public void onCreate() {
        super.onCreate();
    DataBaseOpenHelper m_OpenHelper = new DataBaseOpenHelper( this );
    mDB = m_OpenHelper.getWritableDatabase();
    }

    public static SQLiteDatabase getDB() {
        return mDB;
    }
}

我不明白什么时候可以关闭 SQLiteDatabase 实例。

【问题讨论】:

    标签: android database sqlite android-loadermanager


    【解决方案1】:

    当我刚开始使用 Android 时,这对我来说是个问题,因为网络上没有多少教程描述了如何正确地允许在整个应用程序中访问您的数据库(不要问我为什么)。下面是一些示例代码,展示了三种可能的方法。

    方法#1:继承`Application`

    如果你知道你的应用程序不会很复杂(即如果你知道你最终只会有一个Application 的子类),那么你可以创建一个Application 的子类并扩展你的主Activity它。这可确保数据库的一个实例在应用程序的整个生命周期中运行。

    public class MainApplication extends Application {
    
        /**
         * see NotePad tutorial for an example implementation of DataDbAdapter
         */
        private static DataDbAdapter mDbHelper;
    
        /**
         * create the database helper when the application is launched 
         */
        @Override
        public void onCreate() {
            mDbHelper = new DataDbAdapter(this);
            mDbHelper.open();
        }
    
        /** 
         * close the database helper when the application terminates.
         */
        @Override
        public void onTerminate() {
            mDbHelper.close();
            mDbHelper = null;
        }
    
        public static DataDbAdapter getDatabaseHelper() {
            return mDbHelper;
        }
    }
    

    方法 #2:让 `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://developer.android.com/resources/articles/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;
        }
    }
    

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

    这是我建议的方法。一方面,新的LoaderManager 类在很大程度上依赖于ContentProviders,所以如果你想要一个Activity 或Fragment 来实现LoaderManager.LoaderCallbacks<Cursor>(我建议你利用它,它很神奇!),你需要实现一个@ 987654329@ 为您的应用程序。此外,您无需担心使用 ContentProviders 创建 Singleton 数据库助手。只需从 Activity 中调用getContentResolver(),系统就会为您处理所有事情(换句话说,无需设计单例模式来防止创建多个实例)。

    希望有帮助!

    【讨论】:

    • 一些 cmets:#1 除了 Application 类在你的任何活动开始之前调用你什么都没有。 onTerminate() 永远不会被调用,所以它没用。 #3 如果您不打算将数据导出到其他应用程序,那么 CP 就大材小用了。您可以非常轻松地将 Loader 直接与 DB 一起使用,无需 CP。简而言之——单例是迄今为止大多数情况下最好的方法。
    • @NikolayElenkov,我同意 100%。当我写这篇文章时,我对 Android 的了解并不多,但随着时间的推移逐渐意识到你的所有 3 点:)。谢谢!
    • 感谢您的帖子。我选择了第三种方法,但是,我想在子类 Application 的 onCreate() 方法中使用 LoaderManager 加载数据,以使所有活动都可以访问(全局)。问题是我无法从应用程序上下文中调用 getSupportLoaderManager()。有什么想法吗? :(
    • @M.ES LoaderManager 用于管理Loader跨越Activity and Fragment 生命周期。也就是说,每个ActivityFragment 都有自己的LoaderManager 实例......所以你试图实现的目标并没有多大意义。在LoaderManager 上查看我的blog post 了解更多信息。
    【解决方案2】:

    你真的不需要关闭它。当您的进程终止时,它将自动关闭。除了使用 Application 对象外,您还可以将 DB 助手对象设置为单例以便于访问。顺便说一句,getWritableDatabase()getReadableDatabase() 并没有那么不同。唯一的区别是getReadableDatabase() 可能在你空间不足的情况下工作,而另一个会抛出异常。

    【讨论】:

      【解决方案3】:

      我不认为这是推荐的,如果有的话,你可以有一个 DataBaseOpenHelper 的全局实例,并在你实际需要数据库的地方调用 getWritableDatabase()。显然,只在需要时获取可写实例,否则使用 getReadableDatabase()。

      我不确定这背后的确切原因,但我猜这是获取和/或持有的昂贵对象,因此您不想在应用加载并持有时创建它一个全局实例。也许其他人可以澄清这一点。我希望 Android 文档能更好地解释这一点,因为我也有这样做的冲动。

      【讨论】:

      • 这很奇怪,亚历克斯,看起来你编辑了我的答案,从日志看来你只是用 dont 替换了 don't.. 不知道为什么。我在这个过程中损失了 10 个声望点。怎么会?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-12
      相关资源
      最近更新 更多