I am trying to create an app. App is opening in Emulator. But when I am trying to open the app in real device, it is crashing. I tried many solutions regarding my problem. but I am unable to solve my problem. I added DatabaseHelper, Logcat. I added android.permission in AndroidManifest.xml but failed to get solution. App is not opening. Application terminated. not opening. Please suggest to solve this problem.
I deleted the app before running the app in real device. But problem remains same.
DatabaseHelper.java
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
String DB_PATH = null;
private static String DB_NAME = "kriyayoga.db";
private static SQLiteDatabase myDataBase;
private final Context myContext;
private static final int DATABASE_VERSION = 1;
public static synchronized DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context.getApplicationContext());
}
return mInstance;
}
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DATABASE_VERSION);
this.myContext = context;
this.DB_PATH = "/data/data/" + context.getPackageName() + "/" + "databases/";
//this.DB_PATH = this.myContext.getDatabasePath(DB_NAME).getAbsolutePath();
Log.e("Path 1", DB_PATH);
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
} else {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase() {
File dbFile = myContext.getDatabasePath(DB_NAME);
return dbFile.exists();
}
private void copyDataBase() throws IOException {
InputStream myInput = myContext.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
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) {
if (newVersion > oldVersion)
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onOpen(SQLiteDatabase db) {
onCreate(db);
}
}
Logcat Problem shows at ListNavAdapter.java
E/SQLiteLog: (1) no such table: yoga
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
android.database.sqlite.SQLiteException: no such table: yoga (code 1 SQLITE_ERROR): , while compiling: SELECT heading FROM yoga ORDER BY _id
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:946)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:527)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1347)
at com.priyanka.kriyayoga.ListNavAdapter.onViewCreated(ListNavAdapter.java:81)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1471)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:620)
at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1395)
at android.app.Activity.performStart(Activity.java:7293)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3196)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2011)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7135)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)
When I am running the app in real device it says runtime exception
App is experiencing crashes.
in AndroidManifest.xml I added
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
In ListNavAdapter I used to get data
SQLiteDatabase sqLiteDatabase = DatabaseHelper.getInstance(this.getContext()).getReadableDatabase();
Cursor cursor1 = sqLiteDatabase.rawQuery("SELECT heading FROM yoga ORDER BY _id", new String[]{});
Your issue is very likely that the device on which you are trying this is Android 9+. With 9+ the default was changed from journal mode to WAL (Write Ahead Logging).
Using getWritableDatabase (or getReadableDatabase, they both open the database as writable if the database can be opened as writable) before the copy results in the -wal and -shm files being created. When the database is copied the -wal and -shm files remain. When the copied database is opened, the -wal file is opened by SQLite and a discrepancy is found as the -wal file belongs to the overwritten database file NOT the copied database file. In order to provide a usable database, the corrupt database file is then overwritten with a valid and therefore empty database file and hence why the table(s) appear to have vanished.
Historically (I believe as I can see no other reason) getWritableDatabase was used to get-around a cannot open file ENONENT error, this because when a App is first run, the databases directory does not exists in the data/data/package_name directory (so the copy of the file fails).
The following changes will circumvent this issue by making the databases directory (which is more efficient) when needed.
First change :-
private boolean checkDataBase() {
File dbFile = myContext.getDatabasePath(DB_NAME);
return dbFile.exists();
}
to be :-
private boolean checkDataBase() {
File dbFile = myContext.getDatabasePath(DB_NAME);
if (dbFile.exists()) return true;
if (!dbFile.getParentFile().exists()) {
dbfile.getParentFile().mkdirs();
}
return false;
}
And then remove or comment out the line this.getReadableDatabase(), in the createDataBase method.
Note the above code is in-principle code, it has not been run or tested and may therefore contain errors.
Related
I'm trying to load an existing SQLite database into Android Studio. However, the database adapter is returning an empty database instead of giving me a copy of my populated database.
I've got my permissions
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
My DBAdapter
package com.example.testbed;
import android.app.SearchManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
public class DBAdapter extends SQLiteOpenHelper{
public static final String TAG = DBAdapter.class.getSimpleName();
public static int flag;
private static SQLiteDatabase db;
private static String DB_NAME = "recipes.db";
public static String TABLE_NAME = "DrinkRecipes_Loaded";
public static String DB_PATH = "";
public static String COL_WORD = "WORD";
String outFileName = "";
public static Context myContext;
private String loadedTable = "DrinkRecipes_Loaded";
private String specialtyTable = "DrinkRecipes_Specialty";
private String beautyTable = "DrinkRecipes_Beauty";
private String kidsTable = "DrinkRecipes_Kids";
private String shakesTable = "DrinkRecipes_Shakes";
public DBAdapter(Context context) {
super(context, DB_NAME, null, 1);
this.myContext = context;
ContextWrapper cw = new ContextWrapper(context);
DB_PATH = "/data/data" + BuildConfig.APPLICATION_ID + "/databases/";
Log.e(TAG, "Databasehelper: DB_PATH " + DB_PATH);
outFileName = DB_PATH + DB_NAME;
File file = new File(DB_PATH);
Log.e(TAG, "Databasehelper: " + file.exists());
if (!file.exists()) {
file.mkdir();
}
}
/**
* 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 {
checkDB = SQLiteDatabase.openDatabase(outFileName, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
try {
copyDataBase();
} catch (IOException e1) {
e1.printStackTrace();
}
}
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 {
Log.i("Database",
"New database is being copied to device!");
byte[] buffer = new byte[1024];
OutputStream myOutput = null;
int length;
// Open your local db as the input stream
InputStream myInput = null;
try {
myInput = myContext.getAssets().open(DB_NAME);
// transfer bytes from the inputfile to the
// outputfile
myOutput = new FileOutputStream(DB_PATH + DB_NAME);
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.close();
myOutput.flush();
myInput.close();
Log.i("Database",
"New database has been copied to device!");
} catch (IOException e) {
e.printStackTrace();
}
}
public void openDataBase() throws SQLException {
//Open the database
String myPath = DB_PATH + DB_NAME;
db = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
Log.e(TAG, "openDataBase: Open " + db.isOpen());
}
// we have created a new method for reading loaded recipes.
public ArrayList<recipeModal> readLoadedRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor cursorRecipes = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);
// on below line we are creating a new array list.
ArrayList<recipeModal> recipeModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (cursorRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
recipeModalArrayList.add(new recipeModal(cursorRecipes.getString(0),
cursorRecipes.getString(1),
cursorRecipes.getString(2),
cursorRecipes.getString(3),
cursorRecipes.getString(4),
cursorRecipes.getString(5),
cursorRecipes.getString(6),
cursorRecipes.getString(7),
cursorRecipes.getString(8)));
} while (cursorRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
cursorRecipes.close();
return recipeModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<beautyModal> readBeautyRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor beautyRecipes = db.rawQuery("SELECT * FROM " + beautyTable, null);
// on below line we are creating a new array list.
ArrayList<beautyModal> beautyModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (beautyRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
beautyModalArrayList.add(new beautyModal(beautyRecipes.getString(0),
beautyRecipes.getString(1),
beautyRecipes.getString(2),
beautyRecipes.getString(3),
beautyRecipes.getString(4),
beautyRecipes.getString(5)));
} while (beautyRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
beautyRecipes.close();
return beautyModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<specialtyModal> readSpecialtyRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor specialtyRecipes = db.rawQuery("SELECT * FROM " + specialtyTable, null);
// on below line we are creating a new array list.
ArrayList<specialtyModal> specialtyModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (specialtyRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
specialtyModalArrayList.add(new specialtyModal(specialtyRecipes.getString(0),
specialtyRecipes.getString(1),
specialtyRecipes.getString(2),
specialtyRecipes.getString(3),
specialtyRecipes.getString(4),
specialtyRecipes.getString(5),
specialtyRecipes.getString(6),
specialtyRecipes.getString(7)));
} while (specialtyRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
specialtyRecipes.close();
return specialtyModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<kidsModal> readKidsRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor kidsRecipes = db.rawQuery("SELECT * FROM " + kidsTable, null);
// on below line we are creating a new array list.
ArrayList<kidsModal> kidsModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (kidsRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
kidsModalArrayList.add(new kidsModal(kidsRecipes.getString(0),
kidsRecipes.getString(1),
kidsRecipes.getString(2),
kidsRecipes.getString(3),
kidsRecipes.getString(4)));
} while (kidsRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
kidsRecipes.close();
return kidsModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<shakesModal> readShakesRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor shakesRecipes = db.rawQuery("SELECT * FROM " + shakesTable, null);
// on below line we are creating a new array list.
ArrayList<shakesModal> shakesModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (shakesRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
shakesModalArrayList.add(new shakesModal(shakesRecipes.getString(0),
shakesRecipes.getString(1),
shakesRecipes.getString(2),
shakesRecipes.getString(3),
shakesRecipes.getString(4)));
} while (shakesRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
shakesRecipes.close();
return shakesModalArrayList;
}
#Override
public synchronized void close() {
if (db != null)
db.close();
super.close();
}
public void onCreate(SQLiteDatabase arg0) {
}
#Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
}
}
And when I call it, the only thing that I get is a crashing application and an empty database written to the correct path. I'm very desperate for some solutions to this problem and would appreciate any feedback.
I've tried a few different solutions that seemed promising on Google, but no luck.
EDIT: Stack trace at error
E/SQLiteLog: (1) no such table: DrinkRecipes_Loaded in "SELECT * FROM DrinkRecipes_Loaded"
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.testbed, PID: 4732
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.testbed/com.example.testbed.ViewRecipes}: android.database.sqlite.SQLiteException: no such table: DrinkRecipes_Loaded (code 1 SQLITE_ERROR[1]): , while compiling: SELECT * FROM DrinkRecipes_Loaded
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3851)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4027)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2336)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:247)
at android.app.ActivityThread.main(ActivityThread.java:8676)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Caused by: android.database.sqlite.SQLiteException: no such table: DrinkRecipes_Loaded (code 1 SQLITE_ERROR[1]): , while compiling: SELECT * FROM DrinkRecipes_Loaded
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1463)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:901)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:590)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:62)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:2063)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:2002)
at com.example.testbed.DBAdapter.readLoadedRecipes(DBAdapter.java:128)
at com.example.testbed.ViewRecipes.onCreate(ViewRecipes.java:84)
at android.app.Activity.performCreate(Activity.java:8215)
at android.app.Activity.performCreate(Activity.java:8199)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3824)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4027)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2336)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:247)
at android.app.ActivityThread.main(ActivityThread.java:8676)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
There are a few issues with your code.
You are trying to make the database file a directory rather than making the parent the directory.
You are not catering for later android versions that default to using WAL (write-ahead logging) as opposed to journal logging by using getReabableDatabase when creating (copying the asset).
getReadableDatabase will do as it says and create the database. The copy then overwrites this (if it works).
However, in WAL mode two additional files are created for the WAL logging and populated accordingly. Then:
After the asset has been copied SQLite determines that the WAL file is not the WAL file for the copied database and therefore fails to open the potentially corrupt database.
The Android API detects this failure but does what it has been asked and creates an empty database and hence the Table not found.
Using getReadableDatabase just to circumvent the databases directory not existing is overkill/inefficient as all the processing to create a new database is undertaken.
Here's a rewrite of your code noting that:-
all of the access methods have been commented out (rather than create all the classes)
the createDatabase and checkDatabase methods have been commented out. They have been replaced by the getDatabase method.
the CopyDatabase method has been changed to return false if an io error occurs (getDatabase then throws a runTimeException)
The getDatabase method
checks to see if the database exists and returns if it does. Otherwise, it
checks to see if the parentFile (databases directory) exists,
if not then it makes the directory (and potentially other ones although they should always exist)
calls the CopyDatabase method
So the code (with much of the original code commented out) is :-
public class DBAdapter extends SQLiteOpenHelper {
public static final String TAG = DBAdapter.class.getSimpleName();
public static int flag;
private static SQLiteDatabase db;
private static String DB_NAME = "recipes.db";
public static String TABLE_NAME = "DrinkRecipes_Loaded";
public static String DB_PATH = "";
public static String COL_WORD = "WORD";
String outFileName = "";
public static Context myContext;
private String loadedTable = "DrinkRecipes_Loaded";
private String specialtyTable = "DrinkRecipes_Specialty";
private String beautyTable = "DrinkRecipes_Beauty";
private String kidsTable = "DrinkRecipes_Kids";
private String shakesTable = "DrinkRecipes_Shakes";
public DBAdapter(Context context) {
super(context, DB_NAME, null, 1);
this.myContext = context;
//ContextWrapper cw = new ContextWrapper(context); Not used
DB_PATH = context.getDatabasePath(DB_NAME).getPath(); // no need to hard code anything bar the DB name
/*
//DB_PATH = "/data/data" + BuildConfig.APPLICATION_ID + "/databases/";
Log.e(TAG, "Databasehelper: DB_PATH " + DB_PATH);
outFileName = DB_PATH + DB_NAME;
File file = new File(DB_PATH);
Log.e(TAG, "Databasehelper: " + file.exists());
if (!file.exists()) {
file.getParentFile().mkdirs(); // CHANGED you don't want the database to be a directory
}
*/
getDatabase(context);
}
/*<<<<< ADDED >>>>>*/
private void getDatabase(Context context) {
File dbFile = new File(context.getDatabasePath((DB_NAME)).getPath());
if (dbFile.exists()) return; // Database found so all done
// Otherwise ensure that the database directory exists (does not by default until later versions)
if (!dbFile.getParentFile().exists()) {
dbFile.getParentFile().mkdirs();
}
if (!copyDataBase()) {
throw new RuntimeException("Unable to copy database from the asset (check the stack-trace).");
}
}
/**
* Creates a empty database on the system and rewrites it with your own database.
*/
/* NOTE NEEDED/UNSAFE as getDatabase create a database and for later version of Android it will be in WAL mode
thus the additional WAL files are created. When the database is then opened SQLite see that the WAL files are not
for the copied database and thus the open fails. Android's API then creates an new empty database file
*/
/*
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(); // Causes issues if in WAL mode and result in database
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 {
checkDB = SQLiteDatabase.openDatabase(outFileName, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
try {
copyDataBase();
} catch (IOException e1) {
e1.printStackTrace();
}
}
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 boolean /* <<<<< CHANGED SIGNATURE */ copyDataBase() {
Log.i("Database",
"New database is being copied to device!");
byte[] buffer = new byte[4096]; //Probably more efficient as default page size will be 4k
OutputStream myOutput = null;
int length;
// Open your local db as the input stream
InputStream myInput = null;
try {
myInput = myContext.getAssets().open(DB_NAME);
// transfer bytes from the inputfile to the
// outputfile
myOutput = new FileOutputStream(DB_PATH);
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.close();
myOutput.flush();
myInput.close();
Log.i("Database",
"New database has been copied to device!");
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public void openDataBase() throws SQLException {
//Open the database
String myPath = DB_PATH + DB_NAME;
db = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
Log.e(TAG, "openDataBase: Open " + db.isOpen());
}
/*
// we have created a new method for reading loaded recipes.
public ArrayList<recipeModal> readLoadedRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor cursorRecipes = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);
// on below line we are creating a new array list.
ArrayList<recipeModal> recipeModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (cursorRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
recipeModalArrayList.add(new recipeModal(cursorRecipes.getString(0),
cursorRecipes.getString(1),
cursorRecipes.getString(2),
cursorRecipes.getString(3),
cursorRecipes.getString(4),
cursorRecipes.getString(5),
cursorRecipes.getString(6),
cursorRecipes.getString(7),
cursorRecipes.getString(8)));
} while (cursorRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
cursorRecipes.close();
return recipeModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<beautyModal> readBeautyRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor beautyRecipes = db.rawQuery("SELECT * FROM " + beautyTable, null);
// on below line we are creating a new array list.
ArrayList<beautyModal> beautyModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (beautyRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
beautyModalArrayList.add(new beautyModal(beautyRecipes.getString(0),
beautyRecipes.getString(1),
beautyRecipes.getString(2),
beautyRecipes.getString(3),
beautyRecipes.getString(4),
beautyRecipes.getString(5)));
} while (beautyRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
beautyRecipes.close();
return beautyModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<specialtyModal> readSpecialtyRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor specialtyRecipes = db.rawQuery("SELECT * FROM " + specialtyTable, null);
// on below line we are creating a new array list.
ArrayList<specialtyModal> specialtyModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (specialtyRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
specialtyModalArrayList.add(new specialtyModal(specialtyRecipes.getString(0),
specialtyRecipes.getString(1),
specialtyRecipes.getString(2),
specialtyRecipes.getString(3),
specialtyRecipes.getString(4),
specialtyRecipes.getString(5),
specialtyRecipes.getString(6),
specialtyRecipes.getString(7)));
} while (specialtyRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
specialtyRecipes.close();
return specialtyModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<kidsModal> readKidsRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor kidsRecipes = db.rawQuery("SELECT * FROM " + kidsTable, null);
// on below line we are creating a new array list.
ArrayList<kidsModal> kidsModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (kidsRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
kidsModalArrayList.add(new kidsModal(kidsRecipes.getString(0),
kidsRecipes.getString(1),
kidsRecipes.getString(2),
kidsRecipes.getString(3),
kidsRecipes.getString(4)));
} while (kidsRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
kidsRecipes.close();
return kidsModalArrayList;
}
// we have created a new method for reading loaded recipes.
public ArrayList<shakesModal> readShakesRecipes() {
// on below line we are creating a
// database for reading our database.
SQLiteDatabase db = this.getReadableDatabase();
// on below line we are creating a cursor with query to read data from database.
Cursor shakesRecipes = db.rawQuery("SELECT * FROM " + shakesTable, null);
// on below line we are creating a new array list.
ArrayList<shakesModal> shakesModalArrayList = new ArrayList<>();
// moving our cursor to first position.
if (shakesRecipes.moveToFirst()) {
do {
// on below line we are adding the data from cursor to our array list.
shakesModalArrayList.add(new shakesModal(shakesRecipes.getString(0),
shakesRecipes.getString(1),
shakesRecipes.getString(2),
shakesRecipes.getString(3),
shakesRecipes.getString(4)));
} while (shakesRecipes.moveToNext());
// moving our cursor to next.
}
// at last closing our cursor
// and returning our array list.
shakesRecipes.close();
return shakesModalArrayList;
}
*/
#Override
public synchronized void close() {
if (db != null)
db.close();
super.close();
}
public void onCreate(SQLiteDatabase arg0) {
}
#Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
}
}
The above has been tested but using a substitute database renamed to recipes.db (NorthWind as it's pretty large) the log for a new install :-
2022-03-27 10:22:11.223 I/Database: New database is being copied to device!
2022-03-27 10:22:11.455 I/Database: New database has been copied to device!
AppInspection confirms that the database has been successfully copied (albeit not your database):-
Likewise Device File Explorer shows :-
I'm using an external sqlite database rather than creating one in my android studio project since the database will have some already populated data in it. But I have to insert some more data as well.
And when I insert any new data, it shows the new data but as I close my android app and open again to see the data, the newly inserted data through the app are somehow deleted, only prepopulated data are shown.
I am using DB browser for sqlite to create the external sqlite database and pre-populate it with some data there. In my android studio project, I added this database into my assets folder and implemented SQLiteOpenHelper class to access this database. Reading the data from the database table is a success. Now as I insert new data I can read the new data temporarily as well. Temporarily in the sense that after i close my app the new data are lost.
the table of my external sqlite database:
CREATE TABLE `table_name` (
`Id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`Content` TEXT NOT NULL
);
SQLiteOpenHelper class:
public class ProcessExternalDBHelper {
private static final String DATABASE_NAME = "database_name.db";
private static final int DATABASE_VERSION = 1;
private static String DATABASE_PATH = "";
private static final String DATABASE_TABLE = "table_name";
private static final String KEY_ROWID = "Id";
private static final String KEY_CONTENT = "Content";
private ExternalDbHelper ourHelper;
private final Context ourContext;
private SQLiteDatabase ourDatabase;
private static class ExternalDbHelper extends SQLiteOpenHelper {
public ExternalDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
if (Build.VERSION.SDK_INT >= 17) {
DATABASE_PATH = context.getApplicationInfo().dataDir +
"/databases/";
} else {
DATABASE_PATH = "/data/data/" + context.getPackageName() +
"/databases/";
}
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
}
}
public ProcessExternalDBHelper(Context context) {
ourContext = context;
}
//for reading
public ProcessExternalDBHelper openRead() throws SQLException {
ourHelper = new ExternalDbHelper(ourContext);
ourDatabase = ourHelper.getReadableDatabase();
return this;
}
//for writing
public ProcessExternalDBHelper openWrite() throws SQLException{
ourHelper = new ExternalDbHelper(ourContext);
ourDatabase = ourHelper.getWritableDatabase();
return this;
}
public void close() {
if (ourHelper != null) {
ourHelper.close();
}
}
//Create database in activity
public void createDatabase() throws IOException {
createDB();
}
//Create db if not exists
private void createDB() {
boolean dbExists = checkDatabase();
if (!dbExists) {
openRead();
try {
this.close();
copyDatabase();
} catch (IOException ie) {
throw new Error("Error copying database");
}
}
}
private boolean checkDatabase() {
boolean checkDB = false;
try {
String myPath = DATABASE_PATH + DATABASE_NAME;
File dbfile = new File(myPath);
checkDB = dbfile.exists();
} catch (SQLiteException e) {
}
return checkDB;
}
private void copyDatabase() throws IOException {
InputStream myInput = null;
OutputStream myOutput = null;
String outFileName = DATABASE_PATH + DATABASE_NAME;
try {
myInput = ourContext.getAssets().open(DATABASE_NAME);
myOutput = new FileOutputStream(outFileName);
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 (IOException ie) {
throw new Error("Copydatabase() error");
}
}
//To show all available contents in my database
public List<Model> findallContents() {
List<Model> mContents = new ArrayList<>();
String[] columns = new String[]{KEY_CONTENT};
Cursor cursor = ourDatabase.query(DATABASE_TABLE, columns, null, null,
null, null, null);
int iContent = cursor.getColumnIndex(KEY_CONTENT);
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
{
Model model= new Model();
model.setContent(cursor.getString(iContent));
mContents.add(model);
}
cursor.close();
return mContents;
}
public void addContent(String content) {
ContentValues contentValues = new ContentValues();
contentValues.put(KEY_CONTENT, content);
ourDatabase.insert(DATABASE_TABLE, null, contentValues);
ourDatabase.close();
}
}
My Model.java class:
public class Model {
private String mContent;
public String getContent() {
return mContent;
}
public void setContent(String content) {
this.mContent = content;
}
}
Finally my activity class where i read and write the data:
public class MainActivity extends AppCompatActivity {
private EditText editText_Content;
private ImageButton imageButton_Save;
private List<Model> mContentsArrayList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ProcessExternalDBHelper myDbHelper = new ProcessExternalDBHelper(this);
try {
myDbHelper.createDatabase();
} catch (IOException ioe) {
throw new Error("Unable to CREATE DATABASE");
} finally {
myDbHelper.close();
}
initialize();
GetContents();
imageButton_Save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!(editText_Content.getText().toString().trim().isEmpty()))
{
SaveContents();
}
}
});
}
private void initialize() {
editText_Content = findViewById(R.id.editText_contents);
imageButton_Save = findViewById(R.id.imageButton_save);
mContentsArrayList = new ArrayList<>();
}
//GetContents and show them later in my RecyclerView
private void GetContents() {
try {
mContentsArrayList.clear();
ProcessExternalDBHelper autoProcess = new
ProcessExternalDBHelper(this);
autoProcess.openRead();
mContentsArrayList.addAll(autoProcess.findallContents();
autoProcess.close();
} catch (Exception e) {
}
}
//For saving content into database
private void SaveContents() {
String content = editText_Content.getText().toString();
try {
ProcessExternalDBHelper autoProcess = new
ProcessExternalDBHelper(this);
autoProcess.openWrite(); //for writing into database
autoProcess.addContent(content);
autoProcess.close();
editText_Content.getText().clear();
} catch (Exception e) {
}
}
}
Finally I am using DB Browser for Sqlite (ver 3.10.1), android studio (ver 3.0.1), minSdkVersion 19.
I am expecting the newly inserted data into the database to be saved and later seen even when i close my app and and restart the app later. Thank You!
Your issue is that DATABASE_PATH isn't being reset and is therefore empty when createDatabase is invoked.
Therefore the check to see if the database exists fails to find the database (it's looking purely for the file database_db.db at the highest level of the file system, as such the file will not exist) and the database is copied overwriting the database that has data saved into it.
I'd suggest the following changes :-
private boolean checkDatabase() {
File dbfile = new File(ourContext.getDatabasePath(DATABASE_NAME).getPath());
if ( dbfile.exists()) return true;
File dbdir = dbfile.getParentFile();
if (!dbdir.exists()) {
dbdir.mkdirs();
}
return false;
}
This has the advantage that if the databases directory doesn't exist that it will be created and that it relies solely on the database name for the path.
There is also no need for the try/catch construct.
and optionally :-
private void copyDatabase() throws IOException {
InputStream myInput = null;
OutputStream myOutput = null;
String outFileName = ourContext.getDatabasePath(DATABASE_NAME).getPath(); //<<<<<<<<<< CHANGED
try {
myInput = ourContext.getAssets().open(DATABASE_NAME);
myOutput = new FileOutputStream(outFileName);
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 (IOException ie) {
throw new Error("Copydatabase() error");
}
}
Note if the above are applied there is no need for the SDK version check as the getDatabasePath method gets the correct path.
I try to use a sqlite database but the problem shows "no such table", the code works on some devices and some show that message.
class DatabaseHelper extends SQLiteOpenHelper {
private final String mDatabaseName;
private final Context mContext;
private final String mPath;
DatabaseHelper(Context context, String database, String path){
super(context,database,null,1);
this.mContext=context;
this.mDatabaseName=database;
this.mPath=path;
_createDatabase();
}
private void _createDatabase() {
if(_checkDatabase()){
return;
}
getReadableDatabase();
try {
_copyDatabase();
}catch (Exception e){
}
}
private void _copyDatabase() throws IOException {
InputStream inputStream = mContext.getAssets().open(mDatabaseName);
FileOutputStream fileOutputStream = new FileOutputStream(mPath+mDatabaseName);
byte[] bytes = new byte[1024];
do{
int n;
if((n=inputStream.read(bytes)) <= 0){
fileOutputStream.flush();
fileOutputStream.close();
return;
}
fileOutputStream.write(bytes,0,n);
}while (true);
}
private boolean _checkDatabase() {
return mContext.getDatabasePath(mDatabaseName).exists();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
And database adapter look this
class DatabaseAdapter
{
private SQLiteDatabase database;
private DatabaseHelper databaseHelper;
DatabaseAdapter(Context context, String database, String path){
databaseHelper = new DatabaseHelper(context, database, path);
}
void open(){
try{
database = databaseHelper.getReadableDatabase();
}
catch (SQLiteException e)
{
database = databaseHelper.getReadableDatabase();
}
}
boolean isOpened()
{
return this.database != null && this.database.isOpen();
}
Cursor _get_rows()
{
Cursor cursor = database.rawQuery("SELECT * FROM rows ORDER BY RANDOM() LIMIT 4;", null);
cursor.moveToFirst();
return cursor;
}
}
And database controller look this
public class DatabaseController {
private static DatabaseAdapter databaseAdapter;
public static Cursor _get_rows()
{
if(!databaseAdapter.isOpened()){
databaseAdapter.open();
}
return databaseAdapter._get_rows();
}
public static void initilization(Context activity) {
String dbName= "data.db";
databaseAdapter = new DatabaseAdapter(activity.getApplicationContext(),dbName,"/data/data/"+activity.getApplicationInfo().packageName+"/databases/");
}
}
i use in activity like this
DatabaseController.initilization(this);
Cursor c = DatabaseController._get_rows();
I could not find a solution to this problem, the database was already copied to the entire directory
I suspect that the issues is that you are trapping an exception in :-
private void _createDatabase() {
if(_checkDatabase()){
return;
}
getReadableDatabase();
try {
_copyDatabase();
}catch (Exception e){
}
}
So processing continues and an empty database is created and hence no table.
The root cause might be that the databases directory might not exist. You need to look at the exception that has been trapped to determine the exact error. e.g. e.printStackTrace();
The following is how you could create the databases directory (to resolve the ENOENT (No such file or directory) exception that may be the issue) :-
e.g.
private void _copyDatabase() throws IOException {
File dir = new File(mPath); //<<<<<<<<<< ADDED
if(!dir.exists()) { //<<<<<<<<<< ADDED
dir.mkdirs(); //<<<<<<<<<< ADDED
} //<<<<<<<<<< ADDED
InputStream inputStream = mContext.getAssets().open(mDatabaseName);
FileOutputStream fileOutputStream = new FileOutputStream(mPath+mDatabaseName);
byte[] bytes = new byte[1024];
do{
int n;
if((n=inputStream.read(bytes)) <= 0){
fileOutputStream.flush();
fileOutputStream.close();
return;
}
fileOutputStream.write(bytes,0,n);
}while (true);
}
It is also inadvisable to hard code paths e.g. using :-
databaseAdapter = new DatabaseAdapter(activity.getApplicationContext(),dbName,"/data/data/"+activity.getApplicationInfo().packageName+"/databases/");
It's better to get the path using the Context's getDatabasePath method.
Note the code is in-principle code, it has not been tested or run and may therefore contain errors.
Note on the devices on which you have issues you will need to delete the database (Clear the App's data or uninstall the App) before running any amended code.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I have a big problem in this project.
In this project, I want to read a db data become to a SQLite.
But there was also an Error happened.
I put the db data(last.db) in src→main→assets folder.
Process: net.macdidi.lasttest, PID: 4829
java.lang.ExceptionInInitializerError
at net.macdidi.lasttest.MainActivity.onCreate(MainActivity.java:20)
at android.app.Activity.performCreate(Activity.java:6262)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1125)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2458)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2565)
at android.app.ActivityThread.access$900(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1395)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.app.ActivityThread.main(ActivityThread.java:5821)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getFilesDir()' on a null object reference
at net.macdidi.lasttest.DatabaseHelper.<clinit>(SQLiteOpenHelper.java:18)
at net.macdidi.lasttest.MainActivity.onCreate(MainActivity.java:20)
at android.app.Activity.performCreate(Activity.java:6262)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1125)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2458)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2565)
at android.app.ActivityThread.access$900(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1395)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:168)
at android.app.ActivityThread.main(ActivityThread.java:5821)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)
and this is my code
class DatabaseHelper extends SQLiteOpenHelper {
private static Context context;
private static String DB_PATH = context.getFilesDir().getAbsolutePath();
private static String DB_NAME = "last.db";
private final Context mCtx;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, 1);
this.mCtx = context;
}
public boolean createDatabase() {
boolean dbExist = checkDatabase();
this.getReadableDatabase();
if (dbExist == false) {
if (copyDatabase() == false) {
return false;
}
}
return true;
}
private boolean checkDatabase() {
SQLiteDatabase checkDB = null;
String dbpath = DB_PATH + DB_NAME;
try {
checkDB = SQLiteDatabase.openDatabase(dbpath,
null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
return false;
}
if (checkDB != null) {
checkDB.close();
return true;
}
return false;
}
private boolean copyDatabase() {
try {
InputStream input = mCtx.getAssets().open(DB_NAME);
this.getReadableDatabase();
String outFileName = DB_PATH + DB_NAME;
OutputStream output =
new FileOutputStream(outFileName);
byte [] buffer = new byte[1024];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {
return false;
}
return true;
}
public void onCreate(SQLiteDatabase db) {
}
public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
}
}
I deeply hope someone can help me to solve this big problem for me.
private static String DB_PATH = context.getFilesDir().getAbsolutePath();
First, context is null at this point.
Second, do not attempt to call methods inherited from your Activity from a field initializer. Postpone that work until onCreate(), typically after super.onCreate().
So replace that line with:
private static String DB_PATH;
and in onCreate(), add:
DB_PATH=getFilesDir().getAbsolutePath();
Or, better yet, delete all this code and use SQLiteAssetHelper.
I try to copy SQLite database from assets directory to access it later. But I fail to do it!
public class DatabaseAdapter {
private static String DB_PATH = "/data/data/com.mypackage/databases/";
private static String DB_NAME = "database.sqlite";
private static String TABLE_NAME = "content_table";
private SQLiteDatabase database = null;
private final Context context;
public DatabaseAdapter(Context context){
this.context = context;
}
private void openDatabase() throws SQLiteException{
DatabaseHelper databaseHelper = new DatabaseHelper(context, DB_NAME);
SQLiteDatabase db = null;
if(!checkDatabase()){
try{
//Tried to create db before copying, so file should exist
db = databaseHelper.getReadableDatabase();
db.close();
copyDatabase();
}catch(IOException exception){
Log.d("DatabaseAdapter", "Error copying DB: "+exception);
}
}
database = SQLiteDatabase.openDatabase(DB_PATH+DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
}
private void closeDatabase(){
database.close();
}
public ArrayList<String> queryCategories(){
try{
openDatabase();
}catch(SQLiteException exc){
exc.printStackTrace();
}
//.............................
return result;
}
private boolean checkDatabase(){
File dbFile = new File(DB_PATH + DB_NAME);
return dbFile.exists();
}
private void copyDatabase() throws IOException{
InputStream inputStream = context.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream outputStream = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer))>0){
outputStream.write(buffer, 0, length);
}
outputStream.flush();
outputStream.close();
inputStream.close();
}
}
DatabaseHelper is simple:
ublic class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String name){
super(context, name, null, 1);
}
#Override
public void onCreate(SQLiteDatabase arg0) {
// TODO Auto-generated method stub
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
Tried everything! I tried playing with extention! But I still get an error:
Error copying DB: java.io.FileNotFoundException: /data/data/com.mypackage/databases/database.sqlite (No such file or directory)
I checked on emulator, my file is there, so I should be able to write to it!
Please, any help! It's driving me nuts!
UPD I tried to place it on SD card and it worked. But still can't get why I can't write it to app data folder.
I use this Helper and works fine:
public class DBHelper extends SQLiteOpenHelper{
private final static String DB_PATH = "/data/data/[YOUR PACKAGE HERE]/databases/";
String dbName;
Context context;
File dbFile;
public DBHelper(Context context, String dbName, CursorFactory factory,
int version) {
super(context, dbName, factory, version);
this.context = context;
this.dbName = dbName;
dbFile= new File(DB_PATH + dbName);
}
#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();
}
#Override
public void onCreate(SQLiteDatabase db) {}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
private void copyDataBase(String dbPath){
try{
InputStream assestDB = context.getAssets().open("databases/"+dbName);
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();
}
}
}
Take into account that the file extension of a database is .db and that my databases are into assets/databases/
I have the same problem and I have fixed it with another approach.
At the beginning, I declared the database path as everyone did:
dbPath="data/data/<my package name>/databases/data.db"
This is an exactly path, no mistake. But It' always fail when I try to open the OutPutFileStream to copy database. I don't know why. And then, I change the way to open the database as below:
dbPath = context.getDatabasePath(dbName);
OutputStream myOutput = new FileOutputStream(dbPath.getAbsolutePath());
The problem has ben solved. So surprise.
Hope this helps.
public static void copyDatabase(final Context ctx, String dbName) {
if (ctx != null) {
File f = ctx.getDatabasePath(dbName);
if (!f.exists()) {
// check databases exists
if (!f.getParentFile().exists())
f.getParentFile().mkdir();
try {
InputStream in = ctx.getAssets().open(dbName);
OutputStream out = new FileOutputStream(f.getAbsolutePath());
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
in.close();
out.close();
Logger.i("Database copy successed! " + f.getPath());
} catch (Exception ex) {
Logger.e(ex);
}
}
}
}
Please check the databases folder before your OutputStream.
like this,
File databaseFile = new File(context.getFilesDir().getAbsolutePath()
.replace("files", "databases"));
// check if databases folder exists, if not create it.
if (!databaseFile.exists()){
databaseFile.mkdir();
}