【问题标题】:Android- java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closedAndroid- java.lang.IllegalStateException: 无法执行此操作,因为连接池已关闭
【发布时间】:2015-02-27 06:43:45
【问题描述】:

我正在阅读有关此问题的 stackoverflow,但仍未找到解决方案。有时我的应用程序会遇到这个问题。这是我的错误日志,

12-31 10:58:28.025: E/AndroidRuntime(16322): FATAL EXCEPTION: Timer-0
12-31 10:58:28.025: E/AndroidRuntime(16322): java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:1031)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:746)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:400)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:905)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:144)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:197)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:237)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at com.eyepax.horseapp.data.dbadapters.ContactGroupDbAdapter.getContactGroups(ContactGroupDbAdapter.java:138)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at com.eyepax.horseapp.data.DataManager.getGroups(DataManager.java:1548)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at com.eyepax.horseapp.sync.ContactSync.contactGroupSync(ContactSync.java:43)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at com.eyepax.horseapp.service.SynchingService.callSync(SynchingService.java:77)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at com.eyepax.horseapp.service.SynchingService.access$0(SynchingService.java:70)
12-31 10:58:28.025: E/AndroidRuntime(16322):    at com.eyepax.horseapp.service.SynchingService$1.run(SynchingService.java:57)

这是在 ContacGroupDbAdapter 类中崩溃的方法,

/**
 * Returns ContactGroup.
 * 
 * @return ArrayList<ContactGroup>
 */
public ArrayList<ContactGroup> getContactGroups() {

    this.open();
    Cursor cursor = database.rawQuery("SELECT * FROM " + TABLE_NAME, null);
    ArrayList<ContactGroup> list = null;

    if (cursor != null && cursor.moveToFirst()) {
        list = new ArrayList<ContactGroup>();

        do {
            try {
                ContactGroup contactGroup = new ContactGroup();
                contactGroup.setGroupId(cursor.getString(cursor.getColumnIndex(GROUP_ID)));
                contactGroup.setGroupName(cursor.getString(cursor.getColumnIndex(GROUP_NAME)));
                contactGroup.setIsDeleted(cursor.getInt(cursor.getColumnIndex(GROUP_IS_DELETED)));
                contactGroup.setUpdatedDate(cursor.getString(cursor.getColumnIndex(GROUP_UPDATE_DATE)));
                contactGroup.setIsSync(cursor.getInt(cursor.getColumnIndex(GROUP_IS_SYNC)));

                list.add(contactGroup);
            } catch (Exception e) {

            }
        } while (cursor.moveToNext());

    }

    if (cursor != null)
        cursor.close();
    return list;
}

并且它在 cursor.moveToFirst() 行中因此错误而崩溃。请帮我解决这个问题。

我使用单独的 BaseDbAdapter 类来关闭数据库,

public class BaseDbAdapter {

/**
 * Application context.
 */
protected Context context;

/**
 * Database.
 */
protected SQLiteDatabase database;

/**
 * Database helper class.
 */
protected SQLiteDataBaseHelper dbHelper;

/**
 * StringBuilder
 */
protected StringBuilder stringBuilder;

public static final String CREATE_TABLE_PRE_TEXT = "create table if not exists ";
/**
 * Returns StringBuilder object.
 * 
 * @return
 */
protected StringBuilder getStringBuilder() {
    if (stringBuilder == null) {
        stringBuilder = new StringBuilder();
    }

    return stringBuilder;
}

/**
 * Opens a connection to the database.
 * 
 * @throws SQLException
 */
public synchronized void open() throws SQLException {
    dbHelper = SQLiteDataBaseHelper.getInstance(context);
    database = dbHelper.getWritableDatabase();
}

/**
 * Closes the connection.
 */
public synchronized void close() {
    database.close();
}

public static String getDeleteTableStatement(String tableName) {
    return "DELETE TABLE " + tableName;
}

}

我使用了 SQLiteDataBaseHelper 类,它的 getInstance 方法更改为同步。
as this answer 但问题仍未修复。

 /**
 * Get an instance of SQLiteDataBaseHelper.
 * 
 * @param context
 * @return SQLiteDataBaseHelper
 */
public static synchronized SQLiteDataBaseHelper getInstance(Context context) {

    // if(dbName == null) {
    // dbName = DataManager.getSQLiteDatabaseName(context);
    // }

    if (instance == null) {
        instance = new SQLiteDataBaseHelper(context);

    }

    return instance;
}

【问题讨论】:

  • 你在哪里关闭你的数据库?
  • 我使用单独的 BaseDbAdapter 类来关闭数据库检查我编辑的问题
  • 将 getContactGroups 移动到 BaseDbAdapter

标签: android database multithreading sqlite thread-safety


【解决方案1】:
    public ArrayList<ContactGroup> getContactGroups() {
       ArrayList<ContactGroup> list = null;
        try {
                // TODO Auto-generated method stub
                SQLiteDatabase database = this.getWritableDatabase();
        Cursor cursor = database.rawQuery("SELECT * FROM " + TABLE_NAME, null);
         if (cursor != null && cursor.moveToFirst()) {
            list = new ArrayList<ContactGroup>();


                try { 
                     while (cursor.moveToNext())
                    {
                    ContactGroup contactGroup = new ContactGroup();
                    contactGroup.setGroupId(cursor.getString(cursor.getColumnIndex(GROUP_ID)));
                    contactGroup.setGroupName(cursor.getString(cursor.getColumnIndex(GROUP_NAME)));
                    contactGroup.setIsDeleted(cursor.getInt(cursor.getColumnIndex(GROUP_IS_DELETED)));
                    contactGroup.setUpdatedDate(cursor.getString(cursor.getColumnIndex(GROUP_UPDATE_DATE)));
                    contactGroup.setIsSync(cursor.getInt(cursor.getColumnIndex(GROUP_IS_SYNC)));

                    list.add(contactGroup);
                       }
                } catch (Exception e) {

                } 


        } 

        if (cursor != null)
    {
            cursor.close();
        database.close();
    }
    } catch (Exception e) {

                }

        return list;
    } 

try this effort

【讨论】:

  • 你把这段代码放在哪里
  • 我把这些代码放在 ContactGroupDbAdapter 类中,它扩展了 BaseDbAdapter 类。
  • 将 getContactGroups 移至 BaseDbAdapter
【解决方案2】:

我认为问题在于synchronization。当多个线程访问时,会对数据库的状态产生误解。

您应该避免将数据库作为实例变量,而是在您的帮助程序类(最好是扩展 SQLiteOpenHelper)中将其设为本地方法。获取数据库并对其进行处理的示例如下所示:

public void addContact(Contact contact) {
    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put(KEY_NAME, contact.getName()); // Contact Name
    values.put(KEY_PH_NO, contact.getPhoneNumber()); // Contact Phone Number

    // Inserting Row
    db.insert(TABLE_CONTACTS, null, values);
    db.close(); // Closing database connection
}

请查看本教程:Android SQLite Database Tutorial

以下是一个建议的示例,说明如何干净利落:

public class DatabaseHelper extends SQLiteOpenHelper {

    ......

    // no need to synchronize
    public Cursor getBookList(){
        SQLiteDatabase db = getReadableDatabase(); // or getWritableDatabase()
        Cursor c = db.query(BookEntry.TABLE_NAME, null, null, null, null, null, BookEntry.COLUMN_NAME + " ASC");
        return c;
    }

    // no need to override close method, because that one is very well coded already
    // SQLiteOpenHelper will close any opened database, with its service close method.
}

public class SomeAdapter{


    // no need to synchronize, as all DatabaseHelper instances are method local
    public int getBookCount(){
        DatabaseHelper dbHelper = new DatabaseHelper(context);
        Cursor c = dbHelper.getBookList();
        int rowCount = c.getCount();
        c.close();  // close the cursor once used.
        dbHelper.close(); // ask the helper to close any open database.
        return rowCount;

    }

}

请在此处检查 SQLiteOpenHelper.java:SQLiteOpenHelper.java 然后你就会知道数据库(mDatabase)是如何通过getReadableDatabase()、getWritableDatabase()和close()等方法维护的。

【讨论】:

  • 我使用了 SQLiteDataBaseHelper 类,它的 getInstance 方法已同步更改。查看我编辑的问题。
  • 非静态方法和静态方法上的同步会有不同的锁。 open 和 close 方法将锁定在 Adapter 对象上。 SQLiteDataBaseHelper 的 getInstance 方法将锁定 SQLiteDataBaseHelper 类对象。
  • 我已经为你添加了一个提议的设计,并链接了 SQLiteOpenHelper 源代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 2013-04-10
  • 2014-06-16
  • 2016-02-11
  • 2013-02-05
  • 2017-10-23
  • 2015-04-02
相关资源
最近更新 更多