SQLite static openDatabase database method error in Android - android

I created a static method to access my database on one of my activities but I keep getting error on opening the database.
MainActivity
public static String getStudentData() {
SQLiteDatabase sampleDB = null;
try {
//NOT WORKING
sampleDB = SQLiteDatabase.openDatabase("studentDB",null, SQLiteDatabase.CREATE_IF_NECESSARY);
//Also not working
//sampleDB = SQLiteDatabase.openOrCreateDatabase("studentDB", null);
Cursor c = sampleDB.rawQuery("SELECT * FROM student where id='1'", null);
if (c != null ) {
if (c.moveToFirst()) {
do {
//...
}while (c.moveToNext());
}
}
c.close();
} catch (Exception se ) {
} finally {
sampleDB.close();
}
}
OtherActivity
String student = MainActivity.getStudentData();
I have been getting sqlite3_open_v2("studentDB", &handle, 6, NULL) failed. Cant find what's wrong... I have also tried using MODE_WORLD_WRITEABLE. Currently using MODE_PRIVATEfor database creation. Please help me out!

First argument to openDatabase should be full path to db so if:
//The Android's default system path of your application database.
private static String DB_PATH = "/data/data/YOUR_PACKAGE/databases/";
private static String DB_NAME = "studentDB";
then you should call:
sampleDB = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.CREATE_IF_NECESSARY);

Use a method ContextWrapper#getDatabasePath(java.lang.String) and pass the result to SQLiteDatabase.openDatabase:
File dbFile= myActivity.getDatabasePath("studentDB");
sampleDB = SQLiteDatabase.openDatabase(dbFile.getAbsolutePath(), null, SQLiteDatabase.CREATE_IF_NECESSARY);

Related

Android: runtime exception database already closed

I'm using SQLite database for getting record of table where if specific record is exist.Always getting error while run the application = Caused by: java.lang.IllegalStateException: database /data/data/com.example.tazeen.xxx/databases/xx(conn# 0) already closed
dbhelper = new MyDbHelper(this);
SQLiteDatabase db1 = dbhelper.getReadableDatabase();
Cursor cursor = db1.rawQuery("select * from ActivityObjectList", null);
if (cursor.moveToFirst()) {
do {
imageName = cursor.getString(cursor.getColumnIndex("imageaudioPath"));
String strDownLoadStatus = cursor.getString(cursor.getColumnIndex("DownLoad_Status"));
} while (cursor.moveToNext());
}
cursor.close();
db1.close();
}
I believe you should close some thing like dbhelper.close()... instead of db1.close();
It's guess by understanding your code snippet.
You should close your sqlite db object in db helper class
#Override
public synchronized void close() {
if (mDb != null)
mDb.close();
super.close();
}
You should close sqlite database after read the table.
you would use
like this
Try{
enter code here
what do to
}
finally{
db.close();
}

A strange behavior for regualr sqlite operation on android

I had a problem which I already solved but I still wants to know WHY
the solution solved it.
I wrote an android app that had a sqlite db after a couple of times I debugged it
The oncreate method in the db didnt got called (even though everything worked fine before)
After I changed the db version number from 1 to 2 everything worked fine again
Even though I uninstalled the app through the app manager and also removed the cache and
The local database information.
My question is as follows - does the local database data is saved somewhere else?
In case it doesn't - Why did it worked only after I upgraded the version number
not even when I erased all the app related data?
/**
* A class to handle sqlite reads/writes of user related data to be collected
*/
public class UserDataManager extends SQLiteOpenHelper {
// Class Variables
private final String TAG = UserDataManager.class.getSimpleName();
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
public static final String DATABASE_NAME = "tmc";
// Tables
private static final String TABLE_USER = "user";
// Tables and table columns names
private String CREATE_USER_TABLE;
private static final String COLUMN_USER_ID = "user_id";
private static final String COLUMN_USER_MAIL = "email";
private static final String COLUMN_USER_ACTIVE = "user_active";
private static final String COLUMN_USER_NAME = "name";
private static final String COLUMN_USER_PASSWORD = "password";
private static final String COLUMN_USER_PHONE_NUMBER = "phone_number";
/**
* Class constructor
*
* #param context
* The context to run in
*/
public UserDataManager(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_USER + " ("
+ COLUMN_USER_ID + " INTEGER PRIMARY KEY NOT NULL, "
+ COLUMN_USER_MAIL + " VARCHAR(64) NOT NULL, "
+ COLUMN_USER_NAME + " VARCHAR(64) NOT NULL, "
+ COLUMN_USER_PASSWORD + " VARCHAR(64) NOT NULL, "
+ COLUMN_USER_PHONE_NUMBER + " VARCHAR(64) NOT NULL, "
+ COLUMN_USER_ACTIVE + " INT NOT NULL);";
// create the tables
db.execSQL(CREATE_USER_TABLE);
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_USER);
// Create tables again
onCreate(db);
}
/**
* Adding a user to the database
*
* #param userId
* The created user id
* #param userName
* The user name
* #param userEmail
* The user email
* #param userPassword
* The user password
* #param userPhoneNumber
* The user phone number
* #param isActive
* Set to 1 if the user is active 0 otherwise
* #return True if the user added successfully false otherwise
*/
public boolean AddUser(int userId, String userName, String userEmail,
String userPassword, String userPhoneNumber, boolean isActive) {
// method variables
long rowId;
boolean pass = false;
int active = isActive ? 1 : 0;
SQLiteDatabase db = null;
ContentValues row = null;
// try to add the user to the db
try {
row = new ContentValues();
db = this.getWritableDatabase();
db.delete(TABLE_USER, null, null);
row.put(COLUMN_USER_ID, userId);
row.put(COLUMN_USER_NAME, userName);
row.put(COLUMN_USER_MAIL, userEmail);
row.put(COLUMN_USER_PASSWORD, userPassword);
row.put(COLUMN_USER_CAR_NUMBER, userPhoneNumber);
row.put(COLUMN_USER_ACTIVE, active);
rowId = db.insert(TABLE_USER, null, row);
if (rowId > -1) {
pass = true;
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (db != null) {
// close database connection
db.close();
}
}
return pass;
}
/**
* Get the current registered user
*
* #return The id of the column of the registered user
*/
public int GetRegisteredUserId() {
// method variables
int columnIndex = -1;
int userId = -1;
SQLiteDatabase db = null;
Cursor cursor = null;
// try to get the user from the database
try {
db = this.getReadableDatabase();
cursor = db.query(TABLE_USER, new String[] { COLUMN_USER_ID },
null, null, null, null, null);
if (cursor != null) {
boolean moved = cursor.moveToFirst();
if (moved) {
columnIndex = cursor.getColumnIndex(COLUMN_USER_ID);
if (columnIndex > -1) {
userId = cursor.getInt(columnIndex);
}
}
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (cursor != null)
// release cursor
cursor.close();
if (db != null)
// close database connection
db.close();
}
return userId;
}
/**
* Get the current user email
*
* #return The id of the column of the registered user
*/
public String GetRegisteredUserEmail() {
// method variables
int columnIndex = -1;
String userEmail = null;
SQLiteDatabase db = null;
Cursor cursor = null;
// try to get the user from the database
try {
db = this.getReadableDatabase();
cursor = db.query(TABLE_USER, new String[] { COLUMN_USER_MAIL },
null, null, null, null, null);
if (cursor != null) {
boolean moved = cursor.moveToFirst();
if (moved) {
columnIndex = cursor.getColumnIndex(COLUMN_USER_MAIL);
if (columnIndex > -1) {
userEmail = cursor.getString(columnIndex);
}
}
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (cursor != null)
// release cursor
cursor.close();
if (db != null)
// close database connection
db.close();
}
return userEmail;
}
/**
* Get the current user password
*
* #return The password of the current logged user
*/
public String GetRegisteredUserPassword() {
// method variables
int columnIndex = -1;
String userPassword = null;
SQLiteDatabase db = null;
Cursor cursor = null;
// try to get the user from the database
try {
db = this.getReadableDatabase();
cursor = db.query(TABLE_USER,
new String[] { COLUMN_USER_PASSWORD }, null, null, null,
null, null);
if (cursor != null) {
boolean moved = cursor.moveToFirst();
if (moved) {
columnIndex = cursor.getColumnIndex(COLUMN_USER_PASSWORD);
if (columnIndex > -1) {
userPassword = cursor.getString(columnIndex);
}
}
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (cursor != null)
// release cursor
cursor.close();
if (db != null)
// close database connection
db.close();
}
return userPassword;
}
/**
* Get number of rows in the user table
*
* #return the number of the rows in the user table (How many users are
* saved in the DB)
*/
public int GetRowCount() {
// method variables
int rowsCount = 0;
SQLiteDatabase db = null;
Cursor cursor = null;
// try to get the user from the database
try {
db = this.getReadableDatabase();
cursor = db.query(TABLE_USER, null, null, null, null, null, null);
if (cursor != null) {
boolean moved = cursor.moveToFirst();
if (moved) {
do {
rowsCount++;
} while (cursor.moveToNext());
}
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (cursor != null)
// release cursor
cursor.close();
if (db != null)
// close database connection
db.close();
}
return rowsCount;
}
/**
* Remove a user from the database
*
* #param userId
* The user id
*/
public void LogoutUser() {
// method variables
SQLiteDatabase db = null;
// try to remove a user from the database
try {
db = this.getWritableDatabase();
onUpgrade(db, DATABASE_VERSION, DATABASE_VERSION);
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (db != null) {
// close database connection
db.close();
}
}
}
/**
* Set a user to be active or not
*
* #param isActive
* 1 if the cigarette is active 0 otherwise
* #return True if the cigarette active field has changed false otherwise
*/
public boolean SetUserActive(boolean isActive) {
// method variables
int rowsAffected;
int active = isActive ? 1 : 0;
long userId;
String userIdString;
boolean pass = true;
SQLiteDatabase db = null;
ContentValues values = null;
// try to remove a device from the database
try {
userId = GetRegisteredUserId();
if (userId > -1) {
userIdString = String.valueOf(userId);
db = this.getWritableDatabase();
values = new ContentValues();
values.put(COLUMN_USER_ACTIVE, active);
rowsAffected = db.update(TABLE_USER, values, COLUMN_USER_ID
+ " = ?", new String[] { userIdString });
if (rowsAffected != 1) {
pass = false;
}
}
} catch (SQLException exception) {
Log.e(TAG, exception.getMessage());
} finally {
if (db != null) {
// close database connection
db.close();
}
}
return pass;
}
}
Notes -
1. Please note that my device is rooted and so after inserting the data to the db im changing the permissions on the db file for 777 so I can pull it from the phone to see whats in it (i.e. did the query pass or not)
2. The error that is being thrown is "android.database.sqlite.SQLiteException: no such table: user "
Chocolate chips cookies will be granted for any answer... =)
Why did it worked only after I upgraded the version number not even when I erased all the app related data?
As soon as you start working with either of getReadableDatabase() ,getWriteableDatabase() or any other SQLiteHelper class code. The first method calls is onCreate(SQLiteDatabase db) which creates Database under your application database path
/data/data/PACKAGE_NAME/databases/tmc (in your case).
If you modify your Database structure in SQliteHelper the first method get called is onUpgrage() which checks whether Database_Version get modified or not. If it's then it execute onUpgrade() with series of DROP TABLE IF EXIST followed by onCreate() which again create your database with new structure under your application path by replacing your previous database file.
Clearing Cached data using Application Manager indeed clear database and cached data of that application. But SQLiteHelper did check for Database_Version with old and new one. If new one is greater than old one. It does call onUpgrage() followed by onCreate().
When you intent to use Database with Android Application it get store under /data/data/PACKAGE_NAME/databases/tmc with application process security. Unable to access database file unless you have rooted Android device in which you already have.
One can create Developer Options or anything you like just to pull database from your application process to SD Card for unrooted devices.
Copy database file from application process path to SD Card for unrooted devices.
try {
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
if (sd.canWrite()) {
String currentDBPath = "/data/data/" + getPackageName() + "/databases/ZnameDB"; //Your DATABASE_NAME
String backupDBPath = "ZnameDB_Dev.db"; //DATABASE_COPY_NAME UNDER SDCARD
File currentDB = new File(currentDBPath);
File backupDB = new File(sd, backupDBPath);
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(SettingsActivity.this, "Database Transfered!", Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
Answering your first question, all data is stored under YOUR_PACKAGE/databases/DATABASE.db only.
If you erase app through app manager all data is removed, just package remains. If you uninstall your app everything is cleared including package folder. Even if you set for your app install location to external SD card, database is stored internally anyway.
From documentation:
The .apk file is saved on the external storage, but all private user
data, databases, optimized .dex files, and extracted native code are
saved on the internal device memory.
SQLiteOpenHelper logic is simple:
checks if DB exists, if not new DB is created
retrieve DB version, initial value is 0, that's why in your app minimum value for DB version is 1 to call onCreate() method at least once
if version is equal to 0, onCreate() is called, or
if version is different than the one provided by your code onUpgrade() or onDowngrade() is called
So, whenever you upgrade your scheme, version number MUST be increased, there is no argue about that, in order to allow your app work properly.
Now, in your specific case I can only guess. I would say that erasing your package was not entirely successful and bits of data was left, especially if you mentioned that you did some manual modification on DB file. Maybe it has something to do with Android version running on your device but you didn't mentioned which one is it.
That's all. I hope my answer is satisfying.
Can you exec PRAGMA user_version; in your adb to get the db version? According to the source code of SQLiteOpenHelper, SQLite.getVersion() equals to SQLiteOpenHelper.mNewVersion, so onCreate() method won't be invoked. When you chmod 777 on db file, the user_version will be modified too.
Assuming the databases are not deleted while uninstalling app, this seems plausible. The databases are stored here DDMS/data/data/PACKAGE_NAME/databases/YOUR_DB_FILE. You can only see this if your phone is rooted.
Please check whether this assumption is true and correct me if I am wrong.
Thanks

how to avoid "close() was never explicitly called on database in SQLiteDatabase" [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Android error - close() was never explicitly called on database
I have a problem in my android app.
I have a singleton implemented which has a method with the following code:
public Cursor getFooCursor(Context context)
{
StorageDBOpenHelper helper = new StorageDBOpenHelper(context);
SQLiteDatabase db = helper.getReadableDatabase();
Cursor c = db.query("Foo", new String[] {"_id", "Titel"}, null, null, null, null, "Test DESC");
return c;
}
when i use this, i sometimes get the error: SQLiteDatabase: close() was never explicitly called on database
how to avoid this? the problem is, i can not simply make a db.close() befor i return c, because then its empty.
The approach I use is to pass an instance of the db to a class that returns the cursor:
StorageDBOpenHelper helper = new StorageDBOpenHelper(context);
SQLiteDatabase db = helper.getReadableDatabase();
public Cursor getFooCursor(Context context, SQLiteDatabase db ) {
Cursor c = db.query("Foo", new String[] {"_id", "Titel"}, null, null, null,
null, "Test DESC");
return c;
}
db.close();
Clients should open the database, then use this method to fetch the cursor, then close both the cursor and the database when they are finished. I would recommend not using a singleton here. Instead do something like this:
public class FooDB
{
private SQLiteDatabase db = null;
private void open() throws SQLiteException
{
if (db != null)
{
throw new SQLiteException("Database already opened");
}
// Create our open helper
StorageDBOpenHelper helper = new StorageDBOpenHelper(context);
try
{
// Try to actually get the database objects
db = m_openHelper.getWritableDatabase();
}
catch (Exception e)
{
e.printStackTrace();
}
if (db == null)
{
throw new SQLiteException("Failed to open database");
}
}
private void close() throws SQLiteException
{
if (db != null)
{
db.close();
db = null;
}
}
public Cursor getFooCursor(Context context)
{
if(db == null)
throw new SQLiteException("Database not open");
Cursor c = db.query("Foo", new String[] {"_id", "Titel"}, null, null, null, null, "Test DESC");
return c;
}
}

Android SQLite Exception: unable to close due to unfinalised statements

I am writing an android shopping manager application and have come across an error when trying to close one of my SQLite database tables.
ItemsDb idb = new ItemsDb(this);
idb.open();
ArrayList<String> itemNames = idb.getItemNames();
for(int i=0; i < itemNames.size(); i++){
String itemName = itemNames.get(i);
String itemID = idb.getItemID(itemName);
String itemName = idb.getItemNames().get(i);
String itemPrices = idb.getItemPrices().get(i);
String itemQuantity = idb.getItemQuantities().get(i);
String dateBought = idb.getDateBought(itemName);
String decayRate = idb.getDecayRate(itemName);
String decayType = idb.getDecayType(itemName);
String lastDecay = idb.getLastDecay(itemName);
String prevQuantity = idb.getPreviousQuantity(itemName);
}
idb.close();
This doesn't happen with other calls to this class so and I am wondering if it is because there is a loop with a lot of calls to the database here.
The error is SQLite Exception: unable to close due to unfinalised statements.
The error line from the "ItemsDb" class is here
public ItemsDb(Context c){
ourContext = c;
}
public ItemsDb open() throws SQLException{
ourHelper = new DbHelper(ourContext);
ourDatabase = ourHelper.getWritableDatabase();
return this;
}
public void close(){
ourHelper.close();
}
Apparently SQLite3 has a finalize method for destroying previous DB calls but I am not sure how to implement this or even if it is necessary here.
Any help on this would be great.
It seems the problem was cursor related, thanks Jivings. I wasn't closing the cursor after I queried the database, which meant certain references to the database were invalid.
public String getName(String id) throws SQLException{
String[] columns = new String[]{ KEY_ItemID, KEY_NAME};
Cursor c = ourDatabase.query(DATABASE_TABLE, columns, KEY_ItemID + "='" + id + "'", null, null, null, null);
if(c != null){
c.moveToFirst();
String name = c.getString(1);
c.close();
return name;
}
return null;
}
Calling "c.close" seemed to do the trick.

Addressing "Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor"

I have two DB clsses, one copies the db file from assets to the phone.
the Second is where I have been putting my DB calls but in the log I am getting an awrful lot error about I should close the cursor. This I am getting confused about as all my calls have a cursor.close() on the end.
Code of second:
public class DatabaseTools extends Common {
private Context context;
private SQLiteDatabase db;
private DatabaseHelper dbHelper;
private Cursor cursor;
public DatabaseTools(Context context) {
this.context = context;
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();
}
// MARKS
public ArrayList<String> getNames(String value) {
Names = new ArrayList<String>();
selectStatement = new String[] { DB_COMMON_COL_NAME };
fromStatement = DB_COMMON_COL_VALUE + " = '" + value + "'";
cursor = db.query(
DB_DISTANCE_TABLE_NAME,
selectStatement,
fromStatement,
null,
null,
null,
null);
int distanceIndex = cursor.getColumnIndex(DB_COMMON_COL_NAME);
if (cursor.moveToFirst()) {
do {
distanceNames.add(cursor.getString(distanceIndex));
} while (cursor.moveToNext());
}
cursor.close();
return names;
}
Try the following modification to ensure you close your cursor. Also you're getting database instance in your constructor. That's not good. You should get database instance right before you work with the database, and call close() on the database, as soon as you're finished. I would suggest moving db = dbHelper.getWritableDatabase() inside the getNames(String value) method, than calling db.close() when you're done - also in finally block.
public ArrayList<String> getNames(String value) {
Names = new ArrayList<String>();
selectStatement = new String[] { DB_COMMON_COL_NAME };
fromStatement = DB_COMMON_COL_VALUE + " = '" + value + "'";
cursor = db.query(
DB_DISTANCE_TABLE_NAME,
selectStatement,
fromStatement,
null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
try {
int distanceIndex = cursor.getColumnIndexOrThrow(DB_COMMON_COL_NAME);
while(cursor.moveToNext()) {
distanceNames.add(cursor.getString(distanceIndex));
}
} finally {
if (!cursor.isClosed()) {
cursor.close();
}
}
return names;
}

Categories

Resources