Android ORMLite DbHelper onCreate() not called even after uninstall - android

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

Related

How do I use SQLiteOpenHelper in a secondary class?

As a new Android programmer, I followed various online examples to create my own class that extends SQLiteOpenHelper...
public class MySQLiteHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION=1;
private static final String DATABASE_NAME="MyDB";
// Main Database Operations
public MySQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_A);
db.execSQL(CREATE_TABLE_B);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
...
public long addRecord(){
SQLiteDatabase db = this.getWritableDatabase();
....
etc
This works throughout my various activities with no issues. When I want to use it, I call...
MySQLiteHelper db = new MySQLiteHelper(this);
Then I call the various routines like...
db.addRecord();
Now I have created a secondary class that I need to use throughout the application. In that class, there are some routines that need to process data from the database. Problem is, I can't declare the MySQLiteHelper because of the this which errors out.
Doing some online search I think I understand that I need to get the Context from the application (or the calling activity??), but not sure how to go about doing that with this code.
As I mentioned, I am new to Android... so any code examples would be greatly appreciated.
EDIT
I need to clarify this secondary class as mentioned above. From the aforementioned online examples, the second class is used to "hold" the database record information. It looks something like this...
public class Acct {
private int _id;
private String _name;
private String _phone;
public Acct() {
}
public int get_id(){
return this._id;
}
public void set_id(int id) {
this._id=id;
}
public void set_name(String name){
this._name=name;
}
public String get_name(){
return this._name;
}
public void set_phone(String phone){
this._name=phone;
}
public String get_phone(){
return this._phone;
}
...
This is typically used with something like this in an activity...
MySQLiteHelper db = new MySQLiteHelper(this);
Acct acct = new Acct();
acct=db.getAccount(searchId);
myEditText.setText(acct.get_name());
...
Where my problem arises, I want to create a routine and code it IN the Acct class so it can be referenced such as...
acct.UpdateData();
This UpdateData routine is where we need to access the db and thus the MySQLiteHelper. It needs to be able, for each account, to go into the database, access some information from another table, do some processing, and store a summary back into this table for easier reference. As mentioned, there is no Context in the Acct class, so this is where I am getting confused.
And to make matters worse, because the Acct class is a 'holding' place for data from the DB, the online examples also use Acct IN the 'MySQLiteHelper' itself during the getAccount routine....
public Acct getAccount(int id){
SQLiteDatabase db = this.getReadableDatabase();
String SQL_STRING="SELECT * FROM "+ACCT_TABLE+" WHERE "+ACCT_FLD_ID+" = "+String.valueOf(id);
Cursor cursor =
db.rawQuery(SQL_STRING, null);
Acct acct = new Acct();
if (cursor!=null) {
cursor.moveToFirst();
acct.set_id(cursor.getInt((cursor.getColumnIndex(ACCT_FLD_ID))));
acct.set_name(cursor.getString(cursor.getColumnIndex(ACCT_FLD_NAME)));
acct.set_phone(cursor.getString(cursor.getColumnIndex(ACCT_FLD_PHONE)));
cursor.close();
} else {
acct = null;
}
db.close();
return acct;
}
I hope all this additional helped clarify what I am trying to do for the couple comments and answers posted so far. If you need more information, please ask. I'd like to get this to work, just still not sure how.
Your problem is you need a Context to call the constructor of MySQLiteHelper. You've been successful doing so in an Activity (which is a Context), but now you have some other class (which I will call "Foo") that isn't a Context and doesn't have one.
A quick solution is to make Foo take a Context in its constructor, and instantiate your MySQLiteHelper like so:
public class Foo {
private MyOpenHelper openHelper;
public Foo(Context context) {
openHelper = new MyOpenHelper(context.getApplicationContext());
}
}
If Foo is a singleton, you can do the same thing in whatever method obtains the instance (i.e. force the caller to provide a Context). Every application component either is a Context (Activity, Service) or has a Context (BroadcastReceiver gets one in onReceive(), ContentProvider has getContext()).
The use of getApplicationContext() here is worth noting: The Application object for your app is always a singleton--only one instance of it will exist for as long as your app is running (this is guaranteed by the OS). Activities can be destroyed, and creating a MySQLiteHelper with one can cause a memory leak. The application Context always exists and so it cannot be leaked.
Instead of using this, Try to use MainActivity.this or getApplicationContext().
Hope this help!

Attempt to reopen an already-closed object

I have one database helper class and three datasource classes for three tables in same database.
The database is accessed in lots of places via AsyncTasks. I faced this "attempt to reopen an already-closed object..." problem, I searched around and found that dbhelper.getReadableDatabase() returns same object for already opened connection. I guessed that problem must be due to when two threads performing operations simultaneously and one of them finishes its task and calls close() the connection gets closed and running thread throws this exception.
So to avoid close() I wrote following two methods:
public static synchronized void newOpenRequest() {
requestsOpen++;
Util.debuglog(TAG, "Open requests: " + requestsOpen);
}
public static synchronized boolean canClose() {
requestsOpen--;
Util.debuglog(TAG, "Open requests: " + requestsOpen);
if(requestsOpen == 0)
return true;
return false;
}
In all of three datasource classes, when I do it in following manner:
private void openRead() {
database = dbhelper.getReadableDatabase();
DBHelper.newOpenRequest();
Log.i(TAG, "Database opened.");
}
private void openWrite() {
database = dbhelper.getWritableDatabase();
DBHelper.newOpenRequest();
Log.i(TAG, "Database opened.");
}
private void close() {
if (DBHelper.canClose()) {
dbhelper.close();
Util.debuglog(TAG, "Database closed.");
}
}
My LogCat output is as follows:
So as highlighted in black rectangle, total openRequests were 0, so database closed, normal but as highlighted in red rectangle,
firstly openRequests were 0, so that time only database was supposed to get closed, but (my guess) what happened is canClose() returned true for a thread, and just before call to dbhelper.close(); another thread called open() (since openRequests = 1 is on LogCat just before close) and then first thread's close() invoked giving trouble to another running thread.
So looking for solution to avoid this concurrent access problem.
Thank you.
I have learned to never close the database in android. So maybe your fix is to not close the db. There is no point, keep it open during the entire life of your app. Android will release the resource when your app id destroyed.
You don't need to synchronize your database calls as sqlite can be thread safe.
Is Sqlite Database instance thread safe
DBOpenHelper works just fine:
public class DBOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 31;
private static DBOpenHelper mInstance;
private static final String DATABASE_NAME = "thedb.db";
public static DBOpenHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DBOpenHelper(context.getApplicationContext());
}
return mInstance;
}
private DBOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
sample using the db helper - close the cursor but not the db
SQLiteDatabase db = DBOpenHelper.getInstance(context).getWritableDatabase();
Cursor cursor = null;
try {
cursor = db.query...
}
finally {
cursor.close();
}

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();

SQLiteOpenHelper synchronization

So I've come up with some idea and I'm wondering if it is realizable.
Let's say I've multiple tables(database models) each of them is represented by some class.I don't wont to use singleton pattern with the open helper so I've created some simple class to provide single instance of the database.My idea is that as long as all tables hold reference to SQLiteDatabase(returned by the open helper) they will all work with the same DB instance and probably won't be needed to synchronized the work with the database since the open helper do this.When the last table finish it's work the GC will collect the open helper (since the last reference will be weak reference) -> finalize() is called and I close the db during this method to prevent any warning from OS. My question is: Is this could work?Will it close automatically the DB and will it leak or throw some exception?
Here is my class:
public class DatabaseHelper {
private static WeakReference<SomeCustomOpenHelper> sDBOpenHelper;
private void notifyDBCreate(SQLiteDatabase db) {
for (DBTable table : mTables) {
table.onDBCreate(db);
}
}
private void notifyDBUpgrade(SQLiteDatabase db) {
for (DBTable table : mTables) {
table.onDBUpgrade(db);
}
}
public SQLiteDatabase getDatabase(boolean readOnly) {
SomeCustomOpenHelper dbHelper = sDBOpenHelper.get();
if (dbHelper == null) {
dbHelper = new SomeCustomOpenHelper(context, name, factory, version, new DatabaseEventsCallback());
sDBOpenHelper = new WeakReference<SomeCustomOpenHelper>(dbHelper);
}
if (readOnly) {
return dbHelper.getReadableDatabase();
} else {
return dbHelper.getWritableDatabase();
}
}
private class DatabaseEventsCallback implements IDatabaseEventsCallback {
#Override
public void onCreate(SQLiteDatabase db) {
notifyDBCreate(db);
}
#Override
public void onUpgrade(SQLiteDatabase db) {
notifyDBUpgrade(db);
}
}
interface IDatabaseEventsCallback {
void onCreate(SQLiteDatabase db);
void onUpgrade(SQLiteDatabase db);
}
private static class SomeCustomOpenHelper extends SQLiteOpenHelper {
private IDatabaseEventsCallback mCB;
public SomeCustomOpenHelper(Context context, String name, CursorFactory factory, int version, IDatabaseEventsCallback cb) {
super(context, name, factory, version);
mCB = cb;
}
#Override
public void onCreate(SQLiteDatabase db) {
mCB.onCreate(db);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
mCB.onUpgrade(db);
}
#Override
protected void finalize() throws Throwable {
this.close();
super.finalize();
}
}
}
Did not really know the answer neither, but got interested and looked it up.
The answer is written out properly here;
http://blog.foxxtrot.net/2009/01/a-sqliteopenhelper-is-not-a-sqlitetablehelper.html
But basically the core of the info is;
I created three SQLiteOpenHelper classes, one for each table, even though they all referenced only a single database file.
Here is where everything fell apart. Android maintains Versions for databases based on the package it’s associated with, the name of the database, and the version number you provide. The package and name go into decided what the path on the device will be, while the version is stored (somewhere) on the device so that it knows when it needs to call an OpenHelper’s onUpgrade event handler. It turns out that if, in the SQLiteOpenHelper Constructor, it determines that the database already exists, it won’t call your onCreate or onUpgrade methods at all, even if the particular class which is making the call has never been called before.
I've been through the same issue when I was working on a project. I also went crazy on the doubt if the static instance was using enough memory and causing a considerable memory leak.
I'm not sure if creating a weak reference would guarantee that database instance would be collected. However a possible workaround could be : Assigning a null value to static database instance once your all database transaction is done and you've close the database. This might ensure that the database instance no more allocates any memory.
Let me know if this works or if there is a better work-around.
You can do so. As you say the locking should be happening on the SQLite and I've never heard issues around that so you should be fine with this.
The only restriction you have is that all the tables will have to go into the same database since Android for now just allows you to have one file.
Closing the database is a different thing, that's why it is actually interesting to use the singleton pattern (you avoid closing + opening all the time).
Nonetheless with your approach you just need to make sure to close the db whenever you are done with it. As far as I'm concerned this is not automatically done.
Additionally Lars Vogel has written extremely useful and detailed articles around DB access in Android. You might want to have a look there. http://www.vogella.com/articles/AndroidSQLite/article.html
you can use one open helper for all the table .i am using the single instance in my app also like this .
public static synchronized DatabaseHelper getInstance(Context ctx)
{
if (dbhelper == null) {
dbhelper = new DatabaseHelper(ctx);
}
return dbhelper ;
}
My question is: Is this could work?Will it close automatically the DB
and will it leak or throw some exception?
NO it will not close automatically database , when your application will demand for DATABASE object and OS found some of your database instant are alive then Android framework try to connect that object reference (which is probably weak reference )
and i have to say , I don't recommend opening and closing a DATABASE on-demand or temporarily . It is always nice to open the DB up early and keep it open for the duration of your whole activity and close it when the activity gets finished or suspended .

Android multiple ContentProviders with same database name throws 'no such table' exception

When using same database name for multiple ContentProviders, query fails with exception thrown as 'no such table'.
I researched the reference, and books, the Internet discussions, but could not find resolution.
I noticed that all the ContentProviders fail except the one ContentProvider declared first in the manifest. So I gave unique database name and the exception goes away. It works but it's weird to have multiple single-table databases.
I want to figure out why the problem occurs if possible. Below is my implementation in essence.
All ContentProviders have separate SQLiteOpenHelper defined as inner private class. DATABASE_NAME and DATABASE_VERSION are all the same.
public class TheFirstProvider extends ContentProvider {
private static final String DATABASE_NAME = "dbname.db";
private static final int DATABASE_VERSION = 1;
private SQLiteOpenHelper dbHelper;
#Override
public boolean onCreate(){
mContext = getContext();
dbHelper = new FirstDbHelper(mContext, DATABASE_NAME, null, DATABASE_VERSION);
}
private class FirstDbHelper extends SQLiteOpenHelper {
...
private static final String DATABASE_CREATE_FIRST = ... ;
#Override
public void onCreate(SQLiteDatabase db){
db.execSQL(DATABASE_CREATE_FIRST);
}
}
Check your Create table statement and verify if it was correctly executed and see if the table you are using on the query has the exact same name as the one created. Sometimes a little mistake on the DDL (create statement) lead to problems like this that happens silently.
I also suggest you to install this eclipse plugin to visualize the database on your emulator so you can see the tables you have created and check if it's what you've expected.
private class FirstDbHelper extends SQLiteOpenHelper{
public FirstDbHelper(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String query="Your Query";
db.execSQL(query);
}
Set your Code as below.It will Work.

Categories

Resources