I have search through SO and google but doesn't seem fit into my case.
My application randomly gives me this exception from multiple user logs, which never happen while I test it in the emulator nor my device.(I am running on Galaxy tab2 10.1 ,android OS 4.1.1.)
I tested it can be run successfully from development.The required android manifest permissions are in place.
Below are my codes and stack trace
stacktrace :
android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14)
android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:678)
android.database.sqlite.SQLiteSession.beginTransactionUnchecked(SQLiteSession.java:323)
android.database.sqlite.SQLiteSession.beginTransaction(SQLiteSession.java:298)
android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:505)
android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:416)
com.framework.dataaccess.GenericDAO.start(GenericDAO.java:78)
Below is my singleton that instantiate SQLitedatabase
protected static GenericDAO getInstance(Context ctx, String sql) {
if (instance == null) {
try {
instance = new GenericDAO(ctx, sql);
}
catch (Exception e) { e.printStackTrace(); }
}
if(db == null || !db.isOpen()){
try {
db = instance.getWritableDatabase();
}
catch (Exception e) { e.printStackTrace(); }
}
return instance;
}
and for Insertion, delete or update operation I would put in these start() and commit().
public void start() throws Exception{
try{
db.beginTransaction();
}catch(Exception e){
e.printStackTrace();
throw e;
}
}
public void commit() throws Exception{
try{
db.setTransactionSuccessful();
}
catch(Exception e){
e.printStackTrace();
throw e;
}
finally{
db.endTransaction();
}
}
public Cursor select(String table, String[] columns, String criteriaColValue){
return db.query(true, table, columns, criteriaColValue, null, null, null, null, null);
}
My code throws the exception from the dao select below. Which does not call the 'start()' method.
public ArrayList<Obj> getObjList(){
ChildDao dao = null;
Cursor cursor = null;
ArrayList<Obj> list = new ArrayList<Obj>();
try{
dao = new childDao(context);
cursor = dao.select(TABLE_NAME, columns, Criterea );
if(cursor!=null && cursor.moveToFirst()){
do{
list.add(myObjs);
} while(cursor.moveToNext());
}
}catch(Exception ex){
ex.printStackTrace();
}
finally{
if(cursor!=null)cursor.close();
}
return list;
}
I have no idea how the error hit and not able to reproduce it from development environment. Can anyone give me a guide where to look into ?
Thanks in advance.
This may be a little late, but hope this can give a clue for whoever gets this problem. I also had a similar hard to reproduce exception:
unable to open database file (code 14)
android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file (code 14)
at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:845)
It could be not because of database but has to do with extra data/files allocation somewhere in an application. In my case it was bad SoundPool code. Here are the details:
java.lang.RuntimeException: Could not read input channel file descriptors from parcel
Related
I am working with SQLite android where I am using an sqLiteDatabase.insert function to insert customers and sqLiteDatabase.update to update customers and getting the result which is always a long variable, When result is -1, I know the database operation was not successful but I want to display the actual SQLException that occurred. As the return type of these methods is long so they only print the exception in log. Is there any way to get the message of SQLException and display in Toast etc.
I tried to use try catch to catch the exception and show message but when exception occurs it doesnt go to catch block. Below is my code
public void insertData(SQLiteDatabase sqLiteDatabase, Context context, ContentValues values, DatabaseOperation dbOperation, DatabaseOperationCallback dbOperationCallback) {
JSONObject resultObj = new JSONObject();
try {
if (dbOperation != null) {
sqLiteDatabase.insert(dbOperation.getTableName(), null, values);
}
}
} catch (SQLException ex) {
ex.printStackTrace();
//showing in toast; this is not triggered
} catch (Exception ex) {
ex.printStackTrace();
//showing in toast; this is not triggered
}
}
Please see below picture for reference. Any help will be appreciated
You can use
e.printStackTrace(); // (directly to the log)
or
e.getMessage(); // returns message as a String
or others as per the Java Exception Class.
However, using the insertOrThrow method, is probably the method that you want to use.
I am not able to query a pre-created database.
I created a SQLite database using SQLiteDatabaseBrowser and I populated it.
The following query works in the SQLiteDatabaseBrowser:
SELECT png FROM flags64 WHERE iso3='jpn' LIMIT 1
I moved the file in the folder "../assets/databases" in the android project into the Android Studio.
This is the code used to query the database from my android app:
SQLiteDatabase db = null;
try {
db = getApplicationContext().openOrCreateDatabase(getApplicationContext().getDatabasePath("mysticker.db").getPath(), Context.MODE_PRIVATE, null);
Cursor result = null;
try {
result = db.rawQuery(String.format("SELECT png FROM flags64 WHERE iso3='%s' LIMIT 1", country.toLowerCase()), null);
if (result.getCount()>0) {
result.moveToFirst();
byte[] png = result.getBlob(result.getColumnIndex("png"));
ByteArrayInputStream inputStream = new ByteArrayInputStream(png);
playerCountryFlag.setImageBitmap(BitmapFactory.decodeStream(inputStream));
}
} catch (Exception e) {
Log.e("mySticker", e.getStackTrace().toString());
} finally {
if (result != null) {
result.close();
}
}
} finally {
if (db.isOpen()) {
db.close();
}
}
Debugging the code the query does not return any records.
openOrCreateDatabase() does not open database files from assets but rather in your app's private data directory. You're essentially creating a new empty database.
Use sqlite-asset-helper to deploy a database file from assets to your app's private data dir.
I see in the Crashlytics-Logs of my android application a NullPointerException in this code:
try {
mSQLDBreader = this.getReadableDatabase();
} catch (SQLException e) {
if (mSQLDBreader != null) {
mSQLDBreader.close();
mSQLDBreader = this.getReadableDatabase();
}
}
mSQLDBreader... // NPE
As the previous developer isn't available any more, I don't know why it is tried two times, but the code seems to work sometimes, but often not. What can be reasons that this call returns null?
It seems like if this only happens on 2.3.x-devices, in my crashlogs all the affected devices are 2.3.5 and 2.3.6.
Do you have any threading going on of your own creation? Some code that might be resetting mSQLDBreader via another method. Perhaps that thread occasionally runs and trashes the value of mSQLDBreader before you use it?
Have you ever witnessed this on an emulator running 2.3.x?
I looked at google's code for getReadableDatabase, and I don't see a way that it could return null. Gory details are below if you are interested. Based on what I see, I would suspect either a multithreading bug in your code, or a bug introduced by customizations to the android code by the manufacturer of the devices you tested (if that is even plausible.)
Gory details All paths through getReadableDatabase invoke methods on the return object after creating it. So the value can't be null at that point. Otherwise the NPE would be raised from inside.
Here is a snippet of the 2.3.6 code for getReadableDatabase. Actual source is available on grepcode.
public synchronized SQLiteDatabase getReadableDatabase() {
if (mDatabase != null && mDatabase.isOpen()) {
return mDatabase; // The database is already open for business
}
if (mIsInitializing) { /* snip throw ISE */ }
try {
return getWritableDatabase();
} catch (SQLiteException e) {
// snip : throws or falls through below
}
SQLiteDatabase db = null;
try {
mIsInitializing = true;
String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);
// *** next line calls method on db. NPE would be here if db was null at this point. ***
if (db.getVersion() != mNewVersion) {
// snip throw.
}
onOpen(db);
Log.w(TAG, "Opened " + mName + " in read-only mode");
mDatabase = db;
return mDatabase;
} finally {
// snip : not relevant
}
}
Notice that getReadableDatabase usually just returns the result of getWritableDatabase. He looks like this:
public synchronized SQLiteDatabase getWritableDatabase() {
if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
return mDatabase; // The database is already open for business
}
if (mIsInitializing) {
throw new IllegalStateException("getWritableDatabase called recursively");
}
// snip comment about locking
boolean success = false;
SQLiteDatabase db = null;
if (mDatabase != null) mDatabase.lock();
try {
mIsInitializing = true;
if (mName == null) {
db = SQLiteDatabase.create(null);
} else {
db = mContext.openOrCreateDatabase(mName, 0, mFactory);
}
int version = db.getVersion(); // ** method called on result!
// snip block that has more method calls and never nulls out db
onOpen(db);
success = true;
return db;
} finally {
// snip
mDatabase = db;
// snip rest of finally block that isn't relevant.
}
}
Lastly, it is important to note that both of these methods, as well as the close method of SqliteOpenHelper, are tagged with synchronize, so there is no way for one method to trash the state of the other if you have multiple threads calling these methods at the same time..
I have ran into similar problem in the past. It seems like keep closing and opening the database created this problem for me. If you are using the SQLLiteOpenHelper you should not be closing your database unless you have a really good reason to. See CommonsWare answer here which says
SQLiteOpenHelper holds onto the database you retrieve with
getReadableDatabase()/getWritableDatabase(), and the point is for you
to reuse that opened SQLiteDatabase object, particularly as you do
work across multiple threads.
open dataBase before use
if (mDatabase != null && mDatabase.isOpen()) {
return mDatabase; // The database is already open for business
} else {
return mDatabase.open();
}
im having doubts on how to procede with database manipulation using Begin Transaction
I have 2 data source objects: ClientDataSource and MovementsDataSource
each of theres has its own SQLitedabase object which is set with the Open() method with sets its database private Object with a Writable Database.
Now, i have to send the Records from the Movements Table to a server and then ask for the updated Clients from the same server.
Inside my class i first Send the new Movements, then if sucessful, delete all clients from the SQLite, and finally retrieve the new Updated Clients from the server and insert them into the database.
each data source has a Get() method for obtainting their respective Database Object, BUT it is in fact the same database they are operating and I am not sure of how to use the BaginTransction, Endtransaction methods to ensure data consistency
this is the code from the Async Task
#Override
protected Boolean doInBackground(String... url) {
try {
clientDataSource.open();
movementDataSource.open();
} catch (SQLException e) {
//Treat SQL Exception
}
try {
if(sendMovements()) {
clientDataSource.deleteAllClients();
}
updateDatabase(url[0]);
} catch (JSONException e) {
//Treat Json Exception
} catch (IOException e) {
//Treat IOException
}
return true;
}
i have to give one example then how begintransaction works...
public static void Insert(ArrayList<Model_CategoryMaster> categoryMasters) {
SQLiteDatabase sqldb = EGLifeStyleApplication.sqLiteDatabase;
sqldb.beginTransaction();
for (Model_CategoryMaster model : categoryMasters) {
ContentValues values = new ContentValues();
values.put(CATEGORY_ID, model.Category_Id);
values.put(CATEGORYNAME, model.CategoryName);
values.put(DESCRIPTION, model.Description);
values.put(ISACTIVE, model.IsActive);
values.put(CREATEDON, model.CreatedOn);
values.put(CREATEDBY, model.CreatedBy);
values.put(UPDATEDON, model.UpdatedOn);
values.put(UPDATEDBY, model.UpdatedBy);
values.put(ISDELETED, model.IsDeleted);
values.put(DELETEDON, model.DeletedOn);
values.put(DELETEDBY, model.DeletedBy);
values.put(PK_CATEGORYMASTER, model.PK_CategoryMaster);
if (!CommonMethod.CheckIsDataAlreadyInDBorNot(Table_Name,
CATEGORY_ID, model.Category_Id)) {
sqldb.insert(Table_Name, null, values);
} else {
sqldb.update(Table_Name, values, "Category_Id=?",
new String[] { model.Category_Id });
}
}
sqldb.setTransactionSuccessful();
sqldb.endTransaction();
}// End insert method
begin transaction means data will get arraylist then db will open one time and sql.begintansaction() use to get faster database operation.because db is not open or close more times.
I have a problem with a database file not being read
I have added the database file in assets called mydb but when i run my code it says its not being located. It is calling this toast Toast.makeText(this, "No contact found", Toast.LENGTH_LONG).show(); This is being called because no records are being returned. Also I know it is finding the file as there is no FileNotFoundException exception. This is an example form Android Application Development book.
public class DatabaseActivity extends Activity {
/** Called when the activity is first created. */
TextView quest, response1, response2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView quest = (TextView) findViewById(R.id.quest);
try {
String destPath = "/data/data/" + getPackageName() + "/databases/MyDB";
File f = new File(destPath);
if (!f.exists()) {
CopyDB( getBaseContext().getAssets().open("mydb"),
new FileOutputStream(destPath));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
DBAdapter db = new DBAdapter(this);
//---get a contact---
db.open();
Cursor c = db.getContact(2);
if (c.moveToFirst())
DisplayContact(c);
else
Toast.makeText(this, "No contact found", Toast.LENGTH_LONG).show();
db.close();
}
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();
}
public void DisplayContact(Cursor c)
{
quest.setText(String.valueOf(c.getString(1)));
//quest.setText(String.valueOf("this is a text string"));
}
}
Is there a better way to upload data.
A couple of things come to mind here...
because of the !f.exists() check, then once the database exists (and maybe empty) then it will never copy it again. So maybe for now, copy it all the time, until you work out kinks and then add in the !f.exists()
I've had mixed results with e.printStackTrace(), maybe change to Log.e(TAG, "message", e) and see if you start seeing errors showing up in LogCat
As for a better way... I've done this a couple different ways...
1. Is to create a file (json, cvs, etc) and then process and load it, if the database is empty
2. Similar to the first, except that I create a java serialized object array and load it to the database, if the database is empty.
Also I don't know what DBAdapter looks like, and since it wraps the database the issue may be there.