I regularly get reports from users with this error.
Unable to getWritableDatabase.
try {
//dbOpenHelper is a standard SQLiteOpenHelper
dbOpenHelper.getWritableDatabase();
} catch (Exception e) {
//unable to connect to database.
return;
}
This is only happening sometimes. What could it be? Any fixes or workarounds?
There isn't much to go off of, need to see your LogCat to help any further. Are you closing your dbOpenHelper?
Here is a quick example:
public DatabaseControl open() throws SQLiteException {
dbHelper = new DatabaseHelper(context);
database = dbHelper.getWritableDatabase();
return this;
}
public void close() {
dbHelper.close();
}
Edit 1 - Again, this is my best guess since a LogCat is unobtainable. (In the end it might be in your best interest to run this application on your Dev device and try to replicate and then get your full LogCat ouput)
It sounds to me like the Activity that has the DB is being accessed and processed fine with a proper close(), but in some instances maybe instead of running through that Activity the user presses the back button where onBackPressed() maybe should have a DB close() call?
In other words, to troubleshoot, I would #Override Acitivity lifecycle methods: onPause(), onResume(), onStart(), onStop(), and onDestroy() as well as onBackPressed() simply adding the DB close() and test your application then. If you do this then, I would think that, any returning lifecycle, such as onStart() or onResume() should contain the DB getWritableDatabase()
According to the documentation (see below), there really is no way to get Unable to getWritableDatabase unless the database was not closed properly. Also make sure that if you change anything in your SQlite code / structure that you need to update the DB Version #.
public SQLiteDatabase getWritableDatabase ()
Create and/or open a database that will be used for reading and writing. The first time this is called, the database will be opened and onCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int) and/or onOpen(SQLiteDatabase) will be called.
Once opened successfully, the database is cached, so you can call this method every time you need to write to the database. (Make sure to call close() when you no longer need the database.) Errors such as bad permissions or a full disk may cause this method to fail, but future attempts may succeed if the problem is fixed.
Edit 2
I should have shown how I called on the open() and close() methods the first time. Sorry about that. You don't need the DatabaseHelper open unless you are retrieving or posting to it, so immediately after processing close it until the next time you need it. Same goes for the Cursor, etc
Below is how I query the database, I open everything, retrieve the information, process the information and then immediately close everything. See below:
DatabaseControl control = new DatabaseControl(this);
try {
database = (new DatabaseHelper(this)).getWritableDatabase();
DatabaseControl control = new DatabaseControl(DbTestDisplay.this);
control.open();
control.fetchAllItems();
Cursor c = database.query(GlobalDBVars.TABLE_NAME, null, null, null, null, null, null, null);
c.moveToFirst();
int initialCount = c.getCount();
Log.i("cursor", "Initial Count = " + initialCount);
List<Integer> x = new ArrayList<Integer>();
if (initialCount > 0) {
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
/* Process everything here */
} /* End for loop */
} /* End if statement */
control.close();
c.close();
database.close();
} catch (SQLException sqe) {
Log.e("fetchAllItems", "FAILED: " + sqe.getMessage() + " allData = ");
}
Try getReadableDatabase() instead of getWritableDatabase()
try {
//dbOpenHelper is a standard SQLiteOpenHelper
dbOpenHelper.getReadableDatabase();
} catch (Exception e) {
//unable to connect to database.
return;
}
Related
I'm migrating the following pattern of accessing the Android app's SQLite database into the RxJava world:
public List<Stuff> doStuff(){
synchronized (lock) {
open(); // this effectively checks for isOpen() then calls getWritableDatabase()
// query the database for stuff
close(); // SQLiteOpenHelper close method
return stuffList;
}
}
Something I'm struggling is when should I close the database connection? I know there are patterns for not closing the connection at all as well as closing the connection as part of the Activity method. However, those patterns would require me applying the logic to the whole database manager class which I'd like to avoid if possible. Was hoping maybe there's a suggested way to handle this with RxJava and specifically SqlBright wrapper? My migrated code looks something like this:
public Observable<List<Stuff>> doStuff(){
synchronized (lock) {
open();
String sql = <..>;
return db.createQuery(tableName, sql, args).mapToList(mStuffMapper);
// where do I close()?
}
}
The solution I'm after, ideally, should allow me to change this one method, keeping the rest with the current open/close pattern.
You can use Subscription to close the connection.
db.createQuery(tableName, sql, args)
.mapToList(mStuffMapper);
.doOnSubscribe(new Action0() {
#Override public void call() {
close();
}
});
Subscription subscribe = doStuff().subscribe();
subscribe.unsubscribe();
I need save some objects in DB. I'm using this code in my Dao class.
public void saveActions(List<Action> actionList) throws SQLException {
for (Action action : actionList) {
createOrUpdate(action);
}
}
And sometimes I have CursorWindowAllocationException in createOrUpdate() function.
Does anyone have solution of this problem?
If you look up the source of CursorWindowAllocationException it reads:
This exception is thrown when a CursorWindow couldn't be allocated,
most probably due to memory not being available.
If you follow the stack, you'll see that the call com.j256.ormlite.android.AndroidDatabaseConnection.queryForLong is creating a cursor for every createOrUpdate call.
So what's likely happening here is that there are too many Cursors being created before the memory is freed.
You should execute these calls in a transaction, or better yet, use batch tasks. E.g.
actionDao.callBatchTasks(new Callable<Void>() {
public Void call() throws SQLException {
for (Action action : actionList) {
actionDao.createOrUpdate(action);
}
return null;
}
});
You must call cursor.close(); in finally { } block when you do not need cursor anymore. Cursor allocation will fail without calling close() on cursor after some time when system resources for cursor allocation will be not available.
I have an application with database and content provider. In order to display some data from the database in ListView's, I useLoaderManager.
It's simple and works perfectly well in most of case.
But, when to many change notifications from the content provider arrives, the UI is totally overloaded. It happens when there are many inserts, about 15 per seconds, on the uri observed by the cursor. I think even if the cursor load is in background, the large amount of bindView() calls is enough to overload the UI.
So I would like, in some case as above, limit the number of loads (and so onLoadFinished() calls) to something like one per seconds.
Is there a way to achieve that with LoaderManager ? I tried to play with startLoading() and stopLoading but without success, and anyway it's not recommended.
Or maybe I have to manage a Loader by myself, but I will be surprised if this situation is not common.
Thanks for your advice.
EDIT
I actually missed a method... setUpdateThrottle(long delayMS) do exactly what I want.
You can override applyBatch(...) in your content provider and do something like this:
#Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.beginTransaction();
try {
final int numOperations = operations.size();
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
for (int i = 0; i < numOperations; i++) {
results[i] = operations.get(i).apply(this, results, i);
}
db.setTransactionSuccessful();
return results;
} finally {
db.endTransaction();
}
}
You can use this to batch your inserts into one transaction so notification only happens once.
This is more of a "Am I doing this the best way" kind of question in regards to closing the connection to an sqlite database. What i've been doing is closing the database within my view activity in the onpause and ondestroy methods. When the user navigates back to the activity I requery the database on the onresume method. Here is a snippet of code:
private void setupView() {
newRecipeButton = (Button)findViewById(R.id.NewRecipeButton);
newRecipeButton.setOnClickListener(addNewRecipe);
list = (ListView)findViewById(R.id.RecipeList);
dbHelper = new DataBaseHelper(this);
setupDataBase();
database = dbHelper.getMyDataBase();
queryDataBase();
list.setEmptyView(findViewById(R.id.EmptyList));
registerForContextMenu(list);
}
private void queryDataBase() {
data = database.query("recipes", fields, null, null, null, null, null);
dataSource = new DataBaseAdapter(this, R.layout.recipe_list_item, data, fields, new int[] {R.id.RecipeName, R.id.RecipeStyle});
list.setAdapter(dataSource);
}
private void setupDataBase() {
//Create the database if this is the first run.
try{
dbHelper.createDataBase();
} catch(IOException e){
throw new Error("Unable to Create Database");
}
//Otherwise open the database.
try{
dbHelper.openDataBase();
}catch (SQLiteException e){
throw e;
}
}
#Override
protected void onResume(){
super.onResume();
setupView();
}
#Override
protected void onDestroy() {
super.onDestroy();
dbHelper.close();
}
Of course this isn't the entire activity but merely the parts that deal with the sqlite database. So am I doing this in a tidy manner or is there a better practice I should be following?
onDestroy is probably the best phase to place disposal method of any IO connection.
Another approach is using try { query() } finally { db.close(); } pattern – which also makes sense so that database is only activated during your query.
In Java 7, there is a new syntactic sugar try (db = open database();) { execute queries(); } that closes database automatically after executing queries finishes. However Java 7 is not available on Android devices yet.
I'm developing an Android 2.2 application.
I want to catch and re throw the same exception. I want to do this because I have to close a cursor before exit the method (a finally statement, isn't it?)
Can I do that? How?
Thanks
If this is just to close the cursor correctly, you can do a try...finally without a catch. That would be something like that :
Cursor cursor = null;
try {
// initialize and do things with the cursor
} finally {
if (cursor != null) {
cursor.close();
}
}
Alternatively, if you're in an activity, you can use startManagingQuery; which will take care of your cursor lifecycle depending on the activity lifecycle.
Without discussing if this is a good practice you can do this:
throw new YourException();