android Sqlite多線程訪問異常解決方案

原文  http://www.cnblogs.com/wangmars/p/4530670.html

在開發Android的程序的時候sqlite數據庫是經常用到的;在多線程訪問數據庫的時候會出現這樣的異常: java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed . 或 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase : 或 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:

這樣的異常信息,Sqlite 自身是不支持多線程同時操作的,下面呢我們給出一個解決方案並列出一些項目中用到的代碼。

我們會用到AtomicInteger,一個提供原子操作的Integer的類。因爲Android 依託強大的jdk在使用的時候,不可避免的會用到synchronized關鍵字。而AtomicInteger則通過一種線程安全的加減操作接口,由此我們可以做一個DatabaseManager 這樣的類,具體代碼見下面的代碼塊:

public class DatabaseManager {  private AtomicInteger mOpenCounter = new AtomicInteger();  private static DatabaseManager instance;  
  private static SQLiteOpenHelper mDatabaseHelper;  
  private SQLiteDatabase mDatabase; 
  public static synchronized void initializeInstance(SQLiteOpenHelper helper) {  
    if (instance == null) {  
      instance = new DatabaseManager();  
      mDatabaseHelper = helper;  
    }  
  }  
  public static synchronized DatabaseManager getInstance(SQLiteOpenHelper helper) {  
    if (instance == null) {  
      initializeInstance(helper);    }  
    return instance;  
  }  
  public synchronized SQLiteDatabase getWritableDatabase() {  
    if(mOpenCounter.incrementAndGet() == 1) {  
      // Opening new database        mDatabase = mDatabaseHelper.getWritableDatabase();  
    }  
    return mDatabase;  
  }  
  public synchronized SQLiteDatabase getReadableDatabase() {  
    if(mOpenCounter.incrementAndGet() == 1) {  
      // Opening new database        mDatabase = mDatabaseHelper.getReadableDatabase();  
    }  
    return mDatabase;  
  }  
  public synchronized void closeDatabase() {  
    if(mOpenCounter.decrementAndGet() == 0) {  
      // Closing database        mDatabase.close();  
    }  
  }

在我們進行關閉數據庫的時候判斷

mOpenCounter.decrementAndGet() == 0 (更新器管理的給定對象的字段的當前值爲0)的時候才正式關閉數據庫,就不會出現上述異常。

用方式呢,在我們操作數據庫邏輯代碼中如下使用
首相要取得
mDatabaseManager = DatabaseManager.getInstance(mContext);
對象
/***
 * 判斷表中是否有值 */public boolean isExistTabValus() {  boolean flag = false;  SQLiteDatabase db = mDatabaseManager.getReadableDatabase();//獲取一個可讀的數據庫對象  Cursor curcor = null;  try {    curcor = db.rawQuery("select * from tab ", null);    while (curcor.moveToNext()) {      if (curcor.getCount() > 0) {        flag = true;      }    }  } catch (Exception e) {    Log.e(TAG, "isExistTabValus  error");  } finally {    if (curcor != null) {      curcor.close();    }    mDatabaseManager.closeDatabase();//關閉數據庫  }  return flag;
}

上面提供一個使用方法,現在項目中使用這種方法關於數據庫的操作從未沒有出現併發的問題,大家可以嘗試一下。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章