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);
}
}
Related
I would like to have a database for each user of my app. Usernames are stored in SharedPreferences. So I'm looking for something like this:
public class DatabaseHelper extends SQLiteOpenHelper {
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
String LoggedInUser = sp.getString("user","");
public static final String DATABASE_NAME = LoggedInUser + ".db";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
public void onCreate(SQLiteDatabase db) {
...
}
...
}
But this doesn't work, because SharedPreferences need context (using getApplicationContext() instead of this doesn't work either. This can be solved by something like this:
private Context appContext;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
this.appContext = context;
}
And then accessing SharedPreferences afterwards.
But I need to access SharedPreferences before this method ("DATABASE_NAME" is used in the above method and I want to define "DATABASE_NAME" using SharedPreferences).
Is there any way for doing this?
Since call to super() must be first statement, the only solution to achieve it would be to pass the DATABASE_NAME as constructor parameter:
public DatabaseHelper(final Context context, final string dbName) {
super(context, dbName, null, 1);
}
You can then either implement factory or Facade pattern to construct or pass the value to DatabaseHelper or simply pass the dbName value from Activity/Fragment.
An example of Factory could be:
public final class DatabaseFactory {
public static DatabaseHelper getDataBaseHelper(final Context context){
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
final String loggedInUser = sp.getString("user","");
return new DatabaseHelper(context,loggedInUser);
}
}
In Activity you can access the Helper as follows:
public class MainActivity extends Activity{
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
final DatabaseHelper myDB = DatabaseFactory.getDataBaseHelper(this);
...
}
}
Must you use SharedPreference in you SQLiteOpenHelper?
I think you maybe use SQLite in your Activity, then how about declare SharedPreference in your Activity first, and get that in your SQLite through database's constructor.
I am trying to better understand what it means to open an Sqlite database on a background thread in Android. Right now I am using a static/singleton pattern for my database via my class DatabaseHelper, so I only need to open it once, but I want to open it using good practice and understand why I shouldn't open it directly from within my Activity directly (or within the helper's constructor, for example).
My class:
public class DatabaseHelper extends SQLiteOpenHelper {
private static volatile SQLiteDatabase mDatabase;
private static DatabaseHelper mInstance = null;
private static Context mContext;
// ...
public static synchronized DatabaseHelper getInstance(Context context) {
/**
* use the application context as suggested by CommonsWare.
* this will ensure that you don't accidentally leak an Activity's
* context (see this article for more information:
* http://android-developers.blogspot.nl/2009/01/avoiding-memory-leaks.html)
*/
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
private DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_CREATE_SOME_TABLE); //some SQL expression
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(DB_ALTER);
}
public void open() throws SQLException {
mDatabase = getWritableDatabase();
}
public void close() {
mDatabase.close();
}
public boolean isOpen() {
return mDatabase.isOpen();
}
//below this would be various CRUD functions operating on mDatabase
// ...
// ...
}
Is it correct to say that you should do something like this:
DatabaseHelper mDatabaseHelper = DatabaseHelper.getInstance(this);
Thread thread = new Thread("OpenDbThread") {
public void run(){
mDatabaseHelper.open();
}
};
thread.start();
inside an Activity somewhere?
You're correct that the code you wrote would open the database on a background thread. However, you wouldn't actually the database was opened until thread.isAlive() returned false (or mDatabase.isOpen() returned true). Alternatively, you could make your Activity listen for a callback from your Thread.
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();
I'm using Ormlite has my database for my android application. I have now been given requirements to create a container to be able to hold multiple databases. I do not know before hand how many databases I will need as the number of databases by the container will be dynamic. I've reviewed ormlite's multiple database code, but that is if you know how many databases you have before hand and you create one class per database. I don't have that information available to me. So the question is, how can I create a DatabaseHelper class with ormlite to handle multiple different databases and still be thread safe? All the databases hold the exact same type of data, just different data per container.
DatabaseHelper code:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final int DATABASE_VERSION = 1;
private Dao<MyData, Integer> myDataDao;
private static final AtomicInteger usageCounter = new AtomicInteger(0);
private volatile static DatabaseHelper helper = null;
public DatabaseHelper(Context context, String dynamicDBName)
{
super(context, dynamicDBName, null, DATABASE_VERSION);
}
public static DatabaseHelper getHelper(Context context, String dynamicDBName)
{
if (helper == null)
{
synchronized (DatabaseHelper.class)
{
// double check lock to prevent method from being synchronized
// requiring sync lock only being used once
if (helper == null)
helper = new DatabaseHelper(context, dynamicDBName);
}
}
usageCounter.incrementAndGet();
return helper;
}
#Override
public void close()
{
if (usageCounter.decrementAndGet() == 0)
{
super.close();
helper = null;
}
}
}
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
}
}
}