能否同步Android AsyncTask doInBackground以序列化任务执行



是否有可能使AsyncTask.doInBackground同步,或者以其他方式获得相同的结果?

class SynchronizedTask extends AsyncTask {
    @Override
    protected synchronized Integer doInBackground(Object... params) {
        // do something that needs to be completed 
        // before another doInBackground can be called
    }
}

在我的情况下,任何AsyncTask.execute()都可以在前一个任务完成之前启动,但我只需要在前一任务完成后执行doInBackground中的代码。

EDIT:正如正确指出的,同步仅在同一对象实例上工作。不幸的是,不可能在同一对象实例上创建AsyncTask并多次调用execute(),如AsyncTask文档的"线程规则"部分所述。

解决方案是使用自定义的Executor来序列化任务,或者,如果使用API 11或更高版本,则使用AsyncTask.executeOnExecutor(),如下面的注释中所建议的那样。

我发布了一个答案,展示了一个SerialExecutor的实现,该实现可用于对将按顺序执行的任务进行排队。

理想情况下,我希望能够将AsyncTask.executeOnExecutor()SERIAL_EXECUTOR一起使用,但这仅适用于API 11级或更高级别:

new AsyncTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params);

为了针对11级以下的Android API,我最终实现了一个自定义类,该类封装了一个线程池大小为1的ExecutorService。完整的代码在这里是开源的。

Executors.newFixedThreadPool(int nThreads)创建了一个线程池,该线程池重用在共享的无边界队列之外操作的固定数量的线程。在任何时候,最多nThreads线程都将是活动的处理任务。在我的例子中,nThreads是1,这意味着任务可以排队,但在任何给定时间都只能执行一个任务。

这是代码:

public abstract class SerialExecutor {
    private final ExecutorService mExecutorService;
    public SerialExecutor() {
        mExecutorService = Executors.newFixedThreadPool(1);
    }
    public void queue(Context context, TaskParams params) {
        mExecutorService.submit(new SerialTask(context, params));
    }
    public void stop() {
        mExecutorService.shutdown();
    }
    public abstract void execute(TaskParams params);
    public static abstract class TaskParams { }
    private class SerialTask implements Runnable {
        private final Context mContext;
        private final TaskParams mParams;
        public SerialTask(Context context, TaskParams params) {
            mContext = context;
            mParams = params;
        }
        public void run() {
            execute(mParams);
            Activity a = (Activity) mContext;
            a.runOnUiThread(new OnPostExecute());
        }
    }
    /**
     * Used to notify the UI thread
     */
    private class OnPostExecute implements Runnable {
        public void run() {
        }
    }
}

这可以扩展并用作Activity:中的串行任务执行器

public class MyActivity extends Activity {
    private MySerialExecutor mSerialExecutor;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...
        mSerialExecutor = new MySerialExecutor();
    }
    @Override
    protected void onDestroy() {
        if (mSerialExecutor != null) {
            mSerialExecutor.stop();
        }
        super.onDestroy();
    }
    public void onTrigger(int param) {
        mSerialExecutor.queue(this, new MySerialExecutor.MyParams(param));
    }
    private static class MySerialExecutor extends SerialExecutor {
        public MySerialExecutor() {
            super();
        }
        @Override
        public void execute(TaskParams params) {
            MyParams myParams = (MyParams) params;
            // do something...
        }
        public static class MyParams extends TaskParams {
            // ... params definition
            public MyParams(int param) {
                // ... params init
            }
        }
    }
}

您可能需要考虑使用IntentService。它似乎更适合您的流程,因为它内置了排队功能。

public class RestAsyncTask1 extends AsyncTask<String, Void, String> {
    private AsyncTaskCompleteListener callback;
    private Context context;
    private String method;
    private static final AtomicInteger PROGRESS_NUM = new AtomicInteger(0);
    private static ProgressDialog PROGRESS_DIALOG;
    public RestAsyncTask1(Context context, AsyncTaskCompleteListener callback, String method) {
        this.callback = callback;
        this.context = context;
        this.method = method;
    }
    public static String format(String url, String... params) {
        String[] encoded = new String[params.length];
        for (int i = 0; i < params.length; i++) {
            encoded[i] = Uri.encode(params[i]);
        }
        return String.format(url, (String[]) encoded);
    }
    @Override
    protected void onPreExecute() {
        int x = PROGRESS_NUM.getAndIncrement();
        if (x == 0) {
            String title = "M_yug";
            PROGRESS_DIALOG = new ProgressDialog(context);
           // PROGRESS_DIALOG.setTitle(title);
            PROGRESS_DIALOG.setIndeterminate(true);
            PROGRESS_DIALOG.setCancelable(false);
            PROGRESS_DIALOG.setOnCancelListener(null);
            PROGRESS_DIALOG.setMessage("Loading. Please wait...");
            PROGRESS_DIALOG.show();
        }
    }
    @Override
    protected String doInBackground(String... params) {
        String url = params[0];
        String response = null;
        HttpURLConnection connection = null;
        if (params.length > 1) {
            if (method.equals(Method.GET)) {
                url = format(url, (String[]) Arrays.copyOfRange(params, 1, params.length));
            } else if (params.length > 2) {
                url = format(url, (String[]) Arrays.copyOfRange(params, 1, params.length - 1));
            }
            try {
                URL call = new URL(url);
                connection = (HttpURLConnection) call.openConnection();
                connection.setRequestProperty("Content-Type", "application/json");
                //connection.setRequestProperty("M-Yug", Utilities.VERSION);
                connection.setRequestMethod(method);
                connection.setDoOutput(true);
                if (method.equals("POST")) {
                    BufferedOutputStream outputStream = new BufferedOutputStream(connection.getOutputStream());
                    outputStream.write(params[params.length - 1].getBytes());
                    outputStream.flush();
                }
                int status = connection.getResponseCode();
                if (status == HttpURLConnection.HTTP_OK) {
                    InputStream is = connection.getInputStream();
                    response = readValue(is);
                } else if (status == 400) {
                    InputStream is = connection.getErrorStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                    StringBuilder builder = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        builder.append(line);
                    }
                    reader.close();
                    Toast.makeText(context, "" + builder.toString(), Toast.LENGTH_SHORT).show();
                }
                connection.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }
        return response;
    }
    @Override
    protected void onPostExecute(String s) {
        int x = PROGRESS_NUM.decrementAndGet();
        if (x == 0 && PROGRESS_DIALOG != null && PROGRESS_DIALOG.isShowing()) {
            PROGRESS_DIALOG.dismiss();
        }
        if (s!=null) {
            String resopnse=s.toString();
            callback.onSuccess(resopnse);
        } else {
           Toast.makeText(context,"Server Not Responding",Toast.LENGTH_SHORT).show();
        }
    }
    private String readValue(InputStream is) {
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        String line;
        try {
            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (Exception e) {
        }
        return sb.toString();
    }
    enum Method {
        GET, POST
    }
}

AsyncTask用于运行后台线程,这样您当前的进程就不会中断。

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
 protected Long doInBackground(URL... urls) {
     int count = urls.length;
     long totalSize = 0;
     for (int i = 0; i < count; i++) {
         totalSize += Downloader.downloadFile(urls[i]);
         publishProgress((int) ((i / (float) count) * 100));
     }
     return totalSize;
 }
 protected void onProgressUpdate(Integer... progress) {
     setProgressPercent(progress[0]);
 }
 protected void onPostExecute(Long result) {
     showDialog("Downloaded " + result + " bytes");
 }

}

首先调用doInBackground函数,返回的对象将在执行后移动到。你想在某个进程之后运行哪行代码,你可以把它放在PostExecute函数中。这肯定会帮助您

最新更新