Receiving “Could not open database” error when trying to open sqlite file in /assets

I am trying to open a sqlite database that I created and loaded and /assets of my project. I use a class, MySQLiteHelper to open this database and to handle upgrades, etc.

In my Activity I create a new instance of MySQLiteHelper … as I do so, it says that it can’t open the database (see logcat below).

Had this working and now it stopped. Confused why I am now receiving this error … I rolled back my changes and I still receive this error. I am thinking it has something to do with the file I am loading? Any help would be appreciated.

Class to open sqlite:

package com.sembasys....;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class MySQLiteHelper extends SQLiteOpenHelper {

    // The Android's default system path of your application database.
    private static String DB_PATH = "/data/data/com.sembasys.metrosleepnyc/databases/";
    private static String DB_NAME = "metrosleep";

    private SQLiteDatabase myDataBase;
    private final Context myContext;
    private static final int DATABASE_VERSION = 1;
    public static final String KEY_ID = "stop_id";
    public static final String LINE_ID = "line_id";
    public static final String STATION= "station_name";

    public MySQLiteHelper(Context context) {
        super(context, DB_NAME, null, DATABASE_VERSION);
        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) {
            Log.v("DB Exists", "db exists");

            // By calling this method here onUpgrade will be called on a
            // writeable database, but only if the version number has been
            // bumped
            this.getWritableDatabase();
        }
        dbExist = checkDataBase();
        if (!dbExist) {
            // 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) {

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
            Log.v("Database Upgrade", "Database version higher than old.");
        myContext.deleteDatabase(DB_NAME);
    }

}

Activity where I implement the above class:

package com.sembasys....;


import com.actionbarsherlock.app.SherlockActivity;
import android.widget.SimpleCursorAdapter;
import android.annotation.TargetApi;
import android.app.ListActivity;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import android.support.v4.app.NavUtils;

public class ChooseRoute extends ListActivity  {


    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Show the Up button in the action bar.
        //getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        MySQLiteHelper myDbHelper = new MySQLiteHelper(null);
        myDbHelper = new MySQLiteHelper(this);


            try {
                myDbHelper.openDataBase();
            }catch(SQLException sqle){
                throw sqle;
            }


        if(isNetworkAvailable()) {

            setContentView(R.layout.activity_choose_route);

            TextView empty = (TextView) findViewById(android.R.id.empty);
            empty.setVisibility(View.VISIBLE);

            SQLiteDatabase db = myDbHelper.getReadableDatabase();

            String TABLE_NAME = "Stops";
            Cursor cursor = db.query(true, TABLE_NAME , new String[] { MySQLiteHelper.LINE_ID, MySQLiteHelper.STATION}, null, null, null, null, null, null);
             startManagingCursor(cursor);
            String[] columns = new String[] { MySQLiteHelper.STATION };

            // the XML defined views which the data will be bound to
            int[] to = new int[] { R.id.text };


            SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.todo_row, cursor, columns, to);
            setListAdapter(adapter);
            registerForContextMenu(getListView());


        } else {

            setContentView(R.layout.no_connection);

        }


    }

    private boolean isNetworkAvailable() {
        ConnectivityManager connectivityManager 
              = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null;
    }   


}

And the logcat.

12-17 14:07:27.827: W/dalvikvm(23119): threadid=1: thread exiting with uncaught exception (group=0x40de8930)
12-17 14:07:27.847: E/AndroidRuntime(23119): FATAL EXCEPTION: main
12-17 14:07:27.847: E/AndroidRuntime(23119): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sembasys.metrosleepnyc/com.sembasys.metrosleepnyc.ChooseRoute}: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.ActivityThread.access$600(ActivityThread.java:141)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.os.Handler.dispatchMessage(Handler.java:99)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.os.Looper.loop(Looper.java:137)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.ActivityThread.main(ActivityThread.java:5039)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at java.lang.reflect.Method.invokeNative(Native Method)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at java.lang.reflect.Method.invoke(Method.java:511)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at dalvik.system.NativeStart.main(Native Method)
12-17 14:07:27.847: E/AndroidRuntime(23119): Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at com.sembasys.metrosleepnyc.MySQLiteHelper.openDataBase(MySQLiteHelper.java:126)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at com.sembasys.metrosleepnyc.ChooseRoute.onCreate(ChooseRoute.java:36)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.Activity.performCreate(Activity.java:5104)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
12-17 14:07:27.847: E/AndroidRuntime(23119):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
12-17 14:07:27.847: E/AndroidRuntime(23119):    ... 11 more

Answers

According to your own code, openDatabase() looks for your database in the /databases folder, but the database is still in the /assets folder until you call createDatabase() (or copyDatabase() directly). You must call createDataBase() to copy the database into the appropriate location before trying to open it.