Hey
I'm building an Android app that contains a database.
My question is how can I know whether the app was updated?
I mean, I know the onUpgrade method is called when the DATABASE_VERSION from -
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, DATABASE_VERSION);
this.myContext = context;
}
is lower than the version of the app, but how do I increment it after the update, so the app won't update itself all the time?
You don't need to take care of keeping track of the version number. After onUpgrade() has been called, android takes care of all this stuff automatically. onUpgrade() will automatically be called when the next update is due (i.e. you increased DATABASE_VERSION once again).
To be even more clear: Just keep a static final int DATABASE_VERSION field, which you increase at development time, everytime you change something essential on the database structure.
You create a class that extends SQLLiteOpenHelper which basically looks like this:
public class ContentDatabase extends SQLiteOpenHelper {
// Whenever you change the DB structure, increment DATABASE_VERSION (it starts from 1, so your first upgrade should be 2)
// - note it's only used for upgrades; if it's a new install, onUpgrade won't be called and everything is done by onCreate instead
private static final int DATABASE_VERSION = 6;
public ContentDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
// Code to create the most recent version of your database
// i.e. CREATE TABLE xxx (....)
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Code to update an existing database structure to the most recent
// version.
if (oldVersion < 2) {
// do something to upgrade the DB to version 2
}
if (oldVersion < 3) {
// do something to upgrade the DB to version 3
}
if (oldVersion < 6) {
// Let's assume you added a new table in v4, and then added a field to that new table in v6
if (oldVersion < 4) {
// add the v6 version of the new table to the DB
}
else {
// add the new field to the existing v4 table in the DB
}
}
}
}
Everytime you need to change the structure of the table (i.e. add aditional columns or tables) you increase the DATABASE_VERSION variable by one and write code accordingly for the onCreate() and onUpdate() methods. These methods are called automatically by android.
Consider using SharedPreferences in the application context, you can keep track of lastVersion in there and your application will check it onCreate() to see if lastVersion matches the version of this application.
It is persistent between updates but not between installs.
you can make it so version 0 equates to not having it which you require you to setup the new database. By using SharedPreference mPref = getSharedPreference(String,int)
You can then have code like
if(mPref.getInt("DB_VERSION", 0) == 0 ) {
no db yet so create one
} else { db is there,
if (mPref.getInt("DB_VERSION",0) != DATABASE_VERSION) {
do some special update stuff here
}
}
Related
I'm new to Android Studio and SQLite and wanted to run a query when the app is run for the very first time only, and when the app is run again it wont run the query again.
This will depend upon how you are accessing the database.
The most common way is to utilise the SQLiteOpenHelper class. In which case the onCreate method is called when the database is created. The database only ever being created the once (unless it is deleted e.g. the App uninstalled).
When onCreate is called the database will have been created BUT will not have any components (tables, indexes, views, triggers) other than some system components. Typically this is where the components are created but meets the criteria of your question IF using a class that extends SQLiteOpenHelper. However, unless the query is to store data, it would probably be of little use as there would be no data to query.
However, using a class that extends SQLiteOpenHelper is not the only way in which an SQLite database can be accessed, nor would onCreate be called if you were utilising a pre-existing database copied from the assets folder of the package (e.g. using SQLiteAssetHelper).
In these latter cases, you could test to see if the database actually exists and set a flag/indicator. If it does not and then after opening the database you could then check the indicator and run the query.
Demonstration
Here's a demonstration of two methods.
The first using the more typical SQLiteOpenHelper and thus the onCreate method.
The second using an indicator.
The first method utilises a class that extends SQLiteOpenHelper called DBHelper :-
class DBHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "thedatabase.db";
public static final int DATABASE_VERSION = 1;
private static volatile DBHelper instance;
private DBHelper(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
this.getWritableDatabase(); //Force database open
}
public static DBHelper getInstance(Context context) {
if (instance==null) {
instance = new DBHelper(context);
}
return instance;
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
// Run the query here AFTER creating the components
Log.d("DBHELPER","First run detected");
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
Rather than run a query, data is written to the log from within the onCreate method.
The second method utilises the SQLiteDatabase openOrCreateDatabase (i.e. circumventing using the SQLiteOpenHelper). Thus it has to do some of the things that SQLiteOpenHelper conveniently does automatically:-
class OtherDBHelper {
public static final String DATABASE_NAME = "otherdatabase.db";
public static final int DATABASE_VERSION = 1;
private static boolean databaseCreateIndicator = false;
private static boolean databaseVersionChanged = false;
private SQLiteDatabase database;
private static OtherDBHelper instance;
private OtherDBHelper(Context context) {
if (!context.getDatabasePath(DATABASE_NAME).exists()) {
databaseCreateIndicator = true;
File database_dir = context.getDatabasePath(DATABASE_NAME).getParentFile();
if (!database_dir.exists()) {
database_dir.mkdirs();
}
// Copy database from assets
}
database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath(DATABASE_NAME),null);
//* Database now open */
// If utilising Version number check and set the version number
// If not copying pre-existing database create components (tables etc)
if (databaseCreateIndicator) {
//<<<<<<<<<< Query here >>>>>>>>>>
Log.d("OTHERDBHELPER","First run detected");
}
}
public SQLiteDatabase getSQLiteDatabase() {
return database;
}
public static OtherDBHelper getInstance(Context context) {
if (instance==null) {
instance = new OtherDBHelper(context);
}
return instance;
}
}
again the instead of running a query outputting to the log is used.
To test both in unison then some activity code:-
public class MainActivity extends AppCompatActivity {
DBHelper dbHelper;
OtherDBHelper otherDBHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("PREDBMSG","Just prior to getting the databases.");
dbHelper = DBHelper.getInstance(this);
otherDBHelper = OtherDBHelper.getInstance(this);
Log.d("POSTDBMSG","Just after getting the databases.");
}
}
Results
When run for the first time then the log includes:-
2022-10-20 07:09:27.633 D/PREDBMSG: Just prior to getting the databases.
2022-10-20 07:09:27.663 D/DBHELPER: First run detected
2022-10-20 07:09:27.697 D/OTHERDBHELPER: First run detected
2022-10-20 07:09:27.697 D/POSTDBMSG: Just after getting the databases.
When run again :-
2022-10-20 07:10:41.258 D/PREDBMSG: Just prior to getting the databases.
2022-10-20 07:10:41.266 D/POSTDBMSG: Just after getting the databases.
I have a SQLite database powering all the content in an Android app.
I have a DatabaseHelper class that extends SQLiteAssetHelper.
I have been having problems with too many instances of my database and then getting a SQLiteCantOpenDatabaseException.
To counter this, I have changed my class to maintain a single instance of the DatabaseHelper object.
I have the following:
private static DatabaseHelper databaseHelper;
public static synchronized DatabaseHelper getInstance(Context context, boolean singleRow, boolean showLoader){
if(databaseHelper == null) {
databaseHelper = new DatabaseHelper(context, singleRow, showLoader);
}
return databaseHelper;
}
public DatabaseHelper(Context context, boolean singleRow, boolean showLoader){
super(context, (new File(DatabaseManager.getDatabasePath(context))).getName(), (new File(DatabaseManager.getDatabasePath(context))).getParentFile().getAbsolutePath(), null, DATABASE_VERSION);
this.context = context;
this.singleRow = singleRow;
this.showLoader = showLoader;
}
I then call the getInstance static method as follows:
DatabaseHelper databaseHelper = DatabaseHelper.getInstance(activity.getApplicationContext(), false, false);
After a certain amount of database activity, the app is still crashing on memory grounds.
I then get this error:
Error Code : 2062 (SQLITE_CANTOPEN_EMFILE)
Caused By : Application has opened two many files. Maximum of available file descriptors in one process is 1024 in default.
(unable to open database file (code 2062))
Having taken the singleton approach, I'm a bit lost for why this is still causing this memory leak.
Any help would be appreciated.
If you are getting a message indicating too many files open, a cause may well be that there are too many Cursor that are still open.
However, the message returned may not always be the same and is probably specific to the task/call being called.
In this case the message was (unable to open database file (code 2062)), yet in another case (from a SELECT the message was unable to open database file (code 14)). SQLite unable to open database file (code 14) on frequent “SELECT” query.
The above link also points to a post I made what quite clearly shows that creating a Cursor results in a file (or files) being opened.
The example was looping through about 500 rows and for each row it was creating/recreating 3 cursors for each row (so potentially 1500+ cursors even though only using 4 cursor objects).
Initially it was only closing the 3 cursors at the end (last row of the parent of all) resulting in the unable to open database File (code 14). Closing the 3 cursors for each iteration resolved the issue.
The code that failed was :-
SQLiteDatabase db = getWritableDatabase();
Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
Cursor productcsr;
Cursor aislecsr;
Cursor prdusecsr;
while(shoplistcursor.moveToNext()) {
productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
}
if(shoplistcursor.isLast()) {
prdusecsr.close();
aislecsr.close();
productcsr.close();
}
}
shoplistcursor.close();
db.close();
}
Whilst the fixed code was :-
SQLiteDatabase db = getWritableDatabase();
Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
Cursor productcsr;
Cursor aislecsr;
Cursor prdusecsr;
while(shoplistcursor.moveToNext()) {
productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
productcsr.close();
aislecsr.close();
prdusecsr.close();
deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
} else {
productcsr.close();
aislecsr.close();
prdusecsr.close();
}
}
shoplistcursor.close();
db.close();
}
I tend to now follow the following rule/practice :-
If just getting the result e.g. getting the number of rows, close the Cursor in the method.
If using the Cursor for a display e.g. a ListView, then close the cursor in the activity's onDestroy method.
If using the Cursor for what I'll call more complex processing e.g. deleting rows with underlying references then close the cursors as soon as they are done with, within the processing loop(s).
I really don't know why and really got curious about "Application has opened two many files" error and would like to know what causes it.
However, i use singleton with database without any issues over a year. I used this snippet to get database with singleton in 14 apps and never had any problems.
public class DatabaseManager {
private AtomicInteger mOpenCounter = new AtomicInteger();
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
private DatabaseManager() {
}
public static synchronized DatabaseManager getDatabaseManager(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
return instance;
}
public static synchronized DatabaseManager getDatabaseManager(Context context) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = new DatabaseOpenHelper(context.getApplicationContext());
}
return instance;
}
/**
* Get a writable database
*/
public synchronized SQLiteDatabase openDatabase() {
if (mOpenCounter.incrementAndGet() == 1) {
// Opening new database
mDatabase = mDatabaseHelper.getWritableDatabase();
// System.out.println("DataBaseManager: Database Opened");
} else {
// System.out.println("DataBaseManager: Database Already Open");
}
return mDatabase;
}
public synchronized void closeDatabase() {
if (mOpenCounter.decrementAndGet() == 0) {
// Closing database
mDatabase.close();
// System.out.println("DataBaseManager: Database Closed");
} else {
// System.out.println("DataBaseManager: Database is NOT Closed");
}
}
}
onCreate() i get instance with mDatabaseManager = DatabaseManager.getDatabaseManager(getActivity().getApplicationContext());, onStart() i open database with mDatabaseManager.openDatabase();, and onStop() close it with mDatabaseManager.closeDatabase();
I do the singleton approach as well. There are two ways to access your Data obviously.
You can use a Cursor to populate a list of objects and then close your cursor and then close your DB.
Unless you are returning the cursor for dynamic paging of content because of larger list.
Whether or not to close your connection is contingent upon frequency of usage and your app's specific needs.
However, if you are accessing from new context and sharing the previously created SQLHelper class you could be creating memory leak issues as the constructor requires the context.
It sounds to me like you have too many files open on that single connection though. Have you considered closing your db connection after each interaction. Example:
public static ArrayList<OrderModel> getOrders(Context context){
ArrayList<OrderModel> orderList = new ArrayList<OrderModel>();
SQLiteDatabase db = null;
try{
db = A35DBHelper.openDatabase(context);
String columns[] = {
"*"
};
Cursor cursor = db.query(OrdersTable.TABLE_NAME, columns, OrdersTable.COLUMN_PRIMARY_ID, null, null, null, null);
if (cursor != null) {
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()){
OrderModel order = new OrderModel();
order.setLocalDatabaseId(cursor.getLong(cursor.getColumnIndex(OrdersTable.COLUMN_PRIMARY_ID)));
order.setID(cursor.getString(cursor.getColumnIndex(OrdersTable.COLUMN_REPAIR_ORDER_NUMBER)));
order.setOrderNumber(cursor.getString(cursor.getColumnIndex(OrdersTable.COLUMN_ORDER_NUMBER)));
order.setCreatedAtDate(cursor.getString(cursor.getColumnIndex(OrdersTable.COLUMN_CREATED_AT_DATE)));
order.setImageCount(MediaDataContext.getAllMediaForOrderId(context, order.getID()).size());
order.setDefaultThumbnailUrl(cursor.getString(cursor.getColumnIndex(OrdersTable.COLUMN_DEFAULT_THUMBNAIL_URL)));
orderList.add(order);
}
cursor.close();
}
} catch (Exception ex) {
A35Log.e(TAG, "Failed to get orders: " + ex.getMessage());
}
A35DBHelper.closeDatabase(db);
return orderList;
}
Then my singleton class has the open and close where if the context has changed I new up a new instance of the helper before opening.
Then I use the CloseUtil for try/catch closing each time.
This can still be the same if you are returning the Cursor Object instead of an ArrayList as you are possibly getting dynamic data that handles paging or is to big to fill a list.
But sounds like to me your connection is getting over worked so you may need to revisit your model.
I have my database created in event onCreate, in which I have a lot of tables, but I need add 1 more table, and I can't lose any data, So I need to use the event onUpgrade, So I hope you guys help me because I don't know how to use it.
Example :
public void onCreate(SQLiteDatabase db) {
sql = "CREATE TABLE IF NOT EXISTS funcionarios"
+"(codigo INTEGER PRIMARY KEY, funcionario TEXT, apelido TEXT , functionTEXT, cartao TEXT , foto TEXT , tipo_foto TEXT);";
db.execSQL(sql);
}
what i need is
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(oldVersion < 2){
db.execSQL("CREATE TABLE IF NOT EXISTS calibrar_aceleracao"+
"(limiteMaximo INTEGER, limiteMinimo INTEGER);");
}
}
but it doesn't work.
thanks.
You do not need to change you applications version to update your database - not saying it is incorrect but there is a more efficient way of doing it. And that is through the use of the super's constructor of your helper it would look something like the following:
public class MyDatabaseHelper extends SQLiteOpenHelper {
public MyDatabaseHelper(Context context) {
super(context, "My.db", null, 1 /* This is the version of the database*/);
}
#Override
public void onCreate(SQLiteDatabase database) {
sql = "CREATE TABLE IF NOT EXISTS funcionarios (codigo INTEGER PRIMARY KEY, funcionario TEXT, apelido TEXT , functionTEXT, cartao TEXT , foto TEXT , tipo_foto TEXT);";
db.execSQL(sql);
}
#Override
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
if(oldVersion < 2){
db.execSQL("CREATE TABLE IF NOT EXISTS calibrar_aceleracao (limiteMaximo INTEGER, limiteMinimo INTEGER);");
}
}
}
The method onUpgrade is called when your version database is incremented. Verify in your class where you define your database version and increment this value.
Run application. Your method onUpgrade is called.
For onUpgrade to get called you must increase the database version that you supply to the SqliteOpenHelper implementation constructor.
Use a field in your class to store the same and increment it when you change your database schema.
This is not the way onUpgrade works.This is a method which will be called when you release some new version of your application and make it available for download in google play(and which may be requiring some updations to the database of the application already installed on users' devices').For your problem's solution
Just add the query of CREATE TABLE IF NOT EXISTS in your onCreate() as you did for the creation of the other table in your onCreate() method already
public void onCreate(SQLiteDatabase db) {
sql = "CREATE TABLE IF NOT EXISTS funcionarios"
+"(codigo INTEGER PRIMARY KEY, funcionario TEXT, apelido TEXT , functionTEXT, cartao TEXT , foto TEXT , tipo_foto TEXT);";
///HERE YOUR Create Table QUERY and call db.execSQL
db.execSQL(sql);
}
The method is onUpgrade is not being called probably because there are errors in the sql code, for example in the onCreate:
functionTEXT
is missing a space before TEXT.
Also after,
calibrar_aceleracao"+ "(limiteMaximo
is missing a space before the bracket.
I had the same problem, I was caching the SQLiteException so I didn't see the error was there.
Put some logcat at the beginning and at the end of the method body and you'll see where the error is.
EDIT: another thing, why did you put that if?
if (oldVersion < 2)
It's not necessary at all.
I have used LogCat to determine the problem line.
The SQL String I am trying to execute in onCreate is..
CREATE TABLE Routines(_id integer primary key autoincrement, json TEXT);
When it tries to execute this, the problem occurs.
This may well be whats causing the NullPointerException. If you can't see anything wrong with that, please read on for a bit more background.
This database has not been created yet, I keep getting a NullpointerException, I have compared this to previous SQLite code and the problem is proving evasive.
However, I mention this as it still has to go through the onCreate method. I create a new DatabaseOpenHelper (extending SQliteOpenHelper) in my main code and call the helper's open() method as seen below.
public void open() throws SQLException
{
ssDatabase = databaseOpenHelper.getWritableDatabase();
}
If I am not mistaken, as my database has not been created (I made sure of that through uninstalling it prior). The onCreate SQLiteHelper is invoked when that open() method is called.
This is the code where I call that open method.
try
{
dbConnector = new DatabaseConnector (this);
debug = "2 ";
// This on first start will invoke the database onCreate method - throws SQLException
dbConnector.open(); /* PROBLEM LINE */
debug = "3 ";
}
catch (Exception e)
{
textView1.setText(debug + e.toString());
}
And this is the code containing my DatabaseOpenHelper and onCreate method
private class DatabaseOpenHelper extends SQLiteOpenHelper
{
public DatabaseOpenHelper(Context context, String name, CursorFactory factory, int version)
{
super(context, name, factory, version);
Log.i(TAG, "Constructor");
}
// On initial creation of database
#Override
public void onCreate(SQLiteDatabase db)
{
Log.i(TAG, "Before SQL command");
String sqlCreateCommand = "CREATE TABLE Routines"
+ "(_id integer primary key autoincrement, "
+ "json TEXT);";
Log.i(TAG, sqlCreateCommand);
// I believe this to be the PROBLEM LINE
ssDatabase.execSQL(sqlCreateCommand);
Log.i(TAG, "Jab done");
}
// On upgrade - currently do nothing
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{}
}
Thanks for the help!
seems like i dont have the prvilege to just post a comment. One question: ssDatabase.execSQL(sqlCreateCommand); --> shouldn't this be db.execSQL(sqlCreateCommand);
since the parameter is SQLiteDatabase db. Secondly you use _id. is this index not created by default ? Nevermind if this has nothing to do with it. This were just my thoghts about it. :)
I'm using ORMLite in an android project, and I'm not wanting to use the extended activities because I'm inserting values into the database on an AsyncTask.
In the docs it says:
"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."
It also says to add the database helper class in the strings.xml, which I have. So I'm not sure what I'm doing wrong.
I'm using a class called DataAccess for my data tier that looks like this:
public class DataAccess {
private Context context;
private DBHelper dbHelper;
public DataAccess(Context _context) {
this.context = _context;
dbHelper = getDBHelper(_context);
}
private DBHelper getDBHelper(Context context) {
if (dbHelper == null) {
dbHelper = (DBHelper) OpenHelperManager.getHelper(context, DBHelper.class);
}
return dbHelper;
}
}
And I'm using the extended helper class:
public class DBHelper extends OrmLiteSqliteOpenHelper {
private static final String DATABASE_NAME = "database.db";
private static final int DATABASE_VERSION = 1;
private Dao<SomeObject, Integer> someObjectTable = null;
private ConnectionSource connectionSource = null;
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
this.connectionSource = connectionSource;
try {
TableUtils.createTable(connectionSource, SomeObject.class);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
}
public Dao<SomeObject, Integer> getSomeObjectDao() throws SQLException {
if (someObjectTable == null) {
dateTable = getDao(SomeObject.class);
}
return someObjectTable;
}
The idea is to create the DataAccess class and have it create the DBHelper if it hasn't already.
Can someone tell me if this is right or wrong, or if I'm on the right path?
Thanks!
I'm using ORMLite in an android project, and I'm not wanting to use the extended activities because I'm inserting values into the database on an AsyncTask.
You are on the right track but a little off #Matt. Frankly I'd never done a project without extending our base classes. But it is a good exercise so I've created this ORMLite example project which uses an Activity and manages its own helper.
Your DBHelper class is fine but really you do not need your DataAccess class. In each of your activities (or services...) you will need to have something like the following:
private DBHelper dbHelper = null;
#Override
protected void onDestroy() {
super.onDestroy();
if (dbHelper != null) {
OpenHelperManager.releaseHelper();
dbHelper = null;
}
}
private DBHelper getHelper() {
if (dbHelper == null) {
dbHelper = (DBHelper)OpenHelperManager.getHelper(this, DBHelper.class);
}
return dbHelper;
}
You [obviously], then use this in your code by doing something like:
Dao<SomeObject, Integer> someObjectDao = getHelper().getSomeObjectDao();
So whenever you call getHelper() the first time, it will get the helper through the manager, establishing the connection to the database. Whenever your application gets destroyed by the OS, it will release the helper -- possibly closing the underlying database connection if it is the last release.
Notice that the OpenHelperManager.getHelper() needs the Context as the first argument in case you do this without even an Activity base class.
Edit:
If you do want to create a DataAccess type class to centralize the handling of the helper class then you will need to make the methods static and do your own usage counter. If there are multiple activities and background tasks calling getHelper() then the question is when do you call releaseHelper()? You'll have to increment a count for each get and only call release when the counter gets back to 0. But even then, I'm not 100% sure how many lines you'd save out of your activity class.
I could nitpick but essentially you are doing it correct.
The call
dbHelper = (DBHelper) OpenHelperManager.getHelper(context, DBHelper.class);
Looks up the DBHelper class and instantiates it for the context. If you have defined it in your strings.xml, you can leave off the DBHelper.class at the end.
onUpgrade in you DBHelper.java, you may want to consider dropping the table you create in onCreate and then calling onCreate (to make sure you don't have conversion issues from update to update). You could do a more complex update if you wanted.
Other than that, it looks good. If you end up wanting data accessory methods for your DB objects beyond the base DAO methods, you will eventually want to create more thorough implementations of your object DAOs, but this is a good start.