when we create SQLite database from an android application can use a DatabaseHelper class which extend SQLiteOpenHelper.
My constructor is as follows
public DatabaseHelper(Context context)
{
super(context, dbName, null, DATABASE_VERSION);
}
Then the onCreate() method
public void onCreate(SQLiteDatabase db)
{
String qry = "CREATE TABLE DEPT(dept_id INTEGER PRIMARY KEY, deptName TEXT)";
db.execSQL(qry);
InsertDepts(db);
}
But when i create an instance of the DatabaseHelper class, my database havent created yet.
I believe when I create an Object from this class, the constructor executes and since no database created yet it will create database and execute onCreate() method. So definitely an database must be created.
Or untill we execute the following code doesn't it execute the onCreate() method, even if we create an object from the class.
databaseHelper.getWritableDatabase()
Can anyone please explain the execution order of the databasehelper class.
You create an instance of your DatabaseHelper-class, which causes the constructor to be executed. The constructor will execute the mother-classes constructor (SQLiteOpenHelper), which will then check if the Database-file already exists.
If it exists, nothing is done and your object is created.
If it doesn't exist, the Database-file is created and the onCreate-method is called.
You say, your Database doesn't exist. Are you getting any errors in the LogCat? Also, have you tried accessing the Database using the adb?
Order should be like this (as reads SQLiteOpenHelper javadoc)
Constructor
During 1st call of openReadableDatabase() or openWritableDatabase() will be called onCreate
Then will called onOpen
Added
Just checked sources of SQLiteOpenHelper constructor and it reads:
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
mContext = context;
mName = name;
mFactory = factory;
mNewVersion = version;
}
In contrary openReadableDatabase/OpenWritableDatabase sources consists calls to openOrCreateDatabase() - so constructor doesn't call onCreate
please refer to this
http://androidforbeginners.blogspot.com/2010/01/creating-multiple-sqlite-database.html
Related
I am trying to updgrade the sqlite version number from 1 to 2 but onupgrade method is not getting called.
do i have to delete application in the device and then install the application to test it ?
Only method which get called is DatabaseHelper and onCreate
No other method get called.
In DatabaseHelper.java file
private static final int DBVersion = 1; // I had change this value to 2.but it is not working.
public DatabaseHelper(Context context, CursorFactory cf) {
super(context, DBName, cf, DBVersion);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLE_CREATE_Table);
}
#Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
//This is not called.If it called i will add the changed here
}
another class for dataprovider.java
#Override
public boolean onCreate() {
dbHelper = new DatabaseHelper(getContext(), null);
return true;
}
using :-
#Override
public boolean onCreate() {
dbHelper = new DatabaseHelper(getContext(), null);
SqliteDatabase db = dbHelper.getWritableDatabase(); //<<<<<<<<<<<
return true;
}
attempts to open the database and thus onCreate/onUpgrade would be called.
- onCreate only if the database does not exist.
- onUpgrade only if the database exists AND the specified version number is greater than the database version stored in the database.
That is when instantiating the Database Helper (subclass of SQLiteOpenHelper) no attempt is made to open the database.
The attempt to open the database is only made when the SQLiteDatabase's getWritableDatabase (or getReadableDatabase) are called. Both attempt to open the database. Noting that getWritableDatabase or getReadableDatabase may well be called implicitly.
Note the above does not include directly using the SQliteDatabase's OPEN methods.
Alternative Fix
I personally tend to force the open when constructing the database helper by using :-
public DatabaseHelper(Context context, CursorFactory cf) {
super(context, DBName, cf, DBVersion);
this.getWritableDatabase();
}
I tend to save the returned SQLiteDatabase into a class variable and then use that rather than using this.getWritableDatabase() in the underlying methods.
I'm getting this error when I run my app for the first time after re-install:
android.database.sqlite.SQLiteException: no such table
(This error happens when my app tries to read from the database)
For some reason the onCreate() method in DBHelper is not getting called and therefore the tables are not getting created. I followed the advice from other question and tried calling getWritableDatabase(), also tried a create() call to insert data in some table, but still no luck: onCreate is never called.
I got it to work however by changing the DATABASE_VERSION value to 2. But that doesn't make sense since this is a brand new installation after uninstall.
Also I found that before the SQL read error the database got created but it has only 1 table "android_metadata" (not created by me).
I'm posting some code here for reference
public class DatabaseHelper extends OrmLiteSqliteOpenHelper{
private static final String DATABASE_NAME = "RoutePlanner.db";
private static final int DATABASE_VERSION = 1;
private Dao<Trip, Integer> tripDAO = null;
private RuntimeExceptionDao<Trip, Integer> tripRunTimeDAO = null;
...
}
#Override
public SQLiteDatabase getWritableDatabase() {
return super.getWritableDatabase();
}
public DatabaseHelper(Context context){
super(context, DATABASE_NAME,null, DATABASE_VERSION, R.raw.ormlite_config);
}
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource source) {
try {
Log.i(DatabaseHelper.class.getSimpleName(), "onCreate");
TableUtils.createTable(source, Trip.class);
...
} catch (SQLException ex) {
Log.e(DatabaseHelper.class.getSimpleName(), "Error creating db", ex);
throw new RuntimeException(ex);
}
}
OK, I found the problem, hope this explanations helps others on what NOT to do. The issue was that I had a separate calendar module which I wanted to access my Database. To make things 'simpler' I created a separate DatabaseHelper on that module to access the same SQLite databse as my main module. The existance of the 2nd DatabaseHelper was causing all my issues. Solutions are either join the 2 modules into one, or use a Database Service Provider
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();
I have one database and I've created a Database class that has a private static class DbHelper extends SQLiteOpenHelper to help me manage my database.
This database is access from four different activities.
I have this public void onCreate(SQLiteDatabase db) that it's what creates my database tables and adds values to those tables. Since the program only enter here the first time the user runs the app, I want to create a ProgressDialog.
This is what I have:
Override
public void onCreate(SQLiteDatabase db) {
ProgressDialog progresso = ProgressDialog.show(context, "Info", "Loading DB" );
// Code to create the tables and add the values
progress.dismiss();
}
Got 2 questions.
First:
Since this can be accessed from 4 different activities how can I get the context?
Making:
Context context = getAplicationContext();
Second:
Why can't I use strings from strings.xml?
I can't make this:
ProgressDialog progresso = ProgressDialog.show(context, getString(R.string.driProgressTitle), getString(R.string.driProgressMessage) );
UPDATE
public class Database {
ProgressDialog progresso;
private DbHelper DBHelper;
private final Context Context;
private SQLiteDatabase BaseDados;
private static class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, BD_NAME, null, BD_VERSION);
// TODO Auto-generated method stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// Whanted to show here the progress dialog
new loadDB().execute();
// Creates the table and adds the values
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVesion) {
db.execSQL("DROP TABLE IF EXISTS MYTABLE");
onCreate(db);
}
}
public Database(Context c) {
Context = c;
}
public Database open() throws SQLException {
DBHelper = new DbHelper(Context);
BaseDados = DBHelper.getWritableDatabase();
return this;
}
public void close() {
DBHelper.close();
}
public Cursor getData(int tipo, long groupId, String query[]) {
// Performs the querys to my database
}
return null;
}
public class loadDB extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
progresso = ProgressDialog.show(Context, Context.getString(R.string.ProgressTitle), Context.getString(R.string.ProgressMessage) );
return 1;
}
#Override
protected void onPostExecute(Integer result) {
progresso.dismiss();
super.onPostExecute(result);
}
}
}
With the above code I'm getting this error No enclosing instance of type Database is accessible. Must qualify the allocation with an enclosing instance of type Database (e.g. x.new A() where x is an instance of Database). in new loadDB().execute();.
Don't you have access to the Context from the constructor?
SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler)
EDIT:
Your code:
public DbHelper(Context context) {
super(context, BD_NAME, null, BD_VERSION);
// TODO Auto-generated method stub
}
You have access to the context at this point.. can you just do something like add a field called context then do this:
Context context;
public DbHelper(Context context) {
super(context, BD_NAME, null, BD_VERSION);
// TODO Auto-generated method stub
this.context = context;
}
Now, you have access to the context anywhere in the class? Assuming that the constructor is called before onCreate.
The onCreate(SQLiteDatabase) method only gets called the first time you make a call to getReadableDatabase() or getWritableDatabase (i.e. the first time it is opened), not when the app is first run (of course you could first this to happen by simply opening the database the closing it).
I'm not sure giving it the Application context will work since the progressDialog will need to be displayed in the currently running Activity.
Instead of trying to display progress bars for precisely when the database is first accessed, have your current Activity display one any time it access the database itself. That way the first access to the database is masked by regular access to it.
If you don't want to display progress bars for all DB access, then again you can just open and close the database and have your Activity display a progress bar before you open it, and remove the progress bar when you close it (not doing anything with the database except let onCreate() run).
Unless your database structures are really big, you probably won't even see the progress bar. It doesn't take very long to create the tables.
Use Loader for reading data from DB. Don't clutter background classes with UI stuff
onCreateLoader(..
//you can start progress
onLoadFinished(..
// you can stop it
Also you read data from background thread which is recommended.
You're unable to access the context of the application, as SQLiteOpenHelper does not have contain these methods (unlike Activity)
My advice to you is to use the DbHelper class to set up the database and to manage any sql transactions. Have it's constructor take a context object, then create instances of it within a class which extends Activity, passing the context through to the constructor.
It would also be good practice to have a data access object class sitting inbetween the activity and the sqlliteOpenHelper, to manage opening, closing and issuing transactions too your database object
To show user progress, you will have to run your work in a separate thread, otherwise GUI will just freeze until the database work is completed and user may get the "Activity not responding, force close" message.
Use Application class to store a global flag about if database has been created or not.
Any starting activity checks this flag, if database has not been initialized, it creates an AsyncTask , passes on db and its own context in constructor. AsyncTask will have three methods:
onPreExecute : show your dialog here. Make dialog non cancel able so user can't skip it.
doInBackground : database building code here. (call the Database helper class methods)
onPostExecute : dismiss the dialog. Now user can interact with the Activity.
Is it possible (simple) to get the current database version number, increment it, and pass it to SQLiteOpenHelper's constructor from within an activity rather then hard coding the version number like so?
Activity (called from onclick):
public void updatedb(){
//pseudo-code next 2 comments
//int incVersion = getCurrentDBVersion();<==question here
//incVersion = incVersion + 1;
DatabaseHandler dbincrement = new DatabaseHandler(this, incVersion);
}
SQLiteOpenHelper Extension:
public class DatabaseHandler extends SQLiteOpenHelper{
public DatabaseHandler(Context context, int incVersion) {
super(context, DATABASE_NAME, null, incVersion);
}
}
Yes, use something like this to get the database version:
DatabaseHandler dh = new DatabaseHandler(this);
SQLiteDatabase db = dh.getWriteableDatabase();
int version = db.getVersion();
DatabaseHandler dhInc = new DatabaseHandler(this, version++);
You cannot get the current db version number unless you first open the database. So if your intention was to get the installed database version, increment it, and then call the SQLiteOpenHelper constructor with the new version than I don't believe what Sam proposed will satisfy your request.
Here's why:
1) the first line in a DatabaseHandler constructor must invoke the SQLiteOpenHelper (super) constructor, providing your database version.
2) invoking getWriteableDatabase automatically causes the invocation of the onOpen and/or onUpgrade/onDowngrade methods in your DatabaseHandler. Which onXXXX method is called depends on SQLiteOpenHelper's comparison of the installed database version to the version you provided in your constructor initialization above.
I don't know an easy way to find out the installed database version without providing one first.