0

In my app I have a background task (using AsyncTask) that downloads stuff from a web site.

This task can be called from two separate activities, and it is possible to call it twice. So in "activity1" the background task "update" is called, and runs for a while (it takes something like 5-10 seconds usually). Then while it's running, user switches to "activity2" and runs "update" again. This gives problems: either a crash when both try to clear the database (command: DELETE FROM table) at the same time, causing a "database locked" error. Or they try to put the same item in the database causing a duplicate.

I've tried to solve this by setting a static boolean flag to true when a task is active. When the task is called, it will check for this flag, and if true (i.e. the same task running on another thread) it goes into a wait loop using a handler until this flag clears, and then returns. This to make sure that when the background task returns, the update has been done. I have to use a Looper for that: this sometimes fails with an error "can create only one looper per thread". And I really have it in a way that only one looper can be started, this is the offending code, which appears at the start of the background task:

    if (active) {
        Looper.prepare();
        handler = new Handler();
        handler.postDelayed(new Runnable() {
            int count = 0;

            @Override
            public void run() {
                if (active) {
                    count++;
                    if (count < 1000) 
                        handler.postDelayed(this, 100);
                }
            }
        }, 100);
        Looper.loop();
        active = false;
        return "done";
    }

And to make matters worse it often seems to hang in this loop, without returning.

How to solve such a situation?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Wouter
  • 2,623
  • 4
  • 34
  • 43

3 Answers3

0

Why don't use synchronization instead? It sounds like a concurrency issue. Why don't you make sure that if the first background task is running then the second background task is sleeping until the first one is finished.

Or ensure somehow, that if the user switches to Activity number 2, the background task from activity number 1 is cancelled.

kkudi
  • 1,625
  • 4
  • 25
  • 47
  • Now that was a quick reply! I have no idea about synchronisation... could you give more details on this? – Wouter Mar 28 '11 at 17:50
  • Here is something to start with - http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html – Vino Mar 28 '11 at 18:00
0

Instead of the AsyncTask you can consider to use IntentService. Have a look at the Android Service concept. The IntentService class ensures that only one request will be processed at one time.

I found this answer very useful during implementing IntentService with Activity callback communication.

Community
  • 1
  • 1
FrVaBe
  • 47,963
  • 16
  • 124
  • 157
  • Interesting concept, but doesn't look like what I need, which is database access from multiple threads at the same time. Tying to use a ContentProvider now, appears to be the more appropriate. Even though it's meant for sharing between apps - it also works great for sharing between two or more threads from the same app. – Wouter Apr 15 '11 at 14:54
0

Database locking issues solved by wrapping it into a ContentProvider. Besides problems with a method being called again before the previous instance was finished, I had the issue of different methods running in different background threads clashing while trying to write to the database.

Officially designed to allow for sharing data between apps, it also works great for sharing data between threads in a single app. The ContentProvider will make sure that no locking issues occur.

Wouter
  • 2,623
  • 4
  • 34
  • 43