Reputation: 352
I have been trying to solve a problem regarding the shared use of an SQLiteDatabase by my application and the application's service; that is, a service started by the application. The service wakes up every 30 seconds and checks the database, then, as all good processes should, it closes the connection to the database when it's finished. However, when the application is running concurrently and attempts to access the database, the application crashes. The logcat presents a message that warns me that I am trying to reopen a database connection that has already been closed, like the following:
05-16 16:48:30.796: E/AndroidRuntime(10610): java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.example.myapp/databases/eRing
A diligent troubleshooting effort showed that if I removed the closure of the database by the service that all would be well, sorta... If I let the service cycle long enough. Eventually, SQLiteConnectionPool would wake up and say,
A SQLiteConnection object for database '+data+data+com_example_myapp+databases+eRing' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.
So, I have gone back to the drawing board, and reviewed the documentation and tutorials. I noticed that many of the available resources can hardly mention SQLiteDatabases without discussing ContentProviders. However, the documentation says that you only need a ContentProvider if you intend on accessing the database from another application. Here is a quote from the Android Developer's website:
Before You Start Building
Before you start building a provider, do the following:
Decide if you need a content provider. You need to build a content provider if you want to provide one or more of the following features:
You don't need a provider to use an SQLite database if the use is entirely within your own application.
What I can't tell from this documentation is the following: For the situation where the App owns the Service, and both the Activity and the Service need to access the database concurrently, does this warrant creating a ContentProvider? I am positive that I have no intent on sharing this database with anything else, or any of the other scenarios the documentation lists. Put another way, does the Service and the Activity count as two "Apps"? The Android fundamentals calls an activity and a service "App components" but not individual "Apps".
Please tell me if putting in all the effort to create a custom ContentProvider, and ripping out the direct access (via the SQLiteDBAdapters/Helpers) to the database is worth it.
For Salem: The following is the close method called by the Activity and Service.
public class SettingsDbAdapter {
private static SQLiteDatabase mDb;
private DatabaseHelper mDbHelper;
public static class DatabaseHelper extends SQLiteOpenHelper {
//...
}
//...
public void close() {
Log.v("close()", "Close settingsdbadapter called");
mDbHelper.close();
}
}
//The following is the Services Open method:
public SettingsDbAdapter openReadable() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getReadableDatabase();
return this;
}
//The following is the Activities Open Method:
public SettingsDbAdapter open() throws SQLException {
mDb = mDbHelper.getWritableDatabase();
if (!mDb.isWriteAheadLoggingEnabled()) {
Log.v("SettingsDb","Trying to Enable Write Ahead Logging");
mDb.enableWriteAheadLogging();
}
return this;
}
Upvotes: 0
Views: 213
Reputation: 27004
The content provider is only required when the database is accessed by another application because the later simply has no permission to open the database file.
In your case, the problem is that you have concurrent access on the SQLiteDatabase
. If you wrote a service, your activity should use it as well.
Edit: My comment seemed confused, I removed it. I suggest the 4 following components:
BroadcastReceiver
that, after the phone has booted, registers an alarm (via AlarmManager
), and closesThe two latter access the data via
Upvotes: 1