你的位置:首页 > 操作系统

[操作系统]android Sqlite多线程访问异常解决方案


     在开发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;  }

上面提供一个使用方法,现在项目中使用这种方法关于数据库的操作从未没有出现并发的问题,大家可以尝试一下。