Android: Database INSERT triggers exception "getWritableDatabase called recursively" - android

Whenever the asynchonous task tries to insert data into the SQLite database I run into the following exception.
java.lang.IllegalStateException: getWritableDatabase called recursively
The data is produced by a service that runs separate asynchonous tasks to download, convert and finally to insert the data. I am not sure if the context objects I am passing are correct. Please note the comments I added to the source code. In the following I added the relevant classes and functions. Please leave a comment if you need futher information.
public class CustomServiceHelper {
// This method gets called by the activities.
public static void loadData(Context context) {
Intent intent = new Intent(context, CustomService.class);
context.startService(intent);
}
}
...
public class CustomService extends Service {
private void startStoringTask(Users users) {
// Passing the context of the service.
mStoringTask = new StoringTask(this);
Object[] params = { users };
mStoringTask.execute(params);
}
}
...
public class UsersProvider extends ContentProvider {
#Override
public boolean onCreate() {
// Not sure if getContext() is correct.
mDatabase = new CustomDatabase(getContext());
return true;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
switch (URI_MATCHER.match(uri)) {
case URI_CODE_USERS:
long id = mDatabase.insertUsers(values);
// TODO: Not sure about the return value.
return ContentUris.withAppendedId(uri, id);
}
return null;
}
}
...
public class CustomDatabase {
public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
CustomSQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(TABLE_USERS_CREATE);
}
#Override
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
throw new UnsupportedOperationException();
}
}
private CustomSQLiteOpenHelper mDatabaseHelper = null;
public CustomDatabase(Context context) {
// The context is passed in by the UsersProvider.
mDatabaseHelper = new CustomSQLiteOpenHelper(context);
}
public long insertUsers(ContentValues contentValues) {
return mDatabaseHelper.getWritableDatabase().insert(
CustomSQLiteOpenHelper.TABLE_USERS, null, contentValues);
}
}
...
public class StoringTask extends AsyncTask<Object, Void, Boolean> {
private Context mContext = null;
public StoringTask(Context context) {
mContext = context;
}
#Override
protected Boolean doInBackground(Object... params) {
Users users = (Users)params[0];
return storeUser(users);
}
private boolean storeUsers(Users users) {
if (users == null) return false;
// Not sure if calling getContentResolver on this context is correct.
ContentResolver contentResolver = mContext.getContentResolver();
Iterator<User> iterator = users.iterator();
do {
User user = iterator.next();
storeUser(contentResolver, user);
}
while (iterator.hasNext());
return true;
}
private void storeUser(ContentResolver contentResolver, User user) {
ContentValues cv = new ContentValues(1);
cv.put(CustomDatabase.Contract.COLUMN_NAME, user.name);
contentResolver.insert(UsersProvider.Contract.URI_USERS, cv);
}
}
When I run the application in Debug mode I end up in the framework class ThreadPoolExecutor in the finally block of the runWorker() method.
Edit:
Here is the full exception stack trace.
java.lang.RuntimeException: An error occured while executing doInBackground()
android.os.AsyncTask$3.done(AsyncTask.java:200)
java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
java.util.concurrent.FutureTask.setException(FutureTask.java:124)
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
java.util.concurrent.FutureTask.run(FutureTask.java:137)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
java.lang.Thread.run(Thread.java:1096)
Caused by: java.lang.IllegalStateException: getWritableDatabase called recursively
android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:81)
com.test.users.database.CustomDatabase.insertUsers(CustomDatabase.java:125)
com.test.users.database.CustomDatabase$CustomSQLiteOpenHelper.insertTestData(CustomDatabase.java:85)
com.test.users.database.CustomDatabase$CustomSQLiteOpenHelper.onCreate(CustomDatabase.java:60)
android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:106)
com.test.users.database.CustomDatabase.insertUsers(CustomDatabase.java:125)
com.test.users.contentprovider.UsersProvider.insert(UsersProvider.java:51)
android.content.ContentProvider$Transport.insert(ContentProvider.java:174)
android.content.ContentResolver.insert(ContentResolver.java:587)
com.test.users.tasks.StoringTask.storeFeature(StoringTask.java:82)
com.test.users.tasks.StoringTask.storeResponse(StoringTask.java:58)
com.test.users.tasks.StoringTask.doInBackground(StoringTask.java:32)
com.test.users.tasks.StoringTask.doInBackground(StoringTask.java:1)
android.os.AsyncTask$2.call(AsyncTask.java:185)
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
I did not mention the method CustomSQLiteOpenHelper.insertTestData() which invokes getWritableDatabase(). I call the method insertTestData() in CustomSQLiteOpenHelper.onCreate(). The crash happens everytime whenever the application has not created a database yet. To summarize, hawaii.five-0 was totally right!

java.lang.IllegalStateException: getWritableDatabase called recursively
So this kind of Exception is usually thown when you use getWritableDatabase() or getReadableDatabase() in onCreate or onUpgrade methods of SQLiteOpenHelper.

Related

Android NPE running JUnit test

I'm trying to implement some tests in my application. One thing that I want to test is writing a java object to my db, then retrieving it and asserting the the object that comes out of the db matches the object that went in.
Here's my MySQLiteHelper application code:
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.concurrent.atomic.AtomicInteger;
class MySQLiteHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "unittesttester.db";
private static final int DATABASE_VERSION = 8;
private static final String LOG_TAG = MySQLiteHelper.class.getSimpleName();
private static final int WEATHER_STALENESS_PERIOD_MS = 60 * 5 * 1000; //5 minutes
private AtomicInteger mOpenCounter = new AtomicInteger();
private static MySQLiteHelper mInstance = null;
private SQLiteDatabase db;
private Context mContext;
public static MySQLiteHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySQLiteHelper(context.getApplicationContext());
}
return mInstance;
}
private MySQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(WeatherTable.CREATE_TABLE_WEATHER);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion <= DATABASE_VERSION) {
onCreate(db);
}
}
private synchronized SQLiteDatabase openDatabase() {
final int i = mOpenCounter.incrementAndGet();
if (i == 1) {
db = getWritableDatabase();
}
return db;
}
private synchronized void closeDatabase() {
final int i = mOpenCounter.decrementAndGet();
if (i == 0) {
db.close();
}
}
private void truncateWeatherTable() {
db = openDatabase();
db.delete(WeatherTable.TABLE_WEATHER, null, null);
closeDatabase();
}
public void deleteAndInsertWeather(Weather weather) {
db = openDatabase();
db.beginTransaction();
try {
truncateWeatherTable();
insertWeather(weather);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
closeDatabase();
}
}
private void insertWeather(Weather weather) {
db = openDatabase();
db.insert(WeatherTable.TABLE_WEATHER, null, makeWeatherCv(weather));
closeDatabase();
}
public Weather getWeather() {
db = openDatabase();
String sql = "SELECT * FROM " + WeatherTable.TABLE_WEATHER;
Cursor c = null;
Weather weather = null;
try {
c = db.rawQuery(sql, null);
if (c.moveToFirst()) {
weather = makeWeather(c);
//If sample too old return null
if (System.currentTimeMillis() - weather.getTimestamp() > WEATHER_STALENESS_PERIOD_MS) {
weather = null;
truncateWeatherTable();
}
}
} finally {
if (c != null) {
c.close();
}
closeDatabase();
}
return weather;
}
private Weather makeWeather(Cursor c) {
Weather weather = new Weather();
weather.setTimestamp(c.getLong(c.getColumnIndex(WeatherTable.COLUMN_TIMESTAMP)));
weather.setElevation(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_ELEVATION)));
weather.setTemperature(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_TEMPERATURE)));
weather.setDusk(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DUSK)));
weather.setNighttime(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_NIGHTTIME)));
weather.setGravity(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_GRAVITY)));
weather.setDaytime(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DAYTIME)));
weather.setHumidity(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_HUMIDITY)));
weather.setPressure(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_PRESSURE)));
weather.setOkta(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_OKTA)));
weather.setDawn(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DAWN)));
return weather;
}
private ContentValues makeWeatherCv(Weather weather) {
ContentValues contentValues = new ContentValues();
contentValues.put(WeatherTable.COLUMN_TIMESTAMP, weather.getTimestamp());
contentValues.put(WeatherTable.COLUMN_TEMPERATURE, weather.getElevation());
contentValues.put(WeatherTable.COLUMN_TEMPERATURE, weather.getTemperature());
contentValues.put(WeatherTable.COLUMN_DUSK, weather.getDusk());
contentValues.put(WeatherTable.COLUMN_NIGHTTIME, weather.getNighttime());
contentValues.put(WeatherTable.COLUMN_GRAVITY, weather.getGravity());
contentValues.put(WeatherTable.COLUMN_DAYTIME, weather.getDaytime());
contentValues.put(WeatherTable.COLUMN_HUMIDITY, weather.getHumidity());
contentValues.put(WeatherTable.COLUMN_PRESSURE, weather.getPressure());
contentValues.put(WeatherTable.COLUMN_OKTA, weather.getOkta());
contentValues.put(WeatherTable.COLUMN_DAWN, weather.getDawn());
return contentValues;
}
}
Here's my test class for the class above:
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MySQLiteHelperTest extends AndroidTestCase {
private MySQLiteHelper db;
private Weather mockedWeather = mock(Weather.class);
#Override
public void setUp() throws Exception {
super.setUp();
context = new MockContext();
setContext(context);
assertNotNull(context);
RenamingDelegatingContext renamingContext = new RenamingDelegatingContext(getContext(), "test_");
db = MySQLiteHelper.getInstance(renamingContext);
assertNotNull(db);
when(mockedWeather.getDawn()).thenReturn(0);
when(mockedWeather.getDaytime()).thenReturn(1);
when(mockedWeather.getDusk()).thenReturn(2);
when(mockedWeather.getElevation()).thenReturn(3.0);
when(mockedWeather.getGravity()).thenReturn(4.0);
when(mockedWeather.getHumidity()).thenReturn(5.0);
when(mockedWeather.getNighttime()).thenReturn(6);
when(mockedWeather.getOkta()).thenReturn(7.0);
when(mockedWeather.getPressure()).thenReturn(8.0);
when(mockedWeather.getTemperature()).thenReturn(9.0);
when(mockedWeather.getTimestamp()).thenReturn(10L);
}
#Override
public void tearDown() throws Exception {
super.tearDown();
}
public void testGetInstance() throws Exception {
}
public void testOnCreate() throws Exception {
}
public void testOnUpgrade() throws Exception {
}
#Test
public void testDeleteAndInsertWeather() throws Exception {
db.deleteAndInsertWeather(mockedWeather);
Weather actualWeather = db.getWeather();
assertEquals(mockedWeather.getDawn(), actualWeather.getDawn());
assertEquals(mockedWeather.getDaytime(), actualWeather.getDaytime());
assertEquals(mockedWeather.getDusk(), actualWeather.getDusk());
assertEquals(mockedWeather.getElevation(), actualWeather.getElevation());
assertEquals(mockedWeather.getGravity(), actualWeather.getGravity());
assertEquals(mockedWeather.getHumidity(), actualWeather.getHumidity());
assertEquals(mockedWeather.getNighttime(), actualWeather.getNighttime());
assertEquals(mockedWeather.getOkta(), actualWeather.getOkta());
assertEquals(mockedWeather.getPressure(), actualWeather.getPressure());
assertEquals(mockedWeather.getTemperature(), actualWeather.getTemperature());
assertEquals(mockedWeather.getTimestamp(), actualWeather.getTimestamp());
}
public void testDeleteWeather() throws Exception {
}
public void testInsertWeather() throws Exception {
}
public void testGetWeather() throws Exception {
}
public void testWeatherMakeCv() throws Exception {
}
}
When I run the test I am getting a NPE during my test. It seems to occur when the MySQLiteHelper class has its db = getWritableDatabase() line. getWriteableDatabase() is a public method from the base class.
I don't think I understand why this test results in an NPE. In my test I call the static method, MySQLiteHelper.getInstance(Context context) which should initialize the class. It is my assumption that calling getInstance will provide me with a fully initialized instance of MySQLiteHelper. Why does this not seem to be happening?
EDIT:
The problem I have now is that when getWritableDatabase() is called it returns null instead of an instance of SQLiteDatabase.
I ended completing my goals of unit testing my sqlite database. The problem seemed to be that I needed to use the build artifact called Android Instrumentation Test instead of the Unit Test build artifact.
I setup a test class in my app/src/androidTest/java directory. The test class extended InstrumentationTestCase.
When I setup my database I use the context provided by getInstrumentation().getTargetContext(). This was important because originally I tried to use getInstrumentation().getContext() and I found that that would always result in a SQLiteCantOpenDatabaseException.
So it seemed my problems occurred because:
1) I wasn't using the correct test artifact
2) I wasn't using the correct test base class
3) I wasn't getting the context correctly
AndroidTestCase#getContext() returns whatever Context you've set with setContext() and you haven't set anything, so a null is returned`.
Using a null context with SQLiteOpenHelper will NPE when the database is being opened e.g. with getWritableDatabase().
See Getting context in AndroidTestCase or InstrumentationTestCase in Android Studio's Unit Test feature for more details on how to set up a Contex in test cases.

Why i get error when try to open sqlite database in android BroadcastReceiver?

I'm beginner in android and call alarm manager in main activity,into the alarm manager write this code:
public class AlarmReciever extends BroadcastReceiver {
private static Context myContext;
#Override
public void onReceive(Context context, Intent intent) {
new HttpAsyncTask().execute("http://myHOST.ir/oflineValue.aspx");
}
private class HttpAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
String DATABASE_NAME = "TEMPFOOD";
String TABLE_NAME = "tempData";
SQLiteDatabase db;
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,myContext.MODE_PRIVATE, null);
}catch(Exception e)
{
}
}
#Override
protected void onPostExecute(String result) {
}
}
}
but in this line:
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,myContext.MODE_PRIVATE, null);
i get this error:
why i get that error?
Answer is in your question - second argument should be SQLiteDatabase.CursorFactory
Try to put null as second argument.
Second Argument of openOrCreateDatabase() must be SQLiteDatabase.CursorFactory which is optional and it is required in order to instantiate any Cursor by default. Use the value null as second argument, if you don't want to instantiate.
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,myContext.MODE_PRIVATE, null);
If you want to instantiate, then try the below code:-
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,new SQLiteDatabase.CursorFactory() {
#Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query) {
//Assign the values of masterQuery,query,editTable as per your requirements
return new SQLiteCursor(masterQuery,editTable,query);
}
}, null);

Open DB connection from an IntentService Constructor

When trying to open up a DB connection via the normal mechanism a nullpointerexecption is thrown at the point dbhelper.getWritableDatabase.
The problem seems to stem from the IntentService context I am passing in.
public AnalysisService() {
super("AnalysisService");
Log.d("ANALYSIS_SERVICE", "Service started");
try{
db = new DBAdapter(this)
db.openDB();
}catch(Exception e){
Log.d("ANALYSIS_SERVICE", Arrays.toString(e.getStackTrace()));
Log.e("ANALYSIS_SERVICE", e.toString());
}
}
The db.open method is executed here:
public class DBAdapter implements Database {
protected Context context;
protected SQLiteDatabase db;
private DatabaseHelper dbHelper;
public DBAdapter(Context context) {
this.context = context;
Log.e("DB_ADAPTER", "CREATED");
}
/**
* Opens a database connection.
* #return
* #throws SQLException
*/
#Override
public DBAdapter openDB() throws SQLException {
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase(); //NULLP EXCEPTION THROWN HERE
return this;
}
And if it helps the constructor for the dbHelper is:
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
Log.e("DB_HELPER", "created");
}
This has been puzzling me for the last day or so I can't understand why the context is invalid. Also I have logged all the constructors and all the objects are being created correctly, so it is not the case that DBHelper is null.
As well as using the context as this, I have also tried using getBaseContext() and getApplicationContext(), both resulting in the same error.
From the debug printing the stack trace, I get:
11-21 13:23:45.419: D/ANALYSIS_SERVICE(3930):
[android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221),
android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:166),
com.emotifi.database.DBAdapter.openDB(DBAdapter.java:42),
com.emotifi.analysis.AnalysisService.<init>(AnalysisService.java:45),
java.lang.Class.newInstanceImpl(Native Method),
java.lang.Class.newInstance(Class.java:1319),
android.app.ActivityThread.handleCreateService(ActivityThread.java:2234),
android.app.ActivityThread.access$1600(ActivityThread.java:123),
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1201),
android.os.Handler.dispatchMessage(Handler.java:99),
android.os.Looper.loop(Looper.java:137),
android.app.ActivityThread.main(ActivityThread.java:4424),
java.lang.reflect.Method.invokeNative(Native Method),
java.lang.reflect.Method.invoke(Method.java:511),
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:817),
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584),
dalvik.system.NativeStart.main(Native Method)]
You're setting the context too early in the IntentService lifecycle.
Override onCreate and set it there:
#Override
public void onCreate() {
super.onCreate();
Log.d("ANALYSIS_SERVICE", "Service started");
db = DatabaseFactory.getDefault(this);
}
Then open the database connection in onHandleIntent:
#Override
protected void onHandleIntent(Intent intent) {
// Logging
Log.d("ANALYSIS_SERVICE", "Intent handled");
try {
db.openDB();
} catch (Exception e) {
Log.d("ANALYSIS_SERVICE", "Unable to open database");
e.printStackTrace();
}
}

I have problems when using sqlite inside AsyncTask in android?

I face two main problems when using a sqlite command inside an AsncTask in android.
When I execute a select command on the first try I get no results but on the second try (loading a activity that has this Asynctask) I do get results.
Sometimes I get an error that the database is not closed despite that it is already closed/
What is the problem with this?
UPDATE:
This is the code that retrive data from database (db.getAllMessage)
private ArrayList<FriendMessagesResulted> getMessagesFromCach(Context c){
FriendMessagesResulted messagesResulted1 = new FriendMessagesResulted();
DBAdapter db = new DBAdapter(c);
Cursor c1;
db.open();
c1 = db.getAllMessage(Settings.getCurrentUserId(c),Integer.parseInt(fId));
Log.d("***Database count",c1.getCount()+" from: "+Settings.getCurrentUserId(c)+" to:"+Integer.parseInt(fId));
c1.moveToFirst();
if(c1.getCount()>0)
status=true;
if (messagesResultedList == null) {
messagesResultedList = new ArrayList<FriendMessagesResulted>();
}
else
messagesResultedList.clear();
while (c1.isAfterLast() == false) {
if(Integer.parseInt(c1.getString(0))>maxId)
maxId=Integer.parseInt(c1.getString(0));
messagesResulted1.set_mId(Integer.parseInt(c1.getString(0)));
messagesResulted1.set_msgTxt("MD:"+c1.getString(3));
messagesResulted1.set_MessageTime(c1.getString(4));
messagesResulted1.set_dir(c1.getString(5));
messagesResultedList.add(messagesResulted1);
c1.moveToNext();
}
db.close();
c1.close();
return messagesResultedList;
}
and this the code for AsyncTask, where I call get getMessagesFromCach method
private void getMessages(final Context c)
{
handler = new Handler();
r=new Runnable() {
public void run() {
class RecentMessageLoader extends AsyncTask<Void, Void, ArrayList<FriendMessagesResulted>>{
ArrayList<FriendMessagesResulted> messagesResultedList=null;
#Override
protected ArrayList<FriendMessagesResulted> doInBackground(Void... params) {
if(!finishLoadingPastMessages)
{
messagesResultedList=getMessagesFromCach(c);
if(!status){
Log.d("Where are you","I'm in JSON");
messagesResultedList=getMessagesFromJSON(c);
}
}
else{
Log.d("Where are you","I'm in Recent messages");
messagesResultedList=getRecentMessages(c,Settings.getCurrentUserId(c),Integer.parseInt(fId));
}
return messagesResultedList;
}
protected void onPostExecute( ArrayList<FriendMessagesResulted> FMRList ) {
// to disappear loading message
d.dismiss();
finishLoadingPastMessages=true;
if(FMRList!=null){
for(int i=FMRList.size()-1;i>=0;i--)
addMessage(FMRList.get(i),c);
}
handler.postDelayed(r, 2000);
}
}
new RecentMessageLoader().execute();
}
};
handler.post(r);
}
UPDATE 2 : Cach class ..
public class Cach {
static DBAdapter db;
public Cach(Context c)
{
}
public static void AddMessages(Context c,
int id,
int fromId,
int toId,
String message,
String dir,
String MessageTime)
{
db = new DBAdapter(c);
db.open();
long id2;
id2 = db.insertMessage(id, fromId, toId, message, dir,MessageTime);
db.close();
}
}
It seems the problem is with the type of variables you are using.. there must be Static variables of instance variables which are getting set from many sources... try not to use static variables and use local variables I mean in the methods implicitly.

SQLite database leak found

I'm creating an application. I'm getting this error:
11-08 13:46:24.665: ERROR/Database(443):
java.lang.IllegalStateException:
/data/data/com.testproj/databases/Testdb SQLiteDatabase created and
never closed
I can't seem to find the reason for this, as it somethimes shows me the error, sometimes not. Here is my code:
public class SQLiteAssistant extends SQLiteOpenHelper {
public SQLiteAssistant(Context context){
super(context, DB_NAME, null, DB_VERSION_NUMBER);
this.myContext = context;
}
public void openDataBase() throws SQLException{
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}
public void closeDataBase() {
if(this.myDataBase != null) {
if(this.myDataBase.isOpen())
this.myDataBase.close();
}
}
}
}
In another class, I have these queries:
public class Db{
private static SQLiteAssistant sqlite;
public static String getSomeString(Context ctx) {
sqlite = new SQLiteAssistant(ctx);
sqlite.openDataBase();
Cursor cursor = sqlite.myDataBase.rawQuery("SELECT someColumn from SomeTable",null);
if (cursor != null) {
if (cursor.getCount()==1) {
if(cursor.moveToFirst()) {
String testString = cursor.getString(cursor.getColumnIndex("someColumn"));
cursor.close();
sqlite.closeDataBase();
sqlite.close();
return testString
}
}
}
sqlite.closeDataBase();
sqlite.close();
return null;
}
}
My problem is when I start a new activity in which I get an AsyncTask. This task gets data from a web service and accesses the database for the String. Here is the AsyncTask:
protected class BackTask extends AsyncTask<Context, String, String> {
#Override
protected String doInBackground(Context... params) {
try{
//get requeste data from the database
//access the web service
return result;
} catch (Exception e) {
return null;
}
return null;
}
}
If I let the activity take its course, everything goes fine. If I don't and quickly press the back button, I get the error. Any suggestion on how to solve this problem?
Am not sure you're using SQLiteOpenHelper properly... you don't need that myDataBase field, the idea is that it manages your database connection for you. Don't subclass in that way... unless you're doing things in onCreate() etc that aren't posted here it looks like you can just use SQLiteOpenHelper directly, i.e.:
SQLiteOpenHelper sqlite = new SQLiteOpenHelper(ctx, DB_PATH+DB_NAME, null,
DB_VERSION_NUMBER);
Assuming that ending the activity should also stop your background task, I'd recommend calling AsyncTask.cancel(true) from your Activity.onPause(). Ensure the database is cleaned up from onCancelled().
And if your background task is the only thing reading the database then make it own the SQLiteOpenHelper instance. It's easy to get into trouble with static data, so it's best avoided IMHO. I'd do something like this:
protected class BackTask extends AsyncTask<String, Integer, String>
{
private SQLiteOpenHelper sqlite;
public void BackTask(Context ctx) {
sqlite = new SQLiteOpenHelper(ctx, DB_PATH+DB_NAME, null,
DB_VERSION_NUMBER);
}
#Override
protected String doInBackground(String... params)
{
try {
//get requeste data from the database
//access the web service
return result;
} catch (Exception e) {
}
return null;
}
#Override
protected void onCancelled() {
sqlite.close();
}
#Override
protected void onPostExecute(String result)
sqlite.close();
// Update UI here
}
}
I think this part :
cursor.close();
sqlite.closeDataBase();
sqlite.close();
must be in a finally close like
Try{
//Do something
}
catch(){
//Catch exception
}
finally{
//Close cursor or/and eventually close database if you don't need it in the future
}
Also don't forget to close database in onDestroy method .
onCreate(Bundle b){
//create database instance
}
onDestroy{
//close db
}

Categories

Resources