Android database helper singleton - instantiate in activity or all fragments? - android

I have a DBHelper class set up as a singleton:
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);
databasePath = context.getDatabasePath(DATABASE_NAME).getPath();
}
}
I have a MainActivity and a number of fragments. Many of these fragments need access to my DBHelper methods
Should I be using dbHelper = DBHelper.getInstance(getApplicationContext()) in every fragment that needs database access? Instantiation will only happen once due to the singleton pattern, so I don't need to worry about the class being instantiated in every single fragment with that code
Or is it better to instantiate the DBHelper in MainActivity only, and then in any fragment that needs database access get a reference to the mainactivity and call the object methods from there? Something like this in each fragment:
mainActivity = (MainActivity) getActivity();
mainActivity.dbHelper.insertData();

Since you are sure Singleton will be instantiated in MainActivity the first approach shouldn't have any problems, you could even call getInstance(null) in your fragments

I think the most prodcutive decision will be create custom fragment class, extend it your fragment or v4.fragment, initialise in it dbHelper and use your custom fragment in your activity. it is my humble opinion :)

Codes here is one simple way to resolve concurrent problem in singleton pattern.
public DBHelper extends SQLiteOpenHelper {
// declare private constructor
// some public method
public static class Wrapper {
private static DBHelper dbHelper;
public static void init(Context ctx, Object otherArgs) {
// init DBHelper
dbHelper = new DBHelper(ctx, otherArgs);
}
public static DBHelper get(){
return dbHelper;
}
}
}
In custom Application
public MyApp extends Application{
void onCreate(){
DBHelper.Wrpper.init(this, otherArgs);
}
}
Code like this where DBHelper is needed:
DBHelper.Wrapper.get().insertData();

Related

How to use handle multiple fragment to use method

I have method select() was defined in class DBHelper that extend SQLiteOpenHelper , in MainActivity I initiated the dtabases variable dbHelper :
DBHelper dbHelper = new DBHelper(this, "DB");
I have 4 fragments each one need to call the method select() , How to do that ??
second in each fragment do I need to do the definition of the dbHelper in each fragment or is there a way to get it from the MainActivity in other words defined it once.
DBHelper dbHelper = new DBHelper(getActivity(), "DBTEST");
SQLiteDatabase db =dbHelper.getReadableDatabase();
This is the select() method :
public Cursor selectdb(String tsql) {
DBHelper dbHelper = new DBHelper(getActivity(), "DBTest");
SQLiteDatabase db =dbHelper.getReadableDatabase();
Cursor c = db.rawQuery(tsql, null);
db.close();
return c;
}
You can follow this recipe:
define an interface for retrieving the DBHelper:
public interface DBHelperSource {
DBHelper getDBHelper();
}
Declare your activity to implement the interface and implement the method to return your activity's DBHelper object.
public class MyActivity extends Activity implements DBHelperSource {
...
private DBHelper mDBHelper;
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDBHelper = new DBHelper(this, "DBTest");
...
}
#Override public DBHelper getDBHelper() {
return mDBHelper;
}
...
}
In each fragment's onAttach(Context) method, cast the context to DBHelperSource, retrieve the DBHelper object, and stash it in an instance variable for that fragment.
public class MyFragment extends Fragment {
private DBHelper mDBHelper;
...
#Override public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof DBHelperSource) {
mDBHelper = ((DBHelperSource) context).getDBHelper();
}
}
#Override public void onDetach() {
super.onDetach();
mDBHelper = null;
}
}
For more information on this pattern, see the Android tutorial Communicating with Other Fragments.
There's one little gotcha: if there's a chance that the fragment is attached before the activity instantiates the DBHelper object, then you'd probably want to alter the above as follows. Instead of initializing a DBHelper field in onAttach(), just store the DBHelperSource object itself as a field. Then only call getDBHelper() when you need the DBHelper object itself (i.e., just when you're ready to call select()).
Another approach is to just define the interface to contain the select method itself, and don't bother communicating the DBHelper object to the fragments. Of course, this only works if the logic is identical among all four fragments.

How to initialize context where we cannot get context from getApplicationContext()?

I want to access a class extending SQLiteOpenHelper to get the context of database from a java class. I need to pass application context to get that but don`t have access to getApplicationContext().
How can I get Application Context in java class that is not activity?
I suggest you create a constructor that has a parameter of the Context type.
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
// Variables
private Context ctx;
public MySQLiteOpenHelper(Context ctx) {
this.ctx = ctx;
}
//More code
}
Now, in your activities, you can do this:
MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
And in your fragments, you can do this:
MySQLiteOpenHelper helper = new MySQLiteOpenHelper(getActivity().getApplicationContext()); //getActivity() would work too, Activity (indirectly) extends Context.
You can create custom Application class and write method getContext().
Someting like this:
public class MyApplication extends Application {
private static MyApplication mCurrentInstance;
#Override
public void onCreate() {
super.onCreate();
mCurrentInstance = this;
}
public static MyApplication instance() {
return mCurrentInstance;
}
public static Context context() {
return mCurrentInstance.getApplicationContext();
}
}
And add this class into manifest:
<application
android:name=".MyApplication">

Ormlite - Access Two Databases from the same activity

I have an Android app where I need to access two different databases from the same activity.
I am using Ormlite to read from/write to database.
public class MyActivity extends OrmLiteBaseActivity<MyDatabaseHelper>
I need to use another database helper for the other database.
Can anyone direct me on how to achieve this?
Should I use the same DatabaseHelper and make modifications there to support both databases? Or is there a way to use different databaseHelpers in the same activity?
In your case I think that the better solution is to use separate helpers and not to extend OrmLiteBaseActivity.
public class DatabaseHelperA extends OrmLiteSqliteOpenHelper {
public static DatabaseHelper getInst(){
return inst;
}
public static void init(Context c){
if (inst == null) inst = OpenHelperManager.getHelper(c, DatabaseHelperA.class);
}
public DatabaseHelper(Context context) {
super(context, "a.db", null, 1);
}
}
public class DatabaseHelperB extends OrmLiteSqliteOpenHelper {
public static DatabaseHelper getInst(){
return inst;
}
public static void init(Context c){
if (inst == null) inst = OpenHelperManager.getHelper(c, DatabaseHelperB.class);
}
public DatabaseHelper(Context context) {
super(context, "a.db", null, 1);
}
}

Android how to start a database operation from a broadcast receiver if I cannot pass application context

In my app, when a Broadcast Receiver does what it does, I want to start a database operation as well, but the class that handles the database operation reqiures an instance of the DB singleton, which I usually hold in the application object, which is not accessible through the service context
Here is what happens:
This is my database handler:
public class DatabaseManager extends SQLiteOpenHelper {
// Its a good practice for DBTools to be a singleton. Do not instantiate it with "new DBTools(context)" but with
// DBTools.getInstance(context) instead
private static DatabaseManager sInstance;
public SQLiteDatabase database;
public static DatabaseManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new DatabaseManager(context);
}
return sInstance;
}
public DatabaseManager(Context context) {
super(context, Preferences.LOCAL_SQLITE_DATABASE_NAME, null, 1);
}
In my Application Class I instatiate it this way:
// SQLite Database Handler
public DatabaseManager databaseManager;
#Override
public void onCreate() {
super.onCreate();
databaseManager = DatabaseManager.getInstance(this);
in my receiver I want to start a database operation:
public class PushNotificationReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//DatabaseManager databaseManager = DatabaseManager.getInstance(context); -> This didnt work when the database was closed in onDestroy of my app.
new IncrementProgressIntoDB(context, eventId).execute();
and this is IncrementProgressIntoDB
public class IncrementProgressIntoDB extends AsyncTask<Void, Void, Boolean> {
private int eventId;
private Context context;
public IncrementProgressIntoDB(Context context, int eventId) {
this.context = context;
this.eventId= eventId;
}
#Override
protected Boolean doInBackground(Void... params) {
((MyApplication) context).databaseManager.database.beginTransaction();
and in this last line, I get the following exception:
06-02 10:45:00.552: E/AndroidRuntime(7778):
Caused by: java.lang.ClassCastException: android.app.ReceiverRestrictedContext
cannot be cast to com.asdqwe.asd.MyApplication
I tried the solution from here: Static way to get 'Context' on Android?
but the context that I got was unable to resolve the databaseManager as a field.
In the onReceive() method of your BroadcastReceiver, replace:
new IncrementProgressIntoDB(context, eventId).execute();
with:
new IncrementProgressIntoDB((MyApplication)context.getApplicationContext(), eventId).execute();
Try this. It should work.

Database initialization error in static method

I have database class. The class and its constructor are shown below.
public class LatLogDBAdapter {
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
I want to use the database in the static method. So that I declare as private static LatLogDBAdapter dbHelper;. Then when i initialize, i have problem. dbHelper = new LatLogDBAdapter(this); dbHelper = new LatLogDBAdapter(DetailMapView.this); make compile error. How can I use this in static method?
If you want to create static method that returns your dbhelper i suggest you to create normal subclass of SQLiteOpenHelper and in this class create public static method that will return new instance. This also is sounds like good reason to use design pattern Singleton
Update:
I mean I want to use this database class inside another java class.
That class has static method and use the database.
Here i create for you basic snippet of code:
public class AdapterWrapper {
private static SQLiteOpenHelper instance;
public static SQLiteOpenHelper getInstance(Context c) {
if (instance == null) {
instance = new DatabaseHelper(c);
}
return instance;
}
private static class DatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "Example";
private static final int DB_START_VERSION = 1;
public DatabaseHelper(Context cntx) {
super(cntx, DB_NAME, null, DB_START_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// creating tables
}
#Override
public void onUpgrade(SQLiteDatabase db, int old, int new) {
/// drop an upgrading db
}
}
}

Categories

Resources