Assuming you have your own sqliteopenhelper:
1 Public class extends Sqliteopenhelper {...}
Now you want to the write data to database in separate threads:
1 //Thread 12Context context =Getapplicationcontext ();3Databasehelper helper =NewDatabasehelper (context);4Sqlitedatabase Database =helper.getwritabledatabase ();5 Database.insert (...);6 database.close ();7 8 //Thread 29Context context =Getapplicationcontext ();TenDatabasehelper helper =NewDatabasehelper (context); OneSqlitedatabase Database =helper.getwritabledatabase (); A Database.insert (...); -Database.close ();
You'll get following message in your logcat and one of your changes would not be written:
Android.database.sqlite. Sqlitedatabaselockedexception5)
This is happening because every time to create new SQLiteOpenHelper
object you are actually making new database connection. If you try to write to the database from actual distinct connections at the same time, one would fail.
To use the database with multiple threads we need to make sure we is using one database connection.
Let's make Singleton class which would hold and DatabaseManager
return a single SQLiteOpenHelper
object.
1 Public classDatabasemanager {2 3 Private StaticDatabasemanager instance;4 Private StaticSqliteopenhelper Mdatabasehelper;5 6 Public Static synchronized voidinitializeinstance (Sqliteopenhelper helper) {7 if(Instance = =NULL) {8Instance =NewDatabasemanager ();9Mdatabasehelper =Helper;Ten } One } A - Public Static synchronizedDatabasemanager getinstance () { - if(Instance = =NULL) { the Throw NewIllegalStateException (Databasemanager.class. Getsimplename () + -"Isn't initialized, call initialize (..) Method first. "); - } - + returninstance; - } + A Public synchronizedsqlitedatabase getdatabase () { at returnmdatabasehelper.getwritabledatabase (); - } - -}
Updated code which write data to database in separate threads would look like this.
1 //In your application class2Databasemanager.initializeinstance (NewDatabasehelper ());3 4 //Thread 15Databasemanager Manager =databasemanager.getinstance ();6Sqlitedatabase Database =manager.getdatabase ()7 Database.insert (...);8 database.close ();9 Ten //Thread 2 OneDatabasemanager Manager =databasemanager.getinstance (); ASqlitedatabase Database =manager.getdatabase () - Database.insert (...); -Database.close ();
This would bring you another crash:
Java.lang. IllegalStateException: Attempt to re-open an already-closed objectsqlitedatabase
Since we is using only one database connection, method getDatabase()
return same instance of the object for and SQLiteDatabase
Thread1
Thread2
. What are happening, may Thread1
close database, and while is Thread2
still using it. That's why we have IllegalStateException
crash.
We need to make sure No-one are using database and only then close it. Some folks on Stackoveflow recommended to never close your SQLiteDatabase
. This would honor you with following logcat message. So I don ' t think the is good idea at all.
Leak foundcaused byJava.lang. IllegalStateExceptionSqlitedatabase created and never closed
Working sample:
1 Public classDatabasemanager {2 3 PrivateAtomicinteger Mopencounter =NewAtomicinteger ();4 5 Private StaticDatabasemanager instance;6 Private StaticSqliteopenhelper Mdatabasehelper;7 Privatesqlitedatabase mdatabase;8 9 Public Static synchronized voidinitializeinstance (Sqliteopenhelper helper) {Ten if(Instance = =NULL) { OneInstance =NewDatabasemanager (); AMdatabasehelper =Helper; - } - } the - Public Static synchronizedDatabasemanager getinstance () { - if(Instance = =NULL) { - Throw NewIllegalStateException (Databasemanager.class. Getsimplename () + +"Isn't initialized, call Initializeinstance (..) Method first. "); - } + A returninstance; at } - - Public synchronizedsqlitedatabase OpenDatabase () { - if(Mopencounter.incrementandget () = = 1) { - //Opening New Database -Mdatabase =mdatabasehelper.getwritabledatabase (); in } - returnmdatabase; to } + - Public synchronized voidcloseDatabase () { the if(Mopencounter.decrementandget () = = 0) { * //Closing Database $ mdatabase.close ();Panax Notoginseng - } the } +}
and use it as follows.
1 sqlitedatabase database = 2 database.insert (...); 3 Database.close (); Don ' t close it directly! 4 databasemanager.getinstance (). CloseDatabase (); // correct"
Every time need database you should call openDatabase()
method of DatabaseManager
class. Inside This method, we had a counter, which indicate how many times database is opened. If it equals to one, it means we need to the create new database, if not, the database is already created.
The same happens in closeDatabase()
method. Every time we call the This method, counter was decreased, whenever it goes to zero, we are closing database.
Now you should is able to use your database and is sure-it ' s thread safe.
From:github
Secure access to databases under Android multithreading (Concurrent database access)