how to manage database open close in so many fragments - android

HI i am using an application in that there is so many fragments all fragments are using database, I just want to know how to manage database open close in this situation
I have more than 10 fragments which are using database should i have to open close database for each fragment or should I have to open database once app start and then close at the end of application
if that possible then how please explain me

You can simply create a Singleton helper which you can use throughout the lifecycle of the application as noted here.
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper sInstance;
private static final String DATABASE_NAME = "database_name";
private static final String DATABASE_TABLE = "table_name";
private static final int DATABASE_VERSION = 1;
public static DatabaseHelper getInstance(Context context) {
// Use the application context, which will ensure that you
// don't accidentally leak an Activity's context.
// See this article for more information: http://bit.ly/6LRzfx
if (sInstance == null) {
sInstance = new DatabaseHelper(context.getApplicationContext());
}
return sInstance;
}
/**
* Constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}

Yes both way you can do this as per your requirement if you want to open database throughout all fragment then open it in Parent Activity onCreate method and Close it to OnDestroy method.
Or
Open Database in onAttach method in fragment and close in onDetach method that's it...

Related

Handling SQLite singleton instances and its Context dependency in Android

I am currently working on an Android project that performs a lot of communication with the SQLite database. I am also trying to implement a MVP framework within the app.
My current implementation of the Singleton instance is similar to the following. (taken from this post: https://github.com/codepath/android_guides/wiki/Local-Databases-with-SQLiteOpenHelper )
public class PostsDatabaseHelper extends SQLiteOpenHelper {
private static PostsDatabaseHelper sInstance;
public static synchronized PostsDatabaseHelper getInstance(Context context) {
if (sInstance == null) {
sInstance = new PostsDatabaseHelper(context.getApplicationContext());
}
return sInstance;
}
private PostsDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
With the existing code above, I call the getInstance method in several Presenter classes, passing into each of them the Context object which was passed on from the Activity/Fragment. The Context objects can be passed across multiple classes.
Instead of the code above, I was thinking of instantiating the databaseHelper only once at the start of the Application, and then all references will then point to a variant of the getInstance method without the context dependency.
EDIT: My main aim here is to remove as much as possible, the presence of the Context object in the Presenter classes, so as to make the code 'cleaner'. Because all the calls to getInstance provide/inject the same type of Context (the Application's context and not an Activity-specific context), I don't see a need to put the Context object as an argument.
public class PostsDatabaseHelper extends SQLiteOpenHelper {
private static PostsDatabaseHelper sInstance;
// called by all other classes
public static synchronized PostsDatabaseHelper getInstance() {
if (sInstance == null) {
//throw error
}
return sInstance;
}
// only called once at the start of the Application
public static void instantiateInstance(Context context){
sInstance = new PostsDatabaseHelper(context.getApplicationContext());
}
private PostsDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
What I would like to know is, will there be any downsides to this approach? Thanks!
You are trading lazy initialization for static initialization.
In general, lazy initialization can amortize the cost of initialization over the life of an application. In this case it seems less important, for two reasons:
It is almost certain that you will need this DB. It seems unlikely that by putting the initialization off, you might avoid having to do it at all.
The Android framework guarantees that the DBHelper constructor can be run from the UI thread: it is not what takes the time. The thing that takes the time is the first call to getWriteableDatabase. The lazy creation of the Helper accomplishes almost nothing.
You might consider making the code even less convoluted, by initializing the DB in the Application like this:
public class DBDrivenApp extends Application implements DBProvider {
// ...
private PostsDatabaseHelper db;
// ...
#Override
public void onCreate() {
super.onCreate();
db = new PostsDatabaseHelper(this);
}
#Override
public PostsDatabaseHelper getDB() { return db; }
// ...
}
... and, better yet, use an IoC framework, like Dagger2, to inject the database instance, so that you can mock it in testing.

Should the context of SQLiteOpenHelper always be the running activity?

I want to open the database once only from the main screen of my app , and I want to use this instance anywhere in any activity. Is that possible or should I make the context to be each actual opened activity so that I must create an instance of the database ( open ) in every activity ?
Is that possible or should I make the context to be each actual opened
activity so that I must create an instance of the database ( open ) in
every activity ?
it is possible, and you could use the application context. Your DBHelper could be a singleton. E.g
public class DBHelper extends SQLiteOpenHelper {
private static DBHelper sInstance;
public static synchronized DBHelper getInstance(Context context) {
if (sInstance == null) {
sInstance = new DBHelper(context.getApplicationContext());
}
return sInstance;
}
private DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
You do not need to close and re-open the SQL connection per each individual Activity.
Having said that - it is best to open the connection using an app context, to avoid Activity leaks.
You can get an app context refrence quite easily.

SQLiteOpenHelper variable initialization/use throughout the app

I have a little concern about how I handle my database in my apps, here is basically what I do:
I have a custom class extending SQLiteOpenHelper that handles all the transactions with the DB.
In my app, I have one single Activity and several Fragments that are created, deleted, hidden or shown during the process.
In every Fragment where I need to modify or access data from the DB, I declare a static variable:
private static DatabaseHandler mDB;
And I initialize it this way on the onCreate() methods:
mDB = DatabaseHandler.getInstance(getActivity());
All this is working, my concern is about the variable itself, is it a good idea to declare it as a static variable in all my custom fragment classes?
I also use the same way a class containing the main parameters of the app using mParams = Parameters.getInstance(getActivity());, should I also declare it as static?
I want to avoid memory leaks and NPE but I am not sure what is the right way to handle that.
FYI, the beginning of my DatabaseHandler class:
public class DatabaseHandler extends SQLiteOpenHelper {
private static DatabaseHandler sInstance = null;
(...)
private Resources mResources;
public static DatabaseHandler getInstance(Context context) {
if (sInstance == null) {
sInstance = new DatabaseHandler(context);
}
return sInstance;
}
private DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mResources = context.getResources();
}
(...)
Thank you
I normally create a SQLiteDatabase static instance in my Application class and access across the app.
So , I have a custom class which returns SQLiteDatabase instance on application create.
This is my Application class
public class MainApplication extends Application {
private static SQLiteDatabase mSQLiteDatabase = null;
#Override
public void onCreate(){
super.onCreate();
SQLiteAsyncTask sqLiteAsyncTask = new SQLiteAsyncTask(getApplicationContext());
mSQLiteDatabase = (SQLiteDatabase) sqLiteAsyncTask.loadInBackground();
}
// method to get the sqlite db instance
public SQLiteDatabase getSQLiteInstance(){
return mSQLiteDatabase;
}
}
Now you can get the SQLiteDatabase instance from Activity or Fragment , by
MainApplication.getSQLiteInstance()

Android Global SQLite Database Access

I am trying to make my SQLite database globally accessible throughout my Android application using a singleton pattern:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "foo";
private static final int DATABASE_VERSION = 1;
private static MySQLiteOpenHelper instance;
private MySQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public static MySQLiteOpenHelper getInstance(Context context) {
if (instance == null) {
instance = new MySQLiteOpenHelper(context);
}
return instance;
}
public static MySQLiteOpenHelper getInstance() throws UnsupportedOperationException {
if (instance == null) {
throw new UnsupportedOperationException();
}
return instance;
}
...
The idea here is that the first call is to getInstance(Context context) passing in the Application object. Thereafter I can just use getInstance() where I can't get a handle on a Context object.
However, I come unstuck when I make the initial MySQLiteOpenHelper.getInstance(getApplication()) call:
java.lang.IllegalStateException: getDatabase called recursively
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:204)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
Can anyone shed any light on what is happening here or suggest a better technique for achieving my goal?
Cheers!
The code you posted is just fine.
java.lang.IllegalStateException: getDatabase called recursively
This is caused when you call e.g. getWritableDatabase() recursively.
One common cause for it is to call getWritableDatabase() in database helper onCreate(). The onCreate() gets invoked when getWritableDatabase() is called and the database does not exist. Calling getWritableDatabase() again is an error. You should use the writable SQLiteDatabase passed to onCreate() as an argument instead.
Your MySQLiteOpenHelper should works fine.
That class is not the problem.

correct use of SQLiteOpenHelper (and some consultation)

I have the following code below.
I am creating a database in my application that uses SQLiteOpenHelper.
I have couple of concerns and would appreciate some consults.
Direct answers for these were not found on stack overflow as they might be subjective.
1 - I will be using this database from several activities. However I am not planning on making this a singleton to avoid leaks, but rather I will be getting the getWritableDatabase() and getReadableDatabase() inside each method. I plan on doing a db.close() inside each activity's onDestroy() .Is this advisable ? given my app has couple of activites and is not a huge app.
2 - I am not following and DAO model, nor I am using a different class for every table.
The way I see it, I don't need to. Do I ?
3 - (A question rather than consult)
In the code below, I am not creating a database of the form
private SQLiteDatabase database;
So all the references to the database (from my activities) are being done via the methods in the same subclassed SQLiteOpenHelper, therefore I am referencing the physically created database directly via getWritableDatabase and getReadableDatabase.
Do I need to create an instance of SQLiteDatabase and use it ? Even inside the subclass of SQLiteOpenHelper ?
Below is the code.
public class DbHelper extends SQLiteOpenHelper
{
private static final String DATABASE_NAME = "myDbName";
private static final String DATABASE_TABLE = "myTable";
private static final int DATABASE_VERSION = 1;
private Context ctx;
public DbHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.ctx = context;
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL("CREATE TABLE myTable(_id INTEGER PRIMARY KEY, title TEXT);");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
//nothing here now. maybe later.
}
public void insertTitle(String title)
{
ContentValues titleCV = new ContentValues();
titleCV .put("title", title);
getWritableDatabase().insert(DATABASE_TABLE, null, titleCV );
}
public void getTitles()
{
Cursor result = getReadableDatabase().rawQuery("SELECT _id, title FROM myTable", null);
while (result.moveToNext())
{
int id = result.getInt(0);
String titleGotten= result.getString(1);
}
result.close();
}
Q1
If you have a scenario within your app that have two parallel threads accessing the database, use a single instance of the SQLiteOpenHelper (singleton or member in the Application or whatever). If not you don't need to.
about calling db.close(), if it is in the onDestroy(), then it's fine.
Q2
a DAO is an abstraction layer to ease maintaining and scaling your project. If you are not going to scale or maintain your code (upcoming releases or something), then I suppose you don't need one.
Q3
You don't need to create an instance of SQLiteDatabse. when you call getReadableDatabase() or getWritableDatabase(), SQLiteOpenHelper creates and maintains an instance. The same instance is used the next time you call getReadable\WritableDatabase().
let me know if you still have questions.
step 1: make a staic instace of SqliteOpenHelper
step 2: you never close conexion to database, sqlite manage itself the sequencial access to write or read :)
private static ControladorBBDD instancia;
my class: public class ControladorBBDD extends SQLiteOpenHelper {
default :
private ControladorBBDD(Context ctx_p) throws Exception {
super(ctx_p, DB_NAME, null, DATABASE_VERSION);
try {
ControladorBBDD.ctx = ctx_p;
DB_PATH = ctx.getDatabasePath(DB_NAME).getAbsolutePath();
String myPath = DB_PATH;// + DB_NAME;
this.createDataBase();
db = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException ex) {
Conexiones.escribirLog(Log.getStackTraceString(ex),
ctx.getString(R.string.versionReal));
db.close();
}
}
and my way to implement a conexion to database:
public static synchronized ControladorBBDD getBBDD(Context ctx_p)
throws Exception {
if (instancia == null) {
instancia = new ControladorBBDD(ctx_p);
}
return instancia;
}
and to call it from activities:
dblectura = ControladorBBDD.getBBDD(getApplicationContext());
where private ControladorBBDD dblectura;
i hope that it helps, important thing is that you use applicationContext, no Activity context ;))
well if i were u i would create a class and the dbhelper as a subclass then i would use a open and a close function for main class and also the insert
whenever i want to use database i do it like this
mainclass mc=new mainclass(this);
mc.open();
mc.insert();
mc.close();

Categories

Resources