2

I have a database (.sqlite3) which I manually created. I have tried to incorporate it into my app based on this question/answer

I'm not sure why, but it keeps throwing me the "ErrorCopyingdatabase" error. I'm testing using the emulator.

Here is my code for incorporating my Database into the application. I made 2 classes.

public class DataBaseHelper extends SQLiteOpenHelper {
    private static String TAG = "DataBaseHelper"; // Tag just for the LogCat window
    //destination path (location) of our database on device
    private static String DB_PATH = "";
    private static String DB_NAME ="Characters";// Database name
    private SQLiteDatabase mDataBase;
    private final Context mContext;

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

    public void createDataBase() throws IOException {
        //If the database does not exist, copy it from the assets.

        boolean mDataBaseExist = checkDataBase();
        if(!mDataBaseExist)  {
            this.getReadableDatabase();
            this.close();
            try {
                //Copy the database from assests
                copyDataBase();
                Log.e(TAG, "createDatabase database created");
            }
            catch (IOException mIOException) {
                throw new Error("ErrorCopyingDataBase");
            }
        }
    }

    //Check that the database exists here: /data/data/your package/databases/Da Name
    private boolean checkDataBase() {
        File dbFile = new File(DB_PATH + DB_NAME);
        //Log.v("dbFile", dbFile + "   "+ dbFile.exists());
        return dbFile.exists();
    }

    //Copy the database from assets
    private void copyDataBase() throws IOException {
        InputStream mInput = mContext.getAssets().open(DB_NAME);
        String outFileName = DB_PATH + DB_NAME;
        OutputStream mOutput = new FileOutputStream(outFileName);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer))>0) {
            mOutput.write(mBuffer, 0, mLength);
        }
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    //Open the database, so we can query it
    public boolean openDataBase() throws SQLException {
        String mPath = DB_PATH + DB_NAME;
        //Log.v("mPath", mPath);
        mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
        //mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
        return mDataBase != null;
    }

    @Override
    public synchronized void close() {
        if(mDataBase != null)
            mDataBase.close();
        super.close();
    }
}

and...

public class TestAdapter {
    protected static final String TAG = "DataAdapter";

    private final Context mContext;
    private SQLiteDatabase mDb;
    private DataBaseHelper mDbHelper;

    public TestAdapter(Context context){
        this.mContext = context;
        mDbHelper = new DataBaseHelper(mContext);
    }

    public TestAdapter createDatabase() throws SQLException{
        try {
            mDbHelper.createDataBase();
        }
        catch (IOException mIOException)
        {
            Log.e(TAG, mIOException.toString() + "  UnableToCreateDatabase");
            throw new Error("UnableToCreateDatabase");
        }
        return this;
    }

    public TestAdapter open() throws SQLException{
        try{
            mDbHelper.openDataBase();
            mDbHelper.close();
            mDb = mDbHelper.getReadableDatabase();
        }
        catch (SQLException mSQLException){
            Log.e(TAG, "open >>"+ mSQLException.toString());
            throw mSQLException;
        }
        return this;
    }

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

    public ArrayList getTestData(int numberId){
        try {
            ArrayList<String> details = new ArrayList<>();
            String name = "";
            String summary = "";
            String trivia = "";
            String abilities = "";
            Cursor mcur = mDb.rawQuery("SELECT Name FROM CharactersInfo WHERE _id=?", new String[]{numberId + ""});

            if (mcur.getCount() > 0) {

                mcur.moveToFirst();
                name = mcur.getString(mcur.getColumnIndex("Name"));
                summary = mcur.getString(mcur.getColumnIndex("Summary"));
                trivia = mcur.getString(mcur.getColumnIndex("Trivia"));
                abilities = mcur.getString(mcur.getColumnIndex("Abilities"));


                details.add(name);
                details.add(summary);
                details.add(trivia);
                details.add(abilities);

            }
            return details;
        } catch (SQLException mSQLException) {
            Log.e(TAG, "getTestData >>"+ mSQLException.toString());
            throw mSQLException;
        }
    }
}

I tried to modify the code a bit to suit my needs... As I said, it cannot seem to copy the database, and keeps sending me the ErrorCopyingDatabase error (first code snippet).

Because of this, on subsequent tries there is no database in the first place to do my queries.

By the way, I activate everything from a button on a fragment.

TestAdapter mDbHelper = new TestAdapter(getActivity());
mDbHelper.createDatabase();
mDbHelper.open();
ArrayList cursor = mDbHelper.getTestData(indentifier);
TextView textView = (TextView) view.findViewById(R.id.character_trivia);
String string = "" + cursor;
textView.setText(string);

mDbHelper.close();

I've looked into it a bit and I'd really appreciate the assistance.

EDIT: Here is the logcat (only the fatal exception part), sorry for the late entry:

FATAL EXCEPTION: main
Process: com.lumberjackapps.dailyhero, PID: 2395
java.lang.Error: ErrorCopyingDataBase
    at com.lumberjackapps.dailyhero.DataBaseHelper.createDataBase(DataBaseHelper.java:57)
    at com.lumberjackapps.dailyhero.TestAdapter.createDatabase(TestAdapter.java:34)
    at com.lumberjackapps.dailyhero.CharacterInfo$1.onClick(CharacterInfo.java:46)
    at android.view.View.performClick(View.java:5198)
    at android.view.View$PerformClick.run(View.java:21147)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
E/EGL_emulation: tid 955: eglCreateSyncKHR(1294): error 0x3004 (EGL_BAD_ATTRIBUTE)
E/SurfaceFlinger: ro.sf.lcd_density must be defined as a build property
E/Surface: getSlotFromBufferLocked: unknown buffer: 0xa15d3f80
E/audio_hw_generic: Error opening input stream format 1, channel_mask 0010, sample_rate 16000
Community
  • 1
  • 1
Andy
  • 357
  • 2
  • 17

2 Answers2

1

For using database with your predefined data, you should better using AndroidSqliteAssetHelper.

Here some portion of it's readme:

An Android helper class to manage database creation and version management using an application's raw asset files.

This class provides developers with a simple way to ship their Android app with an existing SQLite database (which may be pre-populated with data) and to manage its initial creation and any upgrades required with subsequent version releases.

It is implemented as an extension to SQLiteOpenHelper, providing an efficient way for ContentProvider implementations to defer opening and upgrading the database until first use.

Rather than implementing the onCreate() and onUpgrade() methods to execute a bunch of SQL statements, developers simply include appropriately named file assets in their project's assets directory. These will include the initial SQLite database file for creation and optionally any SQL upgrade scripts.

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
0

I would suggest to change the copyDataBase() a little bit. Also, I removed the throws clasure. This way, logcat will print better information:

private void copyDataBase() {
    Log.v(TAG, "copyDataBase() - start");
    try {
        InputStream myInput = mContext.getAssets().open(DATABASE_NAME);

        // I think this line should solve your problem... Maybe, you are not setting the output file properly... Try like below:
        OutputStream myOutput = new FileOutputStream(mContext.getDatabasePath(DATABASE_NAME));

        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer))>0){
            myOutput.write(buffer, 0, length);
        }

        myOutput.flush();
        myOutput.close();
        myInput.close();

    } catch (Exception e) {
        Log.e(TAG, "copyDataBase(): " + e);

        StackTraceElement trace[] = e.getStackTrace();
        for(StackTraceElement element : trace) {
            Log.e(TAG, element.toString());

        }
    }
    Log.v(TAG, "copyDataBase() - end");
}

Then, you can delete this:

if(android.os.Build.VERSION.SDK_INT >= 17) {
    DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
}
else {
    DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
}

And change this:

if(!mDataBaseExist)  {
    this.getReadableDatabase();
    this.close();
    try {
        //Copy the database from assests
        copyDataBase();
        Log.e(TAG, "createDatabase database created");
    }
    catch (IOException mIOException) {
        throw new Error("ErrorCopyingDataBase");
    }
}

To this:

if(!mDataBaseExist)  {
    this.getReadableDatabase();
    this.close();
    copyDataBase();
    Log.e(TAG, "createDatabase database created");
}
guipivoto
  • 18,327
  • 9
  • 60
  • 75