6

Working on an app in android I have used Asynctask class, Works fine when i tested on my Android device running on 2.3.5, but the problem i am facing is, same is not working for my tablet 4.0.4

While testing, got to know that prexecute() is being called but doInbackground() not being called, however doInbackground() is being called on device(2.3.5).

One of the reason i believe for the problem is that the processor of Tablet is much faster than that of device, so may be some threading issues, dats why, to tackle this, i have used some flags, and used Thread.sleep() in a do while loop so that when condition is true, it works, but no luck, i am stuck in the loop itself. Here is my code:

MyAsyncTask object = new MyAsyncTask (MainActivity.this);
runOnUiThread(new Runnable() {
    public void run() {         

        try {
            if (object.isReady() || !object.isStarting()) {
                return;
            }

            object.execute();

            do {
                Thread.sleep(1000);             
            } while (!object.isReady() && object.isStarting());

            if(!object.isReady()) { 
                return;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }           
});

AsynctaskClass:

public class MyAsyncTask extends AsyncTask<Void, Void, Boolean>{

    private ProgressDialog dialog;
    private Context context;
    private boolean isStarting = false;
    private boolean isReady = false;


    public AsyncUpdatesofJquery(Context context) {
        this.context = context;
        isStarting = true;
        isReady = false;
    }

    public boolean isStarting() {
        return isStarting;
    }

    public boolean isReady() {
        return isReady;
    }

    @Override
    protected void onPreExecute() {

        isStarting = true;
        isReady = false;
        dialog = new ProgressDialog(context); 
        dialog.setMessage("Downloading Files, Please wait...");
        dialog.show();
    }

    @Override
    protected Boolean doInBackground(Void... params) {

        isReady = true;
        isStarting = false;
        downloadFiles(context); // my background task

        return true;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        context.startActivity(new Intent(context, NewActivity.class));
        dialog.dismiss();
        isReady = false;
        isStarting = false;

    }
}
olshevski
  • 4,971
  • 2
  • 35
  • 34
dave21
  • 315
  • 1
  • 6
  • 14
  • What's the point in running an AsyncTask on UI thread? – Egor Oct 11 '12 at 12:22
  • 2
    First of all, boolean values `isStarting` and `isReady` should be volatile or better `AtomicBoolean` when you use them from different threads. – olshevski Oct 11 '12 at 12:25
  • 1
    @Egor AsyncTask should be started only from UI thread. I assume the code is not in the UI thread in this case. Otherwise, i don't see any purpose in `runOnUiThread()` call. – olshevski Oct 11 '12 at 12:27
  • Are you sure that `doInBackground` is not executed? Did you debug its call? I'm pretty sure that you just get the infinite loop due to the buggy condition of `while` loop – olshevski Oct 11 '12 at 12:31
  • @Kzinch 100% sure, doInBackground is never called, but only in case of Tablet, its being called in case of Android device running on 2.3.5 – dave21 Oct 11 '12 at 12:34
  • You are checking for `!object.isReady() && object.isStarting()` in your while-loop. But after setting both `boolean` values to false in `onPostExecute` what do you expect to happen? It is definitely infinite loop. – olshevski Oct 11 '12 at 12:36
  • How do you know that `doInbackground` is not called? If you are relying on your boolean flags, they are not thread safe. Put some `Log` output in the various methods to see what is actually being called. – dave.c Oct 11 '12 at 12:41
  • onPostExecute is called when doInBackground finishes executing, if i am not wrong, but if doInBackground is not being called, how could boolean values be set to false and hence an infinite loop – dave21 Oct 11 '12 at 12:43
  • @dave.c yeah actually relying on boolean flags only – dave21 Oct 11 '12 at 12:46
  • 1
    @dave21 using the boolean flags as you have done is not thread safe, as threads can cache variable values. As such if a thread modifies a vairable, that change is not necessarily available to any other thread. Either fix the code so that it is thread-safe, or just use some logging. – dave.c Oct 11 '12 at 12:50
  • @dave.c hey i have checked, using logging, doInBackground is never called on tablet, while its been called on Android device – dave21 Oct 11 '12 at 12:56

1 Answers1

17

The multi-threading model changed between 2.3.5 and 4.0.4. AsyncTask now defaults to having all subclasses in an application using the same thread (i.e. only one AsyncTask can run at a time!). It's explained here:

When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.

If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.

With that in mind, it could be that another AsyncTask is running in your app, thereby preventing this one from ever starting. That would explain why it works fine on your 2.3.5 device, but not your 4.0.4 tablet.

Community
  • 1
  • 1
Todd Sjolander
  • 1,459
  • 1
  • 15
  • 28
  • hey bro..u were right, actually one more AsyncTask was already running. but i am not able to implement executeOnExecutor(), any sample code available?? – dave21 Oct 15 '12 at 06:36
  • Looking more into this...I have more bad news. `executeOnExecutor` isn't available until Android 3.0. If you want full compatibility for both your 2.3.5 and 4.0.4, I think you need to dump AsyncTask and go with `Runnable`. That's what I ended up doing. The good news is that you won't need to change much code. You'll have to get on the UI thread on your own, probably using a `Handler` – Todd Sjolander Oct 15 '12 at 11:33
  • Right dude, i had to dump Asynctask and used Runnable, working fine – dave21 Oct 15 '12 at 11:50
  • @ToddSjolander Thanks for you detailed answer and one up for that. Do you have any idea about the list of changes that as to be made or concentrated while implementation. Can anywhere we will be able to find document that are grouped for this purpose so that we can focus on those, instead of facing a strange issue and wasting time on those issues. Hope you could understand my question. – Dinash Mar 04 '13 at 10:30
  • They don't necessarily present it in the form I think you're looking for: "Here's what you need to update to maintain functionality with the latest Android version..." However, there is a diff report buried in the documentation: http://developer.android.com/sdk/api_diff/17/changes.html That's for 4.2, but you could fiddle with the URL to get the others. It's worth looking at when you run into compatibility issues, but it's not presented in an easy format. – Todd Sjolander Mar 04 '13 at 13:16
  • Leave it to Google to mess with compatibility. This is just one more in the long list of idiotic things they do with Android and just another reason why I tell most people to buy an iPhone. – Johann Jul 04 '13 at 18:31