public class DatabaseHelper extends sqliteOpenHelper { ... }
// Thread 1 Context context = getApplicationContext(); DatabaseHelper helper = new DatabaseHelper(context); sqliteDatabase database = helper.getWritableDatabase(); database.insert(…); database.close(); // Thread 2 Context context = getApplicationContext(); DatabaseHelper helper = new DatabaseHelper(context); sqliteDatabase database = helper.getWritableDatabase(); database.insert(…); database.close();
android.database.sqlite.sqliteDatabaseLockedException: database is locked (code 5)@H_403_17@ 发生这种情况是因为你每次都创建了一个新的sqliteOpenHelper,实际上你每次都创建了一个数据库的连接。如果你在同一时间用不同的数据库连接来对同一的数据库进行写操作的话,那么其中一个会失败。 @H_403_17@
public class DatabaseManager { private static DatabaseManager instance; private static sqliteOpenHelper mDatabaseHelper; public static synchronized void initialize(Context context, sqliteOpenHelper helper) { if (instance == null) { instance = new DatabaseManager(); mDatabaseHelper = helper; } } public static synchronized DatabaseManager getInstance() { if (instance == null) { throw new IllegalStateException(DatabaseManager.class.getSimpleName() + " is not initialized,call initialize(..) method first."); } return instance; } public synchronized sqliteDatabase getDatabase() { return new mDatabaseHelper.getWritableDatabase(); } }@H_403_17@ 现在我们来看看执行结果 @H_403_17@
// In your application class DatabaseManager.initializeInstance(getApplicationContext()); // Thread 1 DatabaseManager manager = DatabaseManager.getInstance(); sqliteDatabase database = manager.getDatabase() database.insert(// Thread 2 DatabaseManager manager = DatabaseManager.getInstance(); sqliteDatabase database = manager.getDatabase() database.insert(…); database.close();@H_403_17@ 你的应用将会崩溃,异常信息如下 @H_403_17@
java.lang.IllegalStateException: attempt to re-open an already-closed object: sqliteDatabase@H_403_17@ 因为我们只使用一个数据库连接,Thread1和Thread2的都是由getDatabase()方法返回的相同连接。发生的什么事呢,在Thread2还在使用数据库连接时,Thread1可能已经把它给关闭了,那就是为什么你会得到崩溃异常。 @H_403_17@
Leak found
Caused by: java.lang.IllegalStateException: sqliteDatabase created and never closed@H_403_17@ 下面是一个样例程序 @H_403_17@
DatabaseManager { private AtomicInteger mOpenCounter = new AtomicInteger(); private static DatabaseManager instance; private static sqliteOpenHelper mDatabaseHelper; private sqliteDatabase mDatabase; public static synchronized initializeInstance(sqliteOpenHelper helper) { if (instance == null) { instance = new DatabaseManager(); mDatabaseHelper = helper; } } public static synchronized DatabaseManager ); } return instance; } public synchronized sqliteDatabase openDatabase() { if(mOpenCounter.incrementAndGet() == 1) { // opening new database mDatabase = mDatabaseHelper.getWritableDatabase(); } return mDatabase; } public synchronized closeDatabase() { if(mOpenCounter.decrementAndGet() == 0) { // Closing database mDatabase.close(); } }}@H_403_17@ 使用方式: @H_403_17@
sqliteDatabase database = DatabaseManager.getInstance().openDatabase(); database.insert(...); // database.close(); Don't close it directly! DatabaseManager.getInstance().closeDatabase(); // correct way@H_403_17@ 每当你需要使用数据库时,你需要使用DatabaseManager的openDatabase()方法来取得数据库。我们会使用一个引用计数来判断是否要创建数据库对象。如果引用计数为1,则需要创建一个数据库,如果不为1,说明我们已经创建过了。 @H_403_17@