7

Edit: I tried this on my phone and it works, can anyone tell me why it does not work on an emulator?

I am trying to open a database on android, but it is throwing an "Database file could not be opened" Exception. In the debugger, it seems that the error is occurring on the line mDb = mDbHelper.getWritableDatabase();

My code is as follows:

package com.track.map;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;


    public class DBAdapter {

        protected static final String DATABASE_NAME = "data";
        protected static final int DATABASE_VERSION = 1;

        //database tables
        //track table
        protected static final String TRACK_TABLE = "tracks";
        protected static final String TRACK_ID = "_id";
        protected static final String TRACK_DATE_TIME_START = "date_time_start";
        protected static final String TRACK_DATE_TIME_END = "date_time_end";

        //tables create
        protected static final String TRACK_TABLE_CREATE = 
                                "create table " + TRACK_TABLE + " ("
                                    + TRACK_ID + " integet promary key not null, "
                                    + TRACK_DATE_TIME_START + " text not null, "
                                    + TRACK_DATE_TIME_END + " text not null);";

        protected DatabaseHelper mDbHelper;
        protected SQLiteDatabase mDb;

        protected final Context mContext;

        public DBAdapter(Context context) {
            mContext = context;
        }

        public DBAdapter open() throws android.database.SQLException {
            mDbHelper = new DatabaseHelper(mContext);
            mDb = mDbHelper.getWritableDatabase();
            return this;
        }

        public void close() {
            mDb.close();
        }

        protected static class DatabaseHelper extends SQLiteOpenHelper {

            public DatabaseHelper(Context context) {
                super(context, DATABASE_NAME, null, DATABASE_VERSION);
            }

            @Override
            public void onCreate(SQLiteDatabase db) {
                db.execSQL(TRACK_TABLE_CREATE);
            }

            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                onCreate(db); //for now just recreate the database
            }

        }

    }

and

package com.track.map;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

    private DBAdapter db;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        db = new DBAdapter(this);
        db.open();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

Does anyone know what the problem is?

EDIT:

The logcat is:

03-24 11:43:42.022: I/Database(758): sqlite returned: error code = 14, msg = cannot open file at source line 25467
03-24 11:43:42.022: E/Database(758): sqlite3_open_v2("/data/data/com.track.map/databases/data", &handle, 6, NULL) failed
03-24 11:43:42.032: D/AndroidRuntime(758): Shutting down VM
03-24 11:43:42.032: W/dalvikvm(758): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
03-24 11:43:42.062: E/AndroidRuntime(758): FATAL EXCEPTION: main
03-24 11:43:42.062: E/AndroidRuntime(758): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.track.map/com.track.map.MainActivity}: android.database.sqlite.SQLiteException: unable to open database file
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.ActivityThread.access$2300(ActivityThread.java:125)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.os.Handler.dispatchMessage(Handler.java:99)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.os.Looper.loop(Looper.java:123)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.ActivityThread.main(ActivityThread.java:4627)
03-24 11:43:42.062: E/AndroidRuntime(758):  at java.lang.reflect.Method.invokeNative(Native Method)
03-24 11:43:42.062: E/AndroidRuntime(758):  at java.lang.reflect.Method.invoke(Method.java:521)
03-24 11:43:42.062: E/AndroidRuntime(758):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
03-24 11:43:42.062: E/AndroidRuntime(758):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
03-24 11:43:42.062: E/AndroidRuntime(758):  at dalvik.system.NativeStart.main(Native Method)
03-24 11:43:42.062: E/AndroidRuntime(758): Caused by: android.database.sqlite.SQLiteException: unable to open database file
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1812)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:817)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:851)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:844)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:540)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:203)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
03-24 11:43:42.062: E/AndroidRuntime(758):  at com.track.map.DBAdapter.open(DBAdapter.java:37)
03-24 11:43:42.062: E/AndroidRuntime(758):  at com.track.map.MainActivity.onCreate(MainActivity.java:17)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
03-24 11:43:42.062: E/AndroidRuntime(758):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
03-24 11:43:42.062: E/AndroidRuntime(758):  ... 11 more
Meir
  • 1,943
  • 5
  • 22
  • 38
  • Please post the logcat file. – MysticMagicϡ Mar 24 '13 at 09:58
  • what is databaseHelper in protected DatabaseHelper mDbHelper; – Viswanath Lekshmanan Mar 24 '13 at 10:02
  • Do you test on a phone or emulator? – Hoan Nguyen Mar 24 '13 at 10:31
  • There is no problems at all, I tested on 2 phones. Of course as Rick77 pointed out, the table would be useless. – Hoan Nguyen Mar 24 '13 at 10:40
  • I fixed the sql, and it still does not work. I am using an emulator. – Meir Mar 24 '13 at 11:45
  • 1
    Meir, could you try to use adb to check if there's something weird going on in the /data/data/com.track.map/databases/data directory? "adb shell" to work on the device, floowed by "run-as com.track.map" should do the trick (not all devices allow this, but the emulator sure will). I ask because a) something weird is going on and b) i have checked the arguments passed to sqlite3_open_v2 and they seem alright (http://www.sqlite.org/c3ref/open.html) – Rick77 Mar 24 '13 at 15:37

5 Answers5

5

This may be a little late, but hope this helps for whoever gets this problem (since I can't find a definitive solution around).

I think I know the reason for this cause (at least for my case). Looking in the DDMS --> File Explorer, you'd realize that the Database Folder (/data/data//databases/) does not exist, which is why the application cannot create the database file in that non-existent folder. If you can create a databases folder in some manner, you can avoid this problem.

Because I'm lazy, I just used the /data/data//files/ folder when I'm in Emulator mode. You can get the files dir using this:

context.getFilesDir().getPath()

This worked beautifully for me in the Emulator.

Hope this helps someone.

In case you want to see some code:

String dbFilename = "example.db";
try
{       
    File databaseFile = getDatabasePath(dbFilename);        
    SQLiteDatabase _db = SQLiteDatabase.openOrCreateDatabase(databaseFile);
} catch (Exception e)
{
    String databasePath =  getFilesDir().getPath() +  "/" + dbFilename;
    File databaseFile = new File(databasePath); 
    _db = SQLiteDatabase.openOrCreateDatabase(databaseFile);
}

Edit:

I tried logging into Facebook (my app has FB integration) on the Emulator and /databases folder appeared after that (and persisted). Not sure what happened, but it's possible to create that folder somehow. Something for another expert around here to shed light on.

Sufian
  • 6,405
  • 16
  • 66
  • 120
El Jae
  • 141
  • 2
  • 5
2

try this on your constructor

public youeConstructor(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        context.openOrCreateDatabase(DATABASE_NAME, context.MODE_PRIVATE, null);
    }
TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
Ameen Maheen
  • 2,719
  • 1
  • 28
  • 28
1

Although not relevant for your current issue, the onUpgrade method in SQLiteOpenHelper is also bound to fail in the future: If the action you want to take when a new version of the db is deployed, is to start from scratch, you will need to delete the old tables first.

Edit After some research I found out that your problem is rather common:

Android SQLiteOpenHelper cannot open database file

the 3 links provided with this answer

https://stackoverflow.com/a/8957994/2177061

are particularly interesting and provide some kind of workaround, should you not find a clean way to make the bug disappear.

That said if I where in you, as a first attempt to solve your problem before delving with complex workarounds, I would try to update all Android Development Tools (the SDK in particular, but updating the eclipse plugin won't hurt), completely remove your app from both the emulator and devices, and run it again.

Good luck!

Edit 2 Disregard the following remark (it's not correct, I leave it here for reference)

Your code doesn't work because the SQL query is wrong: you spelled

integet promary

where it should have been

integer primary

(besides, it happens to me too that I get crazy with the Android db classes only to find that the problem resides in the SQL queries :) )

Hope this helps

Community
  • 1
  • 1
Rick77
  • 3,121
  • 25
  • 43
  • 1
    This is not the reason, + TRACK_ID + " integet promary key not null, " + TRACK_DATE_TIME_START would be treated as a column name. – Hoan Nguyen Mar 24 '13 at 10:38
  • Wow! I tried it in a sqlite3 client and I still can't believe it works... thank you for the correction! – Rick77 Mar 24 '13 at 10:42
1

I was looking for a solution to this problem and I didn't find anything that worked... but fortunately I did something that solved it. This is what I did:

Open your adb shell and remove the database you are trying to open. For those who don't know how to use the Linux terminal:

// first open adb shell from a command line

adb shell

// then these are the commands you need (change YOUR.APP.PACKAGE for your app package, it should look like com.domain.apilcation )

cd /data/data/YOUR.APP.PACKAGE/databases/
ls

The last command (ls) will list all the databases that you created for your project and now you can remove the database that you can't open. First, you should copy it, so you don't lose any important data. (I will suppose that your database is called your_database.db)

cp your_database.db your_database.db_backup
rm your_database.db

Then you should launch your app, it should create a new database and for me this solved the problem permanently.

I hope this helps!

mimetist
  • 161
  • 6
0
Why are you keeping code complex try this


public SQLiteDatabase sampleDB;
    public String COLUMN_ID="_id";
    public String COLUMN1="username";
    public String COLUMN2="password";
    public String TABLE_NAME="Androdata";

sampleDB =  this.openOrCreateDatabase(TABLE_NAME, MODE_PRIVATE, null);

private void insertDB() {
        sampleDB.execSQL("INSERT INTO " +
                TABLE_NAME +
                " Values ('1','Androviewer','viewer');");   
        System.out.println("Inserted data successfully....");
    }
    private void createDB() {
        sampleDB.execSQL("CREATE TABLE IF NOT EXISTS " +
                TABLE_NAME+ "(" + COLUMN_ID
                + " integer primary key autoincrement, " + COLUMN1
                + " text not null,"+ COLUMN2
                + " text not null);");
        System.out.println("Database created successfully....");
    }
Viswanath Lekshmanan
  • 9,945
  • 1
  • 40
  • 64
  • Even though I don't doubt that your approach works, I wouldn't advocate it against SQLiteOpenHelper, unless I'm sure that the latter wouldn't cut it (as SQLiteOpenHelper is the recommended method to open/create a db ref: http://developer.android.com/guide/topics/data/data-storage.html#db) – Rick77 Mar 24 '13 at 10:38