3

I'm getting an Unable to destroy activity xxx: android.database.sqlite.SQLiteException: unable to close due to unfinalised statements error while my activity is being destroyed. I presume this is because I'm performing database operations from within AsyncTasks and they are somehow being killed before completion.

How can I ensure that my AsyncTasks actually complete before the activity is stopped? Incidentally, I thought that an AsyncTask can't be explicitly killed without the AsyncTask agreeing to do so by checking.

It may be relevant that this error is occurring during Robotium integration testing. I suspect it's happening after the test is completed and the test calls Robotium.finishOpenedActivities(). My guess is that somehow the AsyncTask is being forcefully killed mid-execution if this is possible (though I don't explcitly support cancellation in my AsyncTask implementation). Additionally, I use OrmLite for my database access.

Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
  • http://stackoverflow.com/questions/8080504/unable-to-close-due-to-unfinalised-statements-android Might be relevant. – DeeV Aug 06 '12 at 16:20
  • We need to know a bit more about how the AsyncTask is being created. – Code Droid Aug 06 '12 at 17:33
  • @CodeDroid Please see the edits to the final paragraph of my question. – Jeff Axelrod Aug 06 '12 at 19:08
  • Simply show a ProgressDialog and force user wait when AsyncTask is rolling. – yorkw Aug 06 '12 at 21:19
  • Pop up ProgressDialog does not mean hold up UI thread, it is a friendly way to tell user to wait (for the important task to finish). think like that, it pause user's interaction, not the UI thread. This is widely used in situation like database build at app first start up, etc. etc. – yorkw Aug 06 '12 at 22:04
  • Can you post your `AsyncTask` code? I think you might be approaching this the wrong way... instead of trying to delay the `Activity` from being destroyed, you should probably focus on the resources you are creating/opening inside the `AsyncTask`. – Alex Lockwood Aug 07 '12 at 00:28
  • @AlexLockwood I don't think it's possible to post the code in any concise fashion. There is no detail about which AsyncTask is causing the crash in LogCat, I have several, and there are typically many other collaborating classes in my AsyncTasks. I think the key point is that there's an in-progress database operation that gets interrupted by the integration tests's call to activity.finish(). What exactly am I supposed to do to ensure the operation completes other than hold up the UI thread? – Jeff Axelrod Aug 07 '12 at 15:01

3 Answers3

2

It looks like if I override the onPause() event in my activity, and from within the overridden onPause(), I call cancel(false) on the AsyncTasks, then the activity is not destroyed until the AsyncTasks are completed.

Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
  • this does seem to work but the problem is that the asyntask does not call onPostExecute anymore when it's finished.. this is because of the cancel(false); i put in the onPause of the activity – yeahman Jun 16 '13 at 18:39
0

You can check AsyncTask.getStatus() against AsyncTask.Status.RUNNING at any time.

Perhaps you need to make your activity and your AsyncTask aware of each other as was asked in this question Is AsyncTask really conceptually flawed or am I just missing something? and the answer by @hackbod explains exactly how

Community
  • 1
  • 1
Alexander Kulyakhtin
  • 47,782
  • 38
  • 107
  • 158
  • @Jeff Axelrod No, while checking with getStatus() is possible I do not think holding anything in UI thread is a good idea. I think however if you do something like hackbod proposed in that answer then your problem will go away. Because your AsyncTask will get a new activity when needed and because you will be passing any running AsyncTask to a new Activity as well. – Alexander Kulyakhtin Aug 06 '12 at 16:44
  • @Jeff Axelrod I'm sure the problem is in inavlid context – Alexander Kulyakhtin Aug 06 '12 at 17:52
0

There are several things you can do here:

  1. Override these methods and see determine exactly what state the object is in when it is closed. It seems that onPostExecute is going to get called when the AsyncTask is done. If it has not been called its too early.

    protected void onProgressUpdate(Integer... progress) {
       setProgressPercent(progress[0]);
    }
    
    protected void onPostExecute(Long result) {
    }
    
  2. You can also execute as follows:

    // with THREAD_POOL_EXECUTOR.
    executeOnExecutor(java.util.concurrent.Executor, Object[]) 
    
  3. Make sure you are following the first two rules in the documentation: Are you following 1 and 2?

    There are a few threading rules that must be followed for this class to work properly:

    1. The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.

    2. The task instance must be created on the UI thread.

    3. execute(Params...) must be invoked on the UI thread.

    4. Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.

    5. The task can be executed only once (an exception will be thrown if a second execution is attempted.)

Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
Code Droid
  • 10,344
  • 17
  • 72
  • 112
  • Yes I am following these rules. As I wrote in the original question, I believe the problem is due to the AsyncTask being killed from my integration test calling activity.finish() before the AsyncTask has completed. I see no reason why this wouldn't also happen during a low memory/background condition once the app is deployed. – Jeff Axelrod Aug 07 '12 at 15:12