代码之家  ›  专栏  ›  技术社区  ›  Neph

android/asynctask:你还需要检查iscancelled(api 24)吗?

  •  0
  • Neph  · 技术社区  · 8 年前

    我的应用程序使用 AsyncTask 在显示 ProgressDialog (我知道它被弃用了)用一个“取消”按钮。

    根据 this 你应该检查一下 isCancelled() 在里面 doInBackground 周期性的,因为 mytask.cancel(true) 不会打断的 干背地 独自一人。

    我一开始没有检查就取消了任务,但发现它仍然停止了 干背地 :根据在按下“取消”按钮之前让它下载的时间,我在结果文件中看到了不同的大小-从几KB到几MB-最终大小大约为9MB。

    这怎么可能?你真的不用打电话 取消() 不再?

    我的异步任务:

    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 回复  |  直到 8 年前
        1
  •  1
  •   Andrey Danilov    8 年前

    根据这个,您应该检查doinbackground中的isCancelled() 因为mytask.cancel(true)不会中断 靠自己的力量。

    事实上这不是真的。

    根据 documentation :

    调用此方法后,应检查 从doinbackground(object[])定期取消()以完成 尽早完成任务。

    意思是你可以 另外 检查 isCancelled() 停止 AsyncTask 早期的 如果它启动了。

    mytask.cancel(true)将停止执行。

    让我们看看引擎盖下面发生了什么

    当你打电话 mytask.cancel(true) :

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

    在哪里? mFuture 是 FutureTask 里面有Runnable

    然后 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 打断 会工作。

    换言之,你好像从来没有打过电话 取消() 中断 异步任务 =) Thread.interrupt 在您的情况下可以停止IO阻塞操作。