7

I am using this tutorial to import a database into my App.

It runs fine on API 10,

but on API 17 it throws the following error:

05-19 14:52:46.492: E/SQLiteLog(1893): (14) cannot open file at line 30176 of [00bb9c9ce4]
05-19 14:52:46.492: E/SQLiteLog(1893): (14) os_unix.c:30176: (2) open(/data/data/com.example.koday/databases/dizionario7.sqlite) - 
05-19 14:52:46.492: E/SQLiteDatabase(1893): Failed to open database '/data/data/com.example.koday/databases/dizionario7.sqlite'.
05-19 14:52:46.492: E/SQLiteDatabase(1893): android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at com.example.koday.DataBaseHelper.checkDataBase(DataBaseHelper.java:82)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at com.example.koday.DataBaseHelper.createDataBase(DataBaseHelper.java:45)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at com.example.koday.MainActivity.frontquiz(MainActivity.java:70)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at com.example.koday.MainActivity.onCreate(MainActivity.java:64)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.app.Activity.performCreate(Activity.java:5104)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.app.ActivityThread.access$600(ActivityThread.java:141)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.os.Handler.dispatchMessage(Handler.java:99)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.os.Looper.loop(Looper.java:137)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at android.app.ActivityThread.main(ActivityThread.java:5039)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at java.lang.reflect.Method.invokeNative(Native Method)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at java.lang.reflect.Method.invoke(Method.java:511)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
05-19 14:52:46.492: E/SQLiteDatabase(1893):     at dalvik.system.NativeStart.main(Native Method)
05-19 14:52:47.683: E/(1893): database aperto
05-19 14:52:47.683: E/SQLiteLog(1893): (1) no such table: dati

Here is my code:

public class DataBaseHelper extends SQLiteOpenHelper {

// The Android's default system path of your application database.
private static String DB_PATH = "/data/data/com.example.koday/databases/";

private static String DB_NAME = "dizionario7.sqlite";

private SQLiteDatabase myDataBase;

private final Context myContext;

/**
 * Constructor Takes and keeps a reference of the passed context in order to
 * access to the application assets and resources.
 * 
 * @param context
 */
public DataBaseHelper(Context context) {

    super(context, DB_NAME, null, 1);
    this.myContext = context;
}

/**
 * Creates a empty database on the system and rewrites it with your own
 * database.
 * */
public void createDataBase() throws IOException {

    boolean dbExist = checkDataBase();

    if (dbExist) {
        // do nothing - database already exist
    } else {

        // By calling this method and empty database will be created into
        // the default system path
        // of your application so we are gonna be able to overwrite that
        // database with our database.
        this.getReadableDatabase();

        try {

            copyDataBase();

        } catch (IOException e) {

            throw new Error("Error copying database");

        }
    }

}

/**
 * Check if the database already exist to avoid re-copying the file each
 * time you open the application.
 * 
 * @return true if it exists, false if it doesn't
 */
private boolean checkDataBase() {

    SQLiteDatabase checkDB = null;

    try {
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READONLY);

    } catch (SQLiteException e) {

        // database does't exist yet.

    }

    if (checkDB != null) {

        checkDB.close();

    }

    return checkDB != null ? true : false;
}

/**
 * Copies your database from your local assets-folder to the just created
 * empty database in the system folder, from where it can be accessed and
 * handled. This is done by transfering bytestream.
 * */
private void copyDataBase() throws IOException {

    // Open your local db as the input stream
    InputStream myInput = myContext.getAssets().open(DB_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME;

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

}

public void openDataBase() throws SQLException {

    // Open the database
    String myPath = DB_PATH + DB_NAME;
    myDataBase = SQLiteDatabase.openDatabase(myPath, null,
            SQLiteDatabase.OPEN_READONLY);

}

@Override
public synchronized void close() {

    if (myDataBase != null)
        myDataBase.close();

    super.close();

}

@Override
public void onCreate(SQLiteDatabase db) {

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

// Add your public helper methods to access and get content from the
// database.
// You could return cursors by doing "return myDataBase.query(....)" so it'd
// be easy
// to you to create adapters for your views.

// Getting single contact
String getkword(String word) {
    SQLiteDatabase db = this.getReadableDatabase();

    Cursor cursor = db.query("data",
            new String[] { "_id", "english", "korean" }, "english" + "=?",
            new String[] { word }, null, null, null, null);
    if (cursor != null)
        cursor.moveToFirst();

    String kword = cursor.getString(2);
    // return contact
    db.close();
    return kword;

}

// Getting All Contacts
public Cursor getCursor() {
    // Select All Query
    String selectQuery = "SELECT  * FROM " + "data";

    SQLiteDatabase db = this.getWritableDatabase();
    Cursor cursor = db.rawQuery(selectQuery, null);

    // looping through all rows and adding to list

    return cursor;
}

}

EDIT EDIT EDIT EDIT I have set permission in my manifest:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Thanks for the help!

Lisa Anne
  • 4,482
  • 17
  • 83
  • 157
  • While it may not be the problem, you should not be hard-coding the path of the application's internal storage, as this is ultimately dependent on implementation details of the Android installation, and so could change between devices/versions. One test you can do (if you are working with a debug rather than release build of your app) is to open an adb shell and type run-as com.example.koday and then use commands such as `pwd` and `ls` to explore your application's storage. – Chris Stratton May 19 '13 at 17:46
  • @Chris Stratton I agree with your observation. Please could you suggest how to avoid hard coding the path?? I am sure that would solve the problem. BTW I use Eclipse + Emulator, the "dizionario7.sqlite" is created in the path "/data/data/com.example.koday/databases/", it this means anything... – Lisa Anne May 19 '13 at 17:52
  • Context.getFilesDir() – Chris Stratton May 19 '13 at 18:07
  • This is the best tutorial on how to work with databases: https://stackoverflow.com/questions/9109438/how-to-use-an-existing-database-with-an-android-application/9109728#9109728 Git it a try! – thiagolr May 29 '13 at 02:01

3 Answers3

18

I think the problem is with the location of the db for different version of SDK. please try this

private static String DB_PATH = "";
public DataBaseHelper(Context context) {
    super(context, DB_NAME, null, 1);// 1? its Database Version
    if(android.os.Build.VERSION.SDK_INT >= 4.2){
        DB_PATH = context.getApplicationInfo().dataDir + "/databases/";         
    } else {
       DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
    }
    this.mContext = context; 
}  

Check this out

How to use an existing database with an Android application

Community
  • 1
  • 1
Naveen Prince P
  • 4,521
  • 3
  • 16
  • 17
  • 2
    I used the same helper in my new project as another one I did and changed only the package name in the file path. In my first project it worked fine, in my second I got this error. How could my file path be fine for my first application but not my second given an identical testing environment? Further, why doesn't openDatabase() throw an exception if it does have an incorrect path? (Throws: SQLiteException if the database cannot be opened) – John Moffitt Jun 28 '13 at 06:34
  • 1
    @naveenprince - FYI: the code you put yields the same result: /data/data/PACKAGE_NAME/databases/ – Jadeye Sep 23 '13 at 11:12
0

A very wild guess is that you don't have required permissions in your android manifest. Besides, I am using the same piece of code for one of my projects replace checkDatabase() with:

private boolean checkDataBase() {

    File dbFile = new File(DATABASE_PATH + DATABASE_NAME);
    return dbFile.exists();
}

Also for the path use:

public static String getDBPath() {
    return Environment.getDataDirectory() + "/data/"
            + context.getPackageName() + "/databases/";
}
Saeid Farivar
  • 1,667
  • 24
  • 43
0

I had the same error. I found out that I was entering the database while importing and updating the tables in the database. so I conclude that if you are updating your data base tables you can't use them at the same moment.

Ahmad Shbita
  • 73
  • 1
  • 5