It is thread safe to use single instance of database by all activities of my Applications. And if i do so, when should i close the database connection.
Please recommend the right method to use SqliteOpenHelper .
I've been using an approach I found in an online course and haven't had a slightest issue with it. Just put a synchronized keyword for your database instance so that multiple threads could manage it at the same time. This is what I am using:
synchronized static AppDatabase getInstance(Context context) {
if (instance == null) {
instance = new AppDatabase(context.getApplicationContext());
}
return (instance);
}
Related
In my application, I am using a single instance of the Helper class which means that I have only one database connection.
public static MyHelper getInstance(Context context) {
if (instance == null) {
synchronized (MyHelper.class) {
if (instance == null) {
instance = new MyHelper(context);
}
}
}
return instance;
}
And as I am using only one connection, all my operations to the database will be serialized. It means that even if I am using multiple threads there is no need for me to take care of synchronization. It will be taken care by Sqlite. But strangely sometimes I am getting the exception that the database is locked. So what can be the reason for this exception ? How can this exception be avoided ?
I created a class that uses 1 SOUNDPOOL to play musical notes. The problem is that there are a lot of notes and thus loading takes too long. I'd like to know if it was possible to use a single instance of the class in several activities to avoid having to recreate my music player each time.
have you heard of Singleton Design Pattern? Have a look at Wikipedia. Following this design pattern will ensure you have ever created only one instance of the class and all other classes will reuse this only instance.
Use Singletone design pattern
public class ClassicSingleton {
private static ClassicSingleton instance = null;
protected ClassicSingleton() {
// Exists only to defeat instantiation.
}
public static ClassicSingleton getInstance() {
if(instance == null) {
instance = new ClassicSingleton();
}
return instance;
}
}
As the other said, use Singleton. In fact, Android provides a Singleton object already, which is the Application. You may want to use that.
Is there any advantage in keeping a local sqlite connection open the entire time that the activity is running?
I usually create a new connection and then close it within every method that does a database operation. It would look something like this :
myMethod(Context context){
LocalDBHelper localDBHelper = new LocalDBHelper(context); //extended SQLiteOpenHelper
SQLiteDatabase db = localDBHelper.getWritableDatabase();
...
localDBHelper.close();
}
So in a typical user session, this would happen around 10 times. Would it make sense to create a connection in onResume(), use that in all the database access methods and finally close it in onPause()?
Is there any advantage in keeping a local sqlite connection open the entire time that the activity is running?
You usually want one "connection" for the entire life of your process. In particular, you do not want to have multiple "connections" in use simultaneously across multiple threads. All of the thread-safety logic for SQLite in Android is based around using a single SQLiteDatabase (and, hence, single SQLiteOpenHelper) for all of those threads, so proper locking can be done.
Based on #CommonsWare answer, i have implemented a Singleton pattern to have a single application wide instance of LocalDBHelper using lazy instantiation. It works fine till now and avoids the need to instantiate and close the helper/database for every operation.
public class MyApplication extends Application{
private static MyApplication instance;
public MyApplication(){
instance = this;
}
public static Context getContext(){
return instance;
}
}
public class LocalDBHelper extends SQLiteOpenHelper{
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "MyDB";
private static final String LOG_TAG = "LocalDBHelper";
private static LocalDBHelper instance = null;
/*private constructor to avoid direct instantiation by other classes*/
private LocalDBHelper(){
super(MyApplication.getContext(), DATABASE_NAME, null, DATABASE_VERSION);
}
/*synchronized method to ensure only 1 instance of LocalDBHelper exists*/
public static synchronized LocalDBHelper getInstance(){
if(instance == null){
instance = new LocalDBHelper();
}
return instance;
}
...
...
}
Usage :
SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
db.insert(...)
Usage with transactions :
SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase();
db.beginTransaction();
try{
....
...
db.setTransactionSuccessful();
}catch(Exception e){
e.printStackTrace();
}
finally{
db.endTransaction();
}
Important : No need to call localDBHelper.getInstance().close() anywhere
As your app works on the same machine every time it is luanched and the same memory is accessed every time, so there will be no problem to let it be open. because in the same memory space , sqlite just loads like a DLL for a main application.
Just one problem may occur! when you wanna run many threads for accessing database at the same time(for example with AsyncTask) the interference between them forces some threads to stop! so its better to make connection for new threads eachtime!
Personally I find it easier to call the SQL Connections required on the initial app load, to store into the SQLite DB's, and either set a refresh button for the user to decide when they want to refresh the data, OR set a periodic update interval timer for the application.
By doing it this way, you are increasing performance during general usage of the app by placing the data load on a pre/user defined time.
Although I do suppose this depends on how often a DB Interaction is going to be performed....
This Question may ahve some useful answers for you:
Should I open() and close() my SQL database constantly or leave it open?
Is there a way to change what database an SQLiteOpenHelper object uses without having to force every class that uses the helper to replace their instance of the class?
The reason why I'm changing the database is because I have some live data and some offline data in two separate databases with identical table structures. I update the offline data and then swap them, allowing me to lock the offline database on big inserts.
You must use the singleton pattern to acces to your database with only one instance
it's look like
public class SingletonDemo {
private static SingletonDemo instance = null;
private SingletonDemo() { // do what you want here}
public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class) {
if (instance == null) {
instance = new SingletonDemo();
}
}
}
return instance;
}
...
// Add all the class function you need here
}
This is thread safe and can be use every where you need.
I am creating an application which makes a lot of interactions with a database (both read and write operations).
To avoid open/close operations at each request, I created a class extending SQLiteOpenHelper with a Singleton design pattern. This way, I am sure only one instance of the SQLiteOpenHelper and only one connection to the database is made during all the application lifecycle (and not only activity lifecycle).
I also read some articles about ContentProvider, but I am not sure it's a better way.
So, this is the main logic of my Singleton class (onCreate and onUpgrade removed) :
public final class BaseSQLite extends SQLiteOpenHelper {
private static BaseSQLite mInstance = null;
private SQLiteDatabase db = null;
public static BaseSQLite getInstance(Context context) {
if (mInstance == null) {
mInstance = new BaseSQLite(context.getApplicationContext(),
DBNAME, DBVERSION);
}
return mInstance;
}
private BaseSQLite(final Context context, final String name,
final int version) {
super(context, name, null, version);
db = getWritableDatabase();
}
#Override
public synchronized void close() {
if (mInstance != null)
db.close();
}
public Cursor getAllData() {
String buildSQL = "SELECT * FROM myTable";
return db.rawQuery(buildSQL, null);
}
}
So, to access my database, I made this :
BaseSQLite baseSQLite = BaseSQLite.getInstance(context);
baseSQLite.getAllData();
It works perfectly for now. But my question is about the close() method. I really don't know when to call it. Actually, my database instance is the same for every Activies of my application, so I think it's a bad idea to call close() in an onPause() method, because the instance will be potentially (and it will often happens) recreated in the onStart() method of the next Activity. Also, I can't detect the end of my application, i.e. when no activity is visible on the screen anymore.
Can somebody give me some help about this issue ? I found some answer when the database is linked to ONE activity, but no really hint is given for my case.
You should call close anytime you are done writing to your database. For example when you insert data, you will have an open connection to the database that should be closed when it is done.
Reading is different. When you create a SQLite database on your phone, the data is persistent. The database exists and the handler you create provides a convenient way to access that information. Reading the database usually takes place by getting a readable instance of the database and using a Cursor to extract values. In that case you close the cursor when you're done, not the database itself.
You're right that you should not be closing the database connection during separate activities' lifecycle methods. Instead, as suggested above, close the database connection in your handler's methods that write to the database when you are done performing that transaction.