保证回调的最佳方法始终是异步执行的?

时间:2013-06-27 19:24:58

标签: java android concurrency

我正在使用Android应用程序,该应用程序必须发出服务器请求,然后在请求完成时执行操作。这里有一些伪代码来帮助解释这种情况:

makeRequest(new SomeTask{
    onDone() {
        // Do actionB with queue
    }
});

// Do actionA with queue.  Must be execute first!!

以下是伪代码中makeRequest的实现:

makeRequest(SomeTask task) {
    if(canDoOptimization) { // if true, don't need to make request

        // It's a bad idea to execute this immediately.
        // Wish I could wait until the current thread of execution was done...
        task.onDone();
        return;
    }

    asyncTask = new AsyncTask<SomeTask, Void, Void>() {
        doInBackground(SomeTask... task) {
            // Make server request...

            task.onDone();
        }
    }
    asyncTask.execute(task);
}

通常actionA按预期发生在actionB之前,但在我们可以避免网络请求的情况下,会立即调用SomeTask.execute。这会导致actionBactionA之前发生,这很糟糕。有什么方法可以保证不发生这种情况吗?

我在javascript中多次遇到过这种情况。在这些情况下,我会使用SomeTask.executesetTimeout包裹setImmediate调用,以维护正确的异步语义。

为清楚起见,以下是JavaScript中相同错误的示例:https://gist.github.com/xavi-/5882483

知道我应该在Java / Android中做些什么吗?

3 个答案:

答案 0 :(得分:1)

欢迎来到同步世界。互斥锁或锁定对象通常用于此目的。 Is there a Mutex in Java?

你的B任务应该等待互联网完成后由任务A发出信号。这将确保正确的执行顺序,其中任务将在B之前完成。

答案 1 :(得分:1)

始终将task.onDone()放入AsyncTask,即使它不需要提出请求。

makeRequest(SomeTask task) {

    asyncTask = new AsyncTask<SomeTask, Void, Void>() {
        void doInBackground(SomeTask... task) {

            if(canDoOptimization) { // if true, don't need to make request

                // It's a bad idea to execute this immediately.
                // Wish I could wait until the current thread of was done...
                task.onDone();
                return;
            } else {
                // Make server request...

                task.onDone();
            }
        }
    }
    asyncTask.execute(task);
}

答案 2 :(得分:0)

为什么你不能只改变事物的顺序?

// Do actionA with queue.  Must be execute first!!

makeRequest(new SomeTask{
onDone() {
    // Do actionB with queue
});

如果actionA也是异步的并且在单独的AsyncTask上执行,你可以在actionA的AsyncTasks的onPostExecute()方法上调用makeRequest(...)。

顺便说一下,自从Android Honeycomb版本以来,AsyncTasks在同一个线程上运行,这意味着如果你有几个任务,它们可以互相阻塞。 通过指定AsyncTsak应该在线程池中运行来解决此问题:

if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else {
  asyncTask.execute();
}