Android SQLite DB table does not exist after creation - android

I am copying a database file from my assets folder to the databases folder on install. I have a shared preference named firstRun with a default value of true. If this is true then I copy the database file and set the firstRun value to false. Immediately following this process I then query a database table for some data. On an older Android version (2.1) an SQLite Exception occurs (no such table) and the application crashes, on Android 4.2.1 the dbHelper logs the same message but continues to run and returns the values from the table it just failed to find. With the earlier Android version, if I launch the application again, the database table is found and all operations proceed normally. After the application crashes I can inspect the copied database and the table and rows are present. This does seem to be different from other issues where tables genuinely don't exist as I can see that they do. I wonder if it's some kind of synchronisation issue where the table doesn't exist immediately after the copy process, but does at some point when a process has finished. To my knowledge this is not done asynchronously so I'm not sure why.
Here is some code to show the problem:
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
boolean firstRun = prefs.getBoolean(getString(R.string.first_time_run), true);
if (firstRun) {
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(getString(R.string.first_time_run), Boolean.FALSE);
edit.commit();
try {
dbHelper.createDatabase();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
// This method will fire an exception the first time the app is run - no such table
Bundle metaData = dbHelper.fetchAppMetaData();
this.appTitle = metaData.getString("app_title");
this.normalId = Integer.parseInt(metaData.getString("normal_id"));
The fetchAppMetaData method is a basic sqlite.query:
Bundle metaData = new Bundle();
Cursor dbCursor = null;
SQLiteDatabase database = getReadableDatabase();
String[] cols = new String[] {"app_title", "normal_id"};
dbCursor = database.query(true, TBL_METADATA, cols, null, null, null, null, null, null);
if (dbCursor != null) {
dbCursor.moveToFirst();
which would eventually return a bundle.
The database creation method is:
//Open the local db as the input stream
InputStream dbFromAssets = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
// Check that the directory now exists
File f = new File(DB_PATH);
if (!f.exists()) {
f.mkdir();
}
// Open the empty db as the output stream
OutputStream appDatabase = new FileOutputStream(outFileName);
// Transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = dbFromAssets.read(buffer)) > 0){
appDatabase.write(buffer, 0, length);
}
// Close the streams - don't cross them!
appDatabase.flush();
appDatabase.close();
dbFromAssets.close();
Would be grateful for any ideas please.

Below is a cut and paste from working code. I use this on the launch of the MainActivity each time the application loads. Tested and working with versions 2.3 - 4.2:
Here is the code I'm using that does the check:
try
{
String destPath = "/data/data/" + getPackageName() + "/databases/(...your db...)";
File f = new File(destPath);
File c = new File("/data/data/" + getPackageName() + "/databases/");
// ---if directory doesn't exist then create it---
if (!c.exists())
{
c.mkdir();
}
// ---if db file doesn't exist then create it---
if (!f.exists())
{
CopyDB(getBaseContext().getAssets().open("...name of db from assets foleder..."), new FileOutputStream(destPath));
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
Here is the code I'm using that does the copying if not found:
public void CopyDB(InputStream inputStream, OutputStream outputStream) throws IOException
{
//---copy 1K bytes at a time---
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0)
{
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}
Hope this is hopeful...

The solution for me was to close the dbHelper after the database is created and before I try to use it again.
For example:
try {
dbHelper.createDatabase();
} catch (Exception e) {
}
dbHelper.close();
dbHelper.fetchAppMetaData();
Hope this helps someone else.

Related

Read/Access SQLite Database on Real Device without Root (Eclipse)

I been working on my project for a little bit while, I currently using emulator to access the DB I created. However, I wonder if anyone knows a way to access DB on a real device in DDMS eclipse?
I understand that to access DB on emulator is just open the data/data/package_name/database...I couldn't really find a way to check out DB on my real device. (The is some security issue in android device) The reason I want to use this is sometimes, emulator doesn't support GPS signal. Does any one knows is there any third-party lib/plugin I can download from ? Thank you so much.
i think it is work for you
**I am copy database in SdCard then access ** .
it is my database helper class
public class OpenDatabaseHelper extends SQLiteOpenHelper {
static final String DATABASE_NAME = "MyDB";
.
.
.
public OpenDatabaseHelper(Context context) {
// super(context, name, factory, version);
super(context, Environment.getExternalStorageDirectory()
+ File.separator + "/DataBase/" + File.separator
+ DATABASE_NAME, null, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
.
.
.
}
create object in Activity class
OpenDatabaseHelper db = new OpenDatabaseHelper(YourActivity.this);
call any method of database
db.DataBasemethod();
then put this code
try {
String destPath = Environment.getExternalStorageDirectory().toString();
File f = new File(destPath);
if (!f.exists()) {
f.mkdirs();
f.createNewFile();
// ---copy the db from the /data/data/ folder into
// the sdcard databases folder--- here MyDB is database name
CopyDB(new FileInputStream("/data/data/" + getPackageName()+ "/databases"), new FileOutputStream(destPath+ "/MyDB"));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
public void CopyDB(InputStream inputStream, OutputStream outputStream)
throws IOException {
// ---copy 1K bytes at a time---
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}

Access SqlLite Database which is shipped with application with SqlLite Database Browser

I have copied database in Android Project folder and It is working fine. Now, I am inserting values in table. So I want to know that Is there anyway by which I can see those data using SqlLite Database Browser ???
Database in assets folder, I opened it but I can't see any new data.
My Code to insert data:, It is working fine, no errors.
public boolean SaveUserResponse(String QId, String OptionId,
String ResponseDate) {
try {
ContentValues cv = new ContentValues();
cv.put("QId", QId);
cv.put("OptionId", OptionId);
cv.put("ResponseDate", ResponseDate);
mDb.insert("tblUserResponse", null, cv);
Log.d("SaveUserResponse", "User Response has been Saved.");
return true;
} catch (Exception ex) {
Log.d("SaveUserResponse", ex.toString());
return false;
}
You can fetch your DB from device using DDMS (can be found under android-sdk\tools). There open Device -> File Explorer. Then navigate to data\data\your_app and pull your DB to a disk.
BTW, your DB shouldn't be placed under assets, here is a code how to copy it from assets (you can call it on the first run of your app):
void copyDataBase() throws IOException {
String DB_PATH = "/data/data/<app>/databases/";
String DB_NAME = "db.sqlite";
//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();
}

Android external database in assets folder

I have an android application that is supposed to read and expand a database that is already created on sqlite...it works fine on emulator by putting database in "data/data/(packagename)/database" folder on the file explorer of emulator. Now problem is occuring with the real device. Obviously it doesnt have the database to open.I tried to put database in assets folder but I am not getting to open it with the openhelper.
you should copy the .db file from your assets folder to an internal/external storage. You can use following codes,
private static String DB_PATH = "/data/data/your package/database/";
private static String DB_NAME ="final.db";// Database name
To create a database,
public void createDataBase() throws IOException
{
//If database not exists copy it from the assets
boolean mDataBaseExist = checkDataBase();
if(!mDataBaseExist)
{
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/database/DB Name
private boolean checkDataBase()
{
File dbFile = new File(DB_PATH + DB_NAME);
return dbFile.exists();
}
Copy the database from assets
private void copyDataBase() throws IOException
{
InputStream mInput = getApplicationContext().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();
}
i hope it should help you.
you cant access the database from asset folder directly you need to copy it first to the path data/data/(packagename)/database then using it :
private String DB_PATH = "/data/data/" + "yourpackaename" + "/databases/" + "db.db";
in your onCreate()
is = getAssets().open("db.db");
write(is);
Then the method to call:
public void write(InputStream is) {
try {
OutputStream out = new FileOutputStream(new File(DB_PATH));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = is.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
is.close();
out.flush();
out.close();
System.err.println(out + "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
You need to first copy the Database file from assests to application data location using java code.Can You Post some code to show How are you opening or handling the database?
You cannot directly open files from assets folder. Instead, you need to copy the contents of your assets folder on an internal/external storage and later use the File path to open the file.
In emulators, its easier for you to access the data folder of your apps. However, on a real non-rooted android device, its not possible due to security reasons.
Do you have a pre-populated database and looking to integrate into your app? If yes, you can simply do with my library
On your app's first launch after installation
SuperDatabase database=new SuperDatabase(getApplicationContext(),"foods.db", AssetDatabaseMode.COPY_TO_SYSTEM);
On subsequent launches
SuperDatabase database=new SuperDatabase(getApplicationContext(),"foods.db", AssetDatabaseMode.READ_FROM_DEVICE);
Simply fire SQL queries
database.sqlInject("INSERT INTO food VALUES('Banana','Vitamin A');");
Get results on Array in CSV, JSON, XML
ArrayList<String> rows=new ArrayList<String>();
rows=database.sqlEjectCSV("SELECT * FROM food;");
for (int i=0;i<rows.size();i++)
{
//Do stuffs with each row
}
You need to include my library for this. Documentations here:
https://github.com/sangeethnandakumar/TestTube

Android restore backup from database file on sdcard

There are a few questions here on stackoverflow where people use BackupAgents to synchronize the apps data with googles cloud (see here). In my specific case the requirements are much more restrictive due to the nature of the more or less sensitive data. Everything must only be stored on the device itself and the app must not connect to the internet.
The main Activity contains a ViewPager which hosts a few ListFragments. Each ListFragment has its own Loader which swaps the cursor in a SimpleCursorAdapter class.
Before both backing up and restoring the database I destroy the loaders with:
getLoaderManager().destroy(LOADER_ID);
My backup function is similar to this anwser:
final String inFileName = "/data/data/<your.app.package>/databases/foo.db";
File dbFile = new File(inFileName);
FileInputStream fis = new FileInputStream(dbFile);
String outFileName = Environment.getExternalStorageDirectory()+"/database_copy.db";
// Open the empty db as the output stream
OutputStream output = new FileOutputStream(outFileName);
// Transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer))>0){
output.write(buffer, 0, length);
}
// Close the streams
output.flush();
output.close();
fis.close();
The restore function is similar in that it copies the database from the sdcard back into the internal app folder, stops the loaders and overwrites the database file.
public static void restore(Context context) throws IOException {
if (externalStorageIsWriteable()) {
// getBackupDir() is a path to the folder on the sdcard
File fileBackup = new File(getBackupDir(), WineSQLiteHelper.DB_NAME);
if (!fileBackup.exists()) {
throw new IOException("File not found");
}
File importFile = getImportDatabase();
try {
FileUtils.copyFile(fileBackup, importFile);
MySQLiteHelper dbHelper = new MySQLiteHelper(context);
dbHelper.close();
dbHelper = null;
File file = new File(Environment.getDataDirectory() + "/data/"
+ PACKAGE + "/databases/" + WineSQLiteHelper.DB_NAME);
FileUtils.copyFile(importFile, file);
// Remove temporary import file.
importFile.delete();
} catch (IOException e) {
throw e;
}
} else {
throw new IOException("External Storage not writeable");
}
}
But somehow the MainActivity gets recreated after I've overwritten the database file and I recieve a few
SQLiteException: no such column
My guess is that perhaps there are still open connections to the database, but I'm not sure about that since this is the first time I have to work with databases this closely.
How to properly close all database connections of a ContentProvider? I can't find anything in the documentation about this. And is this necessary?
How do I properly restore the database?

When opening sqlite getting an exception android

I had created database in my android app, then inserted a statement. Everything worked, so i wanted to get my database fro MY_PACKAGE/databses/ and copy it to sd card to be reachable.
This worked, but when i trying to open with my sqlite Firefox plugin i get this error:
SQLiteManager: Error in opening file Datas.sqlite - either the file is encrypted or corrupt
Exception Name: NS_ERROR_FILE_CORRUPTED
Exception Message: Component returned failure code: 0x8052000b (NS_ERROR_FILE_CORRUPTED) [mozIStorageService.openUnsharedDatabase]
Maybe i have to open with something else or i can't open this so easily ?
I will give all the code i used:
Handling my db i used all this code:
Using your own SQLite database in Android applications
Copying it to sd card this method:
public static boolean backUpDataBase(Context context) {
final String DATABASE_NAME = "Data.sqlite";
final String DATABASE_NAME_FULL = "/data/data/package/databases/"
+ DATABASE_NAME;
boolean result = true;
// Source path in the application database folder
String appDbPath = DATABASE_NAME_FULL;
// Destination Path to the sdcard app folder
String sdFolder = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/" + "Datas.sqlite";
File f = new File(sdFolder);
// if (!f.exists()) {
// f.mkdir();
// }
InputStream myInput = null;
OutputStream myOutput = null;
try {
// Open your local db as the input stream
myInput = new FileInputStream(appDbPath);
// Open the empty db as the output stream
myOutput = new FileOutputStream(f);
// 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);
}
} catch (IOException e) {
result = false;
e.printStackTrace();
} finally {
try {
// Close the streams
if (myOutput != null) {
myOutput.flush();
myOutput.close();
}
if (myInput != null) {
myInput.close();
}
} catch (IOException e) {
}
}
return result;
}
My database looks like this:
2 tables:
CREATE TABLE "Test" ("_id" INTEGER PRIMARY KEY NOT NULL UNIQUE , "Info" TEXT)
CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US')
And code to do all i need:
//return databse which is read and write
DataBaseHelper dataBase= Main.createOrOpenDB(mContext);
Main.backUpDataBase(mContext);
db = dataBase.myDataBase;
// Step 1: Inflate layout
setContentView(R.layout.tabs_fragment_activity);
try{
db.execSQL("INSERT INTO " +"Test" +" Values ('1','Inserted');");
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
So where is wrong, as insert works fine?
It sounds like there is a problem in your code to write it to the SD card (which I'm not seeing immediately).
I wonder, why are you copying it to the SDCard? It sounds like you merely want to check the file...
If that's actually your goal, then I would recommend running the emulator and simply using the DDMS view from eclipse, navigate to the file and click the button in the upper right corner whose tool-tip says "Pull a file from the device". What you get in the emulator should be exactly what you get on your phone.
try to use SQLiteOpenHelper | Android Developers

Categories

Resources