Activity and Background Service Access to SQLite Database - android

I want to check if a SQLite Database is open, and if it is, I would like to access that Database within a service class.
I am worried, and have seen, that multiple open calls to the database clash, and throw exceptions. Because I do query the database within both my Activity and Service classes, I am attempting to implement the solution Commonsware recommended here: When to close db connection on android? Every time after your operation finished or after your app exit. However I do not want to close then open the Database within the Service class if the Activity might need it. From this answer Why use SQLiteOpenHelper over SQLiteDatabase?, it looks like it might make sense to implement a SQLiteOpenHelper to solve the issue of making multiple calls.
Thank you so much for all your help!!

This man Kevin is a legend: http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection. Thank you so much.
On that link he shares his ridiculously simple solution:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static DatabaseHelper instance;
public static synchronized DatabaseHelper getHelper(Context context)
{
if (instance == null)
instance = new DatabaseHelper(context);
return instance;
}
//Other stuff...
}
Then in my SQLite class I changed my code to look like this:
public BlacklistWordDataSource(Context context) {
dbHelper = MySQLiteHelper.getHelper(context);
}

at onCreat in the activity put datasource.open();
then do what ever you want
and at the end of actevity put this to close :
/** Call after close activity */
#Override
protected void onStop() {
super.onStop();
//Close dataSource
datasource.close();
}

Related

OrmLite multithreading

I need to have an access to helper not only from Activities, but, for example, from BroadcastReceivers and AsyncTasks. Am I right, that if I am using OrmLiteBaseActivity to approach it is to use this methods:
OpenHelperManager.getHelper(context, DatabaseHelper.class);
OpenHelperManager.releaseHelper();
inside not Activity classes?
EDIT:
I understand that helper lifecycle is handled by OrmLiteBaseActivity. What I am asking is how to handle helper lifecycle outside of activities. For example, I need an access to database from BroadcastReceiver or AsyncTask. Is it a right way to achieve this using OpenHelperManager.getHelper(context, DatabaseHelper.class);, when I am starting some database stuff in another thread, and OpenHelperManager.releaseHelper();, when I've done all database work and want to release helper?
Am I right, that if I am using OrmLiteBaseActivity to approach it is to use this methods...
Yes, using the OpenHelperManager.getHelper(...) and releaseHelper() methods is the right way to do this. To quote from the ORMLite Android docs:
If you do not want to extend the OrmLiteBaseActivity and other base classes then you will need to duplicate their functionality. You will need to call OpenHelperManager.getHelper(Context context, Class openHelperClass) at the start of your code, save the helper and use it as much as you want, and then call OpenHelperManager.release() when you are done with it. You will probably want to have something like the following in your classes:
The sample code in the docs is:
private DatabaseHelper databaseHelper = null;
#Override
protected void onDestroy() {
super.onDestroy();
if (databaseHelper != null) {
OpenHelperManager.releaseHelper();
databaseHelper = null;
}
}
private DBHelper getHelper() {
if (databaseHelper == null) {
databaseHelper =
OpenHelperManager.getHelper(this, DatabaseHelper.class);
}
return databaseHelper;
}

Correctly open/close a database with Singleton design pattern

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.

Where to close SQLiteOpenHelper when opened in my application's onCreate?

I read that it was better to use only one SQLiteOpenHelper instance in a class extending Application:
public class MyApplication extends Application {
private static SQLiteOpenHelper dBHelper;
#Override
public void onCreate() {
super.onCreate();
dBHelper = new DBHelper(this);
}
public static SQLiteDatabase getDB() {
return dBHelper.getWritableDatabase();
}
}
but in that case, where should I close it?
Thanks
Jul
You should always have one and only one SQLOpenHelper instance and you should never close it. More detailed explanation can be found here and here
You may close the database in the onTerminate() method of the Application subclass. If your application can handle a closed database (by reopening ...) you can additionally close in the onLowMemory() method (but this will not free much memory).
More important is that you close any database cursors if you are finished using them.
EDIT
vmirnonov is right, onTerminate() is only called in the emulator, so ignore that part of the answer.

how should I open and close my database properly

I have an app which stores some data in a SQLite DB.Also I'm doing a lot of query an requery in my app.I have about 15 activities in it.And almoust all use the DB to query for data.
But what I'm doing is opening my DB in every activity and close it in onDestroy{...} of every activity.
The problem is that onDestroy{...} may never get called and sometimes my app stays on for a long time and I switch from an activity to another opening for to many times my DB.
And sometimes I get errors like-database too many times opened and never closed.
I would try to close my DB exactly after I get my data from it and close it...moving to my next activity and re-opening and so on.....
But the problem is that in some activities I come back from other activities....closing my DB and coming back to that activity would produce a big Force Close.
What I wanna do is open my DB at the beginning of my app and close it at the end of it, but I'm facing 2 problems:
1.
Should I make my SQLiteOpenHelper class a singleton?...get an instance of it..open it in my first activity and then in my following activities just get an instance of my DB which is already opened/???
2.Where is the end of my app????How should I know where is the end of my app and where to close my DB.
EDIT:
public class DBAdapter extends SQLiteOpenHelper {
public DBAdapter(Context context) {
super(context, DATABASE_NAME, null, 1);
this.myContext = context;
}
public void openDataBase() throws SQLException {
String myPath = DATABASE_PATH + DATABASE_NAME;
db = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
}
}
That is a piece of code from my class that manages my DB.To make this singleton I should use a constructor likw this:
private DBAdapter()
{
//nothing in here
}
But this is undefined for SQLiteOpenHelper
EDIT FINAL:
This is how I did it according with zirael advice:
package com.Server_1;
import android.app.Application;
public class MyApplication extends Application{
private static DBAdapter db;
public void onCreate()
{
db=new DBAdapter(getApplicationContext());
db.createDatabase();
db.openDataBase();
}
public static DBAdapter getDatabaseAdapter()
{
return db;
}
}
In every activity I where I need DB connection I do this:
MyApplication myApplication = (MyApplication) this.getApplication();
DBAdapter db= myApplication.getDatabaseAdapter();
And finally my manifest looks like:
<application android:icon="#drawable/icon"
android:label="#string/app_name"
android:name=".MyApplication"
android:debuggable="true">
In my app I open connection to database in myApplication class (your custom class that extends Application - it should be named the same as your application in androidManifest).
AndroidManifest.xml
<application android:label="#string/app_name"
android:name="com.mypackage.MyApplication " android:debuggable="true">
MyApplication .java
public class MyApplication extends Application {
private DatabaseAdapter dbAdapter;
#Override
public void onCreate() {
dbAdapter = new DatabaseAdapter(getApplicationContext());
dbAdapter.open();
}
And in each class that need db connection I simply use:
MyApplication myApplication = (MyApplication) this.getApplication();
DatabaseAdapter dbAdapter= myApplication.getDatabaseAdapter();
MyApplication is run automatically on every application start. This way I keep only one connection to DB so it's closed when app is being removed from memory without any problem.
When you retrieve your dbAdapter from you MyApplication class, do it in a lazy fashion, creating it only when needed. In my implementation, I also open it at this time.
public static DbAdapter getDbAdapter() {
if (dbAdapter == null) {
dbAdapter = new DbAdapter();
}
dbAdapter.open();
return dbAdapter;
}
It is a good idea to use getReadableDatabase() or getWriteableDatabase() in the open method of your database adapter.
Also, I think it works better to retrieve your adapter in onStart() and close it in onStop() of the activities where it is being used, rather than using onCreate() and onDestroy().
#Override
protected void onStop() {
super.onStop();
MyApp.closeDatabase();
}
And in the MyApp class...
public static void closeDatabase() {
dbAdapter.close();
}
If you are not managing your database in line with Google's recommendations, why not - there's usually a good reason why things are the way they are...
In any case, you can use getReadableDatabase() and getWriteableDatabase() - these functions will open the database if necessary, but just return the existing database object if it is already open, thus preventing you from opening the database multiple times.
Something you might try is use a singleton that each activity would attach to in its onResume() callback, and detach from in its onPause() callback. When the detach count reaches zero, set a timer which would get canceled in the attach method. If the timer expires, close the database.
There is a good answer from another question Best place to close database connection
"According to this post by a Google engineer, there's nothing wrong with leaving the database connection open:
Android made a deliberate design decision that is can seem surprising,
to just give up on the whole idea of applications cleanly exiting and
instead let the kernel clean up their resources. After all, the kernel
needs to be able to do this anyway. Given that design, keeping
anything open for the entire duration of a process's life and never
closing it is simply not a leak. It will be cleaned up when the
process is cleaned up.
So, for simplicity, I would extend the Application class to provide a single well-defined entry point for your code, and open the database connection in its onCreate(). Store the DB connection as a field in your Application, and provide an accessor method to make the connection available to rest of your code.
Then, don't worry about closing it."

Using singleton class for sharing instance of database between activities?

Hey! I want to use a singleton class, because if I open the database every activity I get "Leak found"( that happens because I open the database even if it is already open ) . I create a singleton class , but I don't know how should I use it.
Here is my class:
package com.ShoppingList;
import com.ShoppingList.databases.DbAdapter;
public class DbManager {
DbAdapter db;
// singleton
private static DbManager instance = null;
private DbManager() {
}
public static DbManager getInstance() {
if (instance == null)
instance = new DbManager();
return instance;
}
public void setinstance(DbAdapter db){
this.db=db;
}
public DbAdapter getinstancedb(){
return db;
}
}
In the first activity I put :
db = new DbAdapter(this);
db.open();
DbManager.getInstance().setinstance(db);
and for the next activity : DbManager.getInstance().getinstancedb(); but I get force close for second activity.
Can anyone help me how to use it? Thanks...
You can extend Application class and create there an instance of DbAdapter. This way it will be shared by all your activities.
Because db has the same context and life cycle of your first activity. Make your methods public and make them do all the setup/teardown necessary to return your desired result.
regarding the leak warning. Are you closing your db manager connection in onDestroy()?

Categories

Resources