Android / AsyncTask:你还需要检查" isCancelled" (API 24)?

时间:2018-06-04 15:23:17

标签: android android-asynctask cancellation

我的应用使用AsyncTask下载文件,同时显示ProgressDialog(我意识到它已被弃用),其中包含"取消"按钮。

根据this,您应定期检查isCancelled()中的doInBackground,因为mytask.cancel(true)不会自行中断doInBackground

我只是在没有检查的情况下取消了任务,发现它仍然停止doInBackground:取决于我按下"取消"按钮,我在生成的文件中看到了不同的尺寸 - 从几kb到几mb - 最终尺寸大约为9mb。

这怎么可能?你真的不必再打电话给isCancelled()吗?

我的AsyncTask:

private class DownloadTask extends AsyncTask<String, String, String> {
    protected void onPreExecute() {
        progressdialog.setMessage("Preparing Download...");
        progressdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressdialog.setProgressNumberFormat(null);
        progressdialog.setProgressPercentFormat(null);
        progressdialog.setIndeterminate(true);
        progressdialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                progressdialog.dismiss();
                mytask.cancel(true);
            }
        });
        progressdialog.show();
    }

    protected String doInBackground(String... bla) {
        String error = download();
        return error;
    }

    protected void onProgressUpdate(String... s) {
        //....
    }

    protected void onPostExecute(String s) {
        progressdialog.dismiss();
        //....
    }

1 个答案:

答案 0 :(得分:1)

  

根据这个你应该在doInBackground中检查isCancelled()   定期因为mytask.cancel(true)不会中断   doInBackground本身。

实际上并非如此。

根据documentation

  

调用此方法后,应检查返回的值   isCancelled()定期从doInBackground(Object [])来完成   尽早完成任务。

这意味着您可以另外检查isCancelled()是否先停止AsyncTask ,如果它已启动。

mytask.cancel(true)无论如何都会停止执行。

让我们看看幕后发生了什么

致电mytask.cancel(true)时:

public final boolean cancel(boolean mayInterruptIfRunning) {
    mCancelled.set(true);
    return mFuture.cancel(mayInterruptIfRunning);
}

其中mFutureFutureTask,其中包含可运行的

然后调用mFuture.cancel

public boolean cancel(boolean mayInterruptIfRunning) {
    if (state != NEW)
        return false;
    if (mayInterruptIfRunning) {
        if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING))
            return false;
        Thread t = runner;
        if (t != null)
            t.interrupt();
        UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); // final state
    }
    else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED))
        return false;
    finishCompletion();
    return true;
}

runner只是

private volatile Thread runner;

由于它只是线程,让我们看看interrupt在您的情况下做了什么:

  

如果此线程在可中断的I / O操作中被阻止   然后通道将关闭,线程的中断状态   将被设置,线程将收到ClosedByInterruptException。

因此,如果您的download()方法使用InterruptibleChannel interrupt即可。

换句话说,您似乎从未调用isCancelled()来中断AsyncTask =),因为Thread.interrupt可以阻止您的阻止操作。