首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关闭ContentProvider中的数据库

关闭ContentProvider中的数据库
EN

Stack Overflow用户
提问于 2010-12-29 00:19:16
回答 6查看 24.6K关注 0票数 73

本周,我学习了所有关于ContentProvider的知识,并使用SQLiteOpenHelper类在提供者中管理数据库的创建和升级。具体地说,我一直在通读sdk的samples目录中的NotePad示例。

现在,我可以看到SQLiteOpenHelper有一个close()方法。我知道让空闲数据库保持开放是一种糟糕的做法,可能会导致内存泄漏等问题(除非this讨论的方向是正确的)。如果我在活动中使用这个类,那么我会简单地在onDestroy()方法中调用close(),但据我所知,ContentProvider没有与活动相同的生命周期。NotePad的代码似乎从未调用过close(),所以我假设它是由SQLiteOpenHelper或其他部分处理的,但我真的很想确认一下。我也不是很信任示例代码……

问题摘要:我们应该在什么时候关闭提供者中的数据库?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-10-04 02:59:16

According to Dianne Hackborn (安卓框架工程师)不需要关闭内容提供商中的数据库。

内容提供者是在创建其宿主进程时创建的,并且只要该进程存在,它就会一直存在,因此不需要关闭数据库--它将作为内核的一部分在进程终止时被关闭,以清理进程的资源。

感谢@bigstones指出这一点。

票数 96
EN

Stack Overflow用户

发布于 2012-08-09 13:34:59

这个问题有点老了,但仍然很相关。请注意,如果您使用“现代”方式(例如,在后台线程中使用LoaderManager和创建CursorLoaders来查询ContentProvider ),请确保不要在ContentProvider实现中调用db.close()。当CursorLoader/AsyncTaskLoader试图在后台线程中访问ContentProvider时,我遇到了各种与CursorLoader/AsyncTaskLoader相关的崩溃,这些问题通过删除db.close()调用得到了解决。

因此,如果你遇到类似下面这样的崩溃(Jelly Bean 4.1.1):

代码语言:javascript
复制
Caused by: java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
    at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
    at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:677)
    at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
    at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
    at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:143)
    at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
    at android.content.ContentResolver.query(ContentResolver.java:388)
    at android.content.ContentResolver.query(ContentResolver.java:313)
    at com.hindsightlabs.paprika.loaders.GroceryListLoader.loadInBackground(GroceryListLoader.java:147)
    at com.hindsightlabs.paprika.loaders.GroceryListLoader.loadInBackground(GroceryListLoader.java:1)
    at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240)
    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51)
    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40)
    at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    ... 4 more

或者这个(ICS 4.0.4):

代码语言:javascript
复制
Caused by: java.lang.IllegalStateException: database /data/data/com.hindsightlabs.paprika/databases/Paprika.db (conn# 0) already closed
    at android.database.sqlite.SQLiteDatabase.verifyDbIsOpen(SQLiteDatabase.java:2215)
    at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:436)
    at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:422)
    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:79)
    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164)
    at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:156)
    at android.content.ContentResolver.query(ContentResolver.java:318)
    at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:49)
    at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:35)
    at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240)
    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51)
    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40)
    at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    ... 4 more

或者,如果您在LogCat中看到类似以下内容的错误消息:

代码语言:javascript
复制
Cursor: invalid statement in fillWindow()

然后检查您的ContentProvider实现,并确保您没有过早关闭数据库。根据this的说法,当进程被杀死时,ContentProvider将被自动清理,所以你不需要提前关闭它的数据库。

也就是说,请确保您仍然是正确的:

  1. 关闭从ContentProvider.query()返回的游标。(CursorLoader/LoaderManager会自动为你做这件事,但是如果你在LoaderManager框架之外做直接查询,或者你已经实现了一个自定义的CursorLoader/AsyncTaskLoader子类,你必须确保你正在以线程安全的方式清理你的游标properly.)
  2. Implementing你的ContentProvider。(要做到这一点,最简单的方法是确保您的数据库访问方法包装在同步块中。)
票数 21
EN

Stack Overflow用户

发布于 2012-01-28 19:08:39

我看了Mannaz的回答,发现SQLiteCursor(database, driver, table, query);构造函数被弃用了。然后,我找到了getDatabase()方法,并用它代替了mDatabase指针;并保留了用于向后功能的构造函数

代码语言:javascript
复制
public class MyOpenHelper extends SQLiteOpenHelper {
    public static final String TAG = "MyOpenHelper";

    public static final String DB_NAME = "myopenhelper.db";
    public static final int DB_VESRION = 1;

    public MyOpenHelper(Context context) {
        super(context, DB_NAME, new LeaklessCursorFactory(), DB_VESRION);
    }

    //...
}

public class LeaklessCursor extends SQLiteCursor {
    static final String TAG = "LeaklessCursor";

    public LeaklessCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
            String editTable, SQLiteQuery query) {
        super(db, driver, editTable, query);
    }

    @Override
    public void close() {
        final SQLiteDatabase db = getDatabase();
        super.close();
        if (db != null) {
            Log.d(TAG, "Closing LeaklessCursor: " + db.getPath());
            db.close();
        }
    }
}


public class LeaklessCursorFactory implements CursorFactory {
    @Override
    public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
        String editTable, SQLiteQuery query) {
        return new LeaklessCursor(db,masterQuery,editTable,query);
    }
}
票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4547461

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档