It worked by using the hard coded path. Is my path wrong? This is my code for getting the path
public class DatabaseAssets extends SQLiteOpenHelper {
private static String dbName = "questions.db";
Context context;
File dbFile;
public DatabaseAssets(Context context) {
super(context, "questions.db", null, 1);
this.context = context;
File DB_PATH = context.getDatabasePath(dbName);
String db = DB_PATH.getAbsolutePath();
dbFile= new File(db + "questions.db");
}
This is my getWritableDatabase and getReadableDatabase code.
@Override
public synchronized SQLiteDatabase getWritableDatabase() {
if(!dbFile.exists()){
SQLiteDatabase db = super.getWritableDatabase();
copyDataBase(db.getPath());
}
return super.getWritableDatabase();
}
@Override
public synchronized SQLiteDatabase getReadableDatabase() {
if(!dbFile.exists()){
SQLiteDatabase db = super.getReadableDatabase();
copyDataBase(db.getPath());
}
return super.getReadableDatabase();
}
This is my copy code, but I don't think this is the problem.
private void copyDataBase(String dbPath){
try{
InputStream assestDB = context.getAssets().open("databases/"+"questions.db");
OutputStream appDB = new FileOutputStream(dbPath,false);
byte[] buffer = new byte[1024];
int length;
while ((length = assestDB.read(buffer)) > 0) {
appDB.write(buffer, 0, length);
}
appDB.flush();
appDB.close();
assestDB.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
I believe that your issue is because you are using SQLiteDatabase db = super.getReadableDatabase();
or getWritableDatabase (doesn't matter which) and also that you are appending the database name to the database name (and thus the path will be data/data/<the_package_name>/databases/questions.dbquestions.db instead of data/data/<the_package_name>/databases/questions.db) :-
You could fix the path name issue using either :-
public DatabaseAssets(Context context) {
super(context, "questions.db", null, 1);
this.context = context;
File DB_PATH = context.getDatabasePath(dbName);
String db = DB_PATH.getAbsolutePath();
//dbFile = new File(db + "questions.db");
// path will be data/data/<the_package_name>/database/questions.dbquestions.db
dbFile = new File(db);
}
or :-
public DatabaseAssets(Context context) {
super(context,dbName,null,1);
this.context = context;
dbFile = context.getDatabasePath(dbName);
}
In regard to the first mentioned issue, getting a writable or readable database has been used historically to circumvent an issue in that the copy of the asset would fail (due to the databases directory not existing when an App is installed). What this does is create a database which is then overridden JUST to create the databases directory.
With later versions of Android the default mode is now WAL (Write-Ahead Logging), it used to be Journal. With WAL changes to the database are written to the WAL file. Copying the asset will only copy the database not the WAL file. The database open detects an issue (the WAL part does not tally with the database) and the overly kind Android API creates a new empty database rather than failing.
To avoid this issue you can create the missing directory (which is actually more efficient anyway). So instead of :-
if(!dbFile.exists()){
SQLiteDatabase db = super.getWritableDatabase();
copyDataBase(db.getPath());
}
Use :-
if(!dbFile.exists()){
if (!dbFile.getParentFile().exists) {
dbfile.mkdirs()
}
copyDataBase(dbFile.getPath());
}