Search code examples
javaandroidmultithreadingblocking

Why is my Service's AsyncTask blocking AsyncTasks from the main Activity?


I'm trying to write a simple Service that will do something every few seconds. But when I run the Service while trying to run other AsyncTasks in the main Activity, I noticed that the other AsyncTasks get stuck at onPreExecute. When I disabled the service, everything worked as expected. Is there a reason why the Service's AsynTask is blocking the other AsyncTasks?

Service

public class SVC_SyncData extends Service {

    private final String TAG = "SVC_SyncData";

    private AT_SyncData m_SyncPoll = null;

    public static boolean isRunning = false;

    public SVC_SyncData() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate");
        m_SyncPoll = new AT_SyncData(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        m_SyncPoll.execute();
        isRunning = true;
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy");
        m_SyncPoll.cancel(false);
        isRunning = false;
    }
}

AT_SyncData's doInBackground

@Override
protected Void doInBackground(Void... params) {
    Log.i(TAG, "doInBackground");

    try {
        while (!isCancelled()) {
            Log.i(TAG, "syncData");

            // Sleep until next cycle
            Thread.sleep(5000);
        }
    }
    catch (Exception ex) {
        ex.printStackTrace();
    }

    return null;
}

Solution

  • The AsyncTask documentation states:

    Order of execution

    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.

    Thus, newer versions of android will have this problem you describe. You need to use executeOnExecutor to make sure that you are running on separate threads.

    Furthermore, if you have service that you want to run in a separate thread I recommend either:

    1. Use an IntentService
    2. Sometimes you will want more control over your service's lifecycle than what IntentService gives you, in those cases you can just create a thread in the service and run your background code in that. Actually, to be more specific, create a HandlerThread which includes a Looper so you can use the standard android method for communication (messages) between your main thread and the background thread. Personally, I usually choose this option for my services.