SOLUTION
I had to override the getReadableDatabase() and getWritableDatabase() in my custom DBHelper class.
I am facing a unique kind of problem.
Until now, I have written Android apps that have used one SQLite DB internally on the phone memory, and it works perfectly. Now I wanted to add another DB and wanted to store it on the SD card. I did this by modifying the DatabaseHelper class that we usually use. I have also written a script that transfers the db from the assets folder to the SD card for one DB and the internal memory location for another.
Now the problem that I am facing is that when I try to access the external DB, android creates an internal DB in the /data/data/package_name/databases folder and thus I end up getting no such table exception.
Can someone tell me why I am getting this error!
Edit 1
My DB Helper Class
public class DBHelper extends SQLiteOpenHelper {
private Context myContext;
private String DB_PATH;
private String DB_NAME;
private boolean isExternal;
private SQLiteDatabase myDataBase;
private final String TAG = "ERROR";
public DBHelper(Context AppC, String DB_NAME, boolean isExternal,
int DB_VERSION) {
super(AppC, DB_NAME + ".sqlite", null, DB_VERSION);
this.myContext = AppC;
this.isExternal = isExternal;
this.DB_NAME = DB_NAME;
setDbPath();
}
private void setDbPath() {
if (this.isExternal) {
try {
DB_PATH = Environment.getExternalStorageDirectory()
+ "/myappname/";
} catch (Exception e) {
DB_PATH = "/mnt/sdcard/myappname/";
}
} else {
try {
DB_PATH = Environment.getDataDirectory()
+ "/data/my.app.package/databases/";
} catch (Exception e) {
DB_PATH = "data/data/my.app.package/databases/";
}
}
}
/**
* Creates a empty database on the system and rewrites it with your own
* database.
* */
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (!dbExist) {
try {
copyDataBase();
} catch (Exception E) {
// MRC
}
}
}
/**
* 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 transferring byte streams.
* */
private void copyDataBase() throws IOException {
String filePath = DB_PATH + this.DB_NAME + ".sqlite";
if (this.isExternal) {
File file = new File(filePath);
if (!file.exists()) {
File dir = new File(DB_PATH);
if (dir.exists() || dir.mkdirs()) {
transferFromAssets(this.DB_NAME + ".zip", filePath);
} else {
Log.d(TAG, "Unable to create dir " + DB_PATH);
}
}
} else {
// By calling this method and empty database will be created
// into the default system path of your application so we
// will be able to overwrite that database with our
// database.
SQLiteDatabase db_Read = this.getReadableDatabase();
db_Read.close();
transferFromAssets(this.DB_NAME + ".zip", filePath);
}
}
private void transferFromAssets(String from, String to) throws IOException {
ZipInputStream myInput = new ZipInputStream(myContext.getAssets().open(
from));
myInput.getNextEntry(); // Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(to);
// transfer bytes from the inputfile to the outputfile
AndroidUtil.copyStream(myInput, myOutput);
}
/**
* 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() {
File dbFile = new File(DB_PATH + this.DB_NAME + ".sqlite");
return dbFile.exists();
}
public void openDataBase() throws SQLException {
String myPath = DB_PATH + this.DB_NAME + ".sqlite";
Log.d(TAG, "Opening DB:" + myPath);
myDataBase = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
*My Internal Memory DB’s class’s constructor *
public WordsDB(Context AppC) {
DBAPI = new DBHelper(AppC, "DB_NAME", false, 11);
this.AppC = AppC;
try {
DBAPI.createDataBase();
DBAPI.openDataBase();
} catch (IOException e) {
CustomToast.Toast(AppC, "", TCategory_E.CRITICAL_ERROR,
TDuration_E.LONG, TPosition_E.CENTER);
// MRC
}
}
** My External DB class’s constructor **
public BackupDB(Context AppC) {
DBAPI = new DBHelper(AppC, "/mnt/sdcard/myapp/backup-db",
true, 11);
this.AppC = AppC;
try {
DBAPI.createDataBase();
DBAPI.openDataBase();
} catch (IOException e) {
CustomToast.Toast(AppC, "", TCategory_E.CRITICAL_ERROR,
TDuration_E.LONG, TPosition_E.CENTER);
// MRC
}
}
Edit 2
The function in the external DB’s helper class that leads to the error:
public void setValue(int No, int Stars) {
try {
ContentValues update = new ContentValues();
update.put(COL_STARRED, Stars);
String args[] = { No + "" };
SQLDB = DBAPI.getWritableDatabase();
SQLDB.acquireReference();
SQLDB.update(TABLE_NAME, update, COL_ID + "=?", args);
SQLDB.releaseReference();
SQLDB.close();
} catch (Exception E) {
Log.d(TAG, E.getMessage());
}
}
If I try to use the external DB as an internal DB, there is no error which leads me to think that there is something wrong that I am doing for an external DB.
Can you please provide some code?
Can you please describe what modification did you made?
If you are using
SQLiteOpenHelper, be aware that DB path, that is passed to it’s constructor – is relative to /data/data/package/databases/ folder, so you cannot pass SD path there. If you will still need this – I’ll suggest usingContextWrapperand redefining it’sgetDatabasePathmethod to point to your SD DB.