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

取消正在执行的异步任务的理想方法

  •  107
  • Samuh  · 技术社区  · 15 年前

    我正在后台线程中运行远程音频文件获取和音频文件播放操作,使用 AsyncTask . 一 Cancellable 显示运行获取操作时的进度条。

    我想取消/中止 异步任务 当用户取消(决定)操作时运行。处理这种案件的理想方法是什么?

    9 回复  |  直到 7 年前
        1
  •  78
  •   yanchenko    15 年前

    刚刚发现 AlertDialogs boolean cancel(...); 我到处都在用其实什么也没用。伟大的。
    所以…

    public class MyTask extends AsyncTask<Void, Void, Void> {
    
        private volatile boolean running = true;
        private final ProgressDialog progressDialog;
    
        public MyTask(Context ctx) {
            progressDialog = gimmeOne(ctx);
    
            progressDialog.setCancelable(true);
            progressDialog.setOnCancelListener(new OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    // actually could set running = false; right here, but I'll
                    // stick to contract.
                    cancel(true);
                }
            });
    
        }
    
        @Override
        protected void onPreExecute() {
            progressDialog.show();
        }
    
        @Override
        protected void onCancelled() {
            running = false;
        }
    
        @Override
        protected Void doInBackground(Void... params) {
    
            while (running) {
                // does the hard work
            }
            return null;
        }
    
        // ...
    
    }
    
        2
  •  75
  •   wrygiel    13 年前

    如果你在做计算 :

    • 你得检查一下 isCancelled() 定期地。

    如果你在做一个http请求 :

    • 保存 HttpGet HttpPost 某处(如公共场所)。
    • 打电话之后 cancel ,呼叫 request.abort() . 这会导致 IOException 被扔进你的 doInBackground .

    在我的例子中,我有一个连接器类,用于各种异步任务。为了简单起见,我添加了一个新的 abortAllRequests 方法,并在调用 取消 .

        3
  •  20
  •   BenMorel Manish Pradhan    11 年前

    问题是asynctask.cancel()调用只调用任务中的onCancel函数。这是您要处理取消请求的位置。

    这里有一个小任务,我用来触发一个更新方法

    private class UpdateTask extends AsyncTask<Void, Void, Void> {
    
            private boolean running = true;
    
            @Override
            protected void onCancelled() {
                running = false;
            }
    
            @Override
            protected void onProgressUpdate(Void... values) {
                super.onProgressUpdate(values);
                onUpdate();
            }
    
            @Override
            protected Void doInBackground(Void... params) {
                 while(running) {
                     publishProgress();
                 }
                 return null;
            }
         }
    
        4
  •  11
  •   CommonsWare    15 年前

    简单:不要使用 AsyncTask . 异步任务 设计用于快速结束(数十秒)的短操作,因此不需要取消。”音频文件播放“不合格。你甚至不需要一个背景线程来播放普通的音频文件。

        5
  •  4
  •   dbyrne    15 年前

    唯一的方法是检查isCancelled()方法的值,并在返回true时停止播放。

        6
  •  4
  •   Andrew Chen    14 年前

    这就是我编写异步任务的方式
    关键是添加线程,睡眠(1);

    @Override   protected Integer doInBackground(String... params) {
    
            Log.d(TAG, PRE + "url:" + params[0]);
            Log.d(TAG, PRE + "file name:" + params[1]);
            downloadPath = params[1];
    
            int returnCode = SUCCESS;
            FileOutputStream fos = null;
            try {
                URL url = new URL(params[0]);
                File file = new File(params[1]);
                fos = new FileOutputStream(file);
    
                long startTime = System.currentTimeMillis();
                URLConnection ucon = url.openConnection();
                InputStream is = ucon.getInputStream();
                BufferedInputStream bis = new BufferedInputStream(is);
    
                byte[] data = new byte[10240]; 
                int nFinishSize = 0;
                while( bis.read(data, 0, 10240) != -1){
                    fos.write(data, 0, 10240);
                    nFinishSize += 10240;
                    **Thread.sleep( 1 ); // this make cancel method work**
                    this.publishProgress(nFinishSize);
                }              
                data = null;    
                Log.d(TAG, "download ready in"
                      + ((System.currentTimeMillis() - startTime) / 1000)
                      + " sec");
    
            } catch (IOException e) {
                    Log.d(TAG, PRE + "Error: " + e);
                    returnCode = FAIL;
            } catch (Exception e){
                     e.printStackTrace();           
            } finally{
                try {
                    if(fos != null)
                        fos.close();
                } catch (IOException e) {
                    Log.d(TAG, PRE + "Error: " + e);
                    e.printStackTrace();
                }
            }
    
            return returnCode;
        }
    
        7
  •  0
  •   Göksel Güren    12 年前

    全局asynctask类变量

    LongOperation LongOperationOdeme = new LongOperation();
    

    以及中断异步任务的keycode_back操作

       @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                LongOperationOdeme.cancel(true);
            }
            return super.onKeyDown(keyCode, event);
        }
    

    对我有用。

        8
  •  0
  •   Piovezan    12 年前

    我不喜欢用 cancel(true) 不必要,因为它们可能有资源需要释放,例如关闭套接字或文件流、将数据写入本地数据库等。另一方面,我遇到了异步任务在一段时间内拒绝完成自身的情况,例如有时主活动是正在关闭,我请求从活动的内部完成异步任务 onPause() 方法。所以这不是简单的打电话 running = false . 我必须寻求一个混合的解决方案:两个都可以 运行=错误 ,然后给异步任务几毫秒的时间来完成,然后调用 cancel(false) 取消(真) .

    if (backgroundTask != null) {
        backgroundTask.requestTermination();
        try {
            Thread.sleep((int)(0.5 * 1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (backgroundTask.getStatus() != AsyncTask.Status.FINISHED) {
            backgroundTask.cancel(false);
        }
        backgroundTask = null;
    }
    

    作为副作用,在 doInBackground() 完成,有时 onCancelled() 方法被调用,有时 onPostExecute() . 但至少异步任务的终止是有保证的。

        9
  •  0
  •   Alex Ivan Howard    7 年前

    关于Yanchenko在2010年4月29日的回答: 使用“while(running)”方法在每次执行asynctask时都必须多次执行“doinbackground”下的代码,这样做很好。如果每次执行asynctask时只需执行“doinbackground”下的代码一次,则在“while(running)”循环中将所有代码包装在“doinbackground”下不会在取消asynctask本身时停止后台代码(后台线程)的运行,因为“while(run仅当while循环中的所有代码至少执行一次时,才会计算“ning”条件。你也应该这样 (a.)将“doinbackground”下的代码分解为多个“while(running)”块或 (b.)在“doinbackground”代码中执行许多“取消”检查,如在 https://developer.android.com/reference/android/os/AsyncTask.html .

    因此,对于(a)选项,可以修改Yanchenko的回答如下:

    public class MyTask extends AsyncTask<Void, Void, Void> {
    
    private volatile boolean running = true;
    
    //...
    
    @Override
    protected void onCancelled() {
        running = false;
    }
    
    @Override
    protected Void doInBackground(Void... params) {
    
        // does the hard work
    
        while (running) {
            // part 1 of the hard work
        }
    
        while (running) {
            // part 2 of the hard work
        }
    
        // ...
    
        while (running) {
            // part x of the hard work
        }
        return null;
    }
    
    // ...
    

    对于选项(b.)“doinbackground”中的代码将如下所示:

    public class MyTask extends AsyncTask<Void, Void, Void> {
    
    //...
    
    @Override
    protected Void doInBackground(Void... params) {
    
        // part 1 of the hard work
        // ...
        if (isCancelled()) {return null;}
    
        // part 2 of the hard work
        // ...
        if (isCancelled()) {return null;}
    
        // ...
    
        // part x of the hard work
        // ...
        if (isCancelled()) {return null;}
    }
    
    // ...