取消执行AsyncTask的理想方法

问题描述 投票:107回答:9

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

当用户取消(决定)操作时,我想取消/中止AsyncTask运行。处理这种情况的理想方式是什么?

android android-asynctask
9个回答
78
投票

刚刚发现AlertDialogsboolean 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;
    }

    // ...

}

76
投票

如果你正在进行计算:

  • 你必须定期检查isCancelled()

如果您正在执行HTTP请求:

  • 保存你的HttpGetHttpPost的实例(例如公共领域)。
  • 在致电cancel后,请致电request.abort()。这将导致IOException被扔进你的doInBackground

在我的例子中,我有一个连接器类,我在各种AsyncTasks中使用它。为了简单起见,我在该类中添加了一个新的abortAllRequests方法,并在调用cancel后直接调用此方法。


20
投票

问题是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;
        }
     }

11
投票

简单:不要使用AsyncTaskAsyncTask专为短时间操作而设计,可快速结束(数十秒),因此无需取消。 “音频文件播放”不符合条件。您甚至不需要后台线程来播放普通音频文件。


4
投票

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


4
投票

这就是我编写AsyncTask的方法 关键点是添加Thread.sleep(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;
    }

0
投票

我们的全局AsyncTask类变量

LongOperation LongOperationOdeme = new LongOperation();

和KEYCODE_BACK动作中断AsyncTask

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

这个对我有用。


0
投票

我不喜欢用cancel(true)强制中断我的异步任务,因为它们可能有资源被释放,例如关闭套接字或文件流,将数据写入本地数据库等。另一方面,我遇到过的情况异步任务拒绝在部分时间内完成自己,例如有时当主活动被关闭时,我请求异步任务从活动的onPause()方法内部完成。所以这不是简单地调用running = false的问题。我必须找到一个混合解决方案:两个调用running = false,然后给几个毫秒的异步任务完成,然后调用cancel(false)cancel(true)

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()。但至少可以保证异步任务终止。


0
投票

参考Yanchenko在2010年4月29日的回答:当每次执行AsyncTask期间必须多次执行'doInBackground'下的代码时,使用'while(running)'方法很简洁。如果'doInBackground'下的代码每次执行AsyncTask只需要执行一次,那么在'while(running)'循环中将所有代码包装在'doInBackground'下将不会阻止后台代码(后台线程)运行时AsyncTask本身被取消,因为只有在while循环中的所有代码至少执行一次后才会评估'while(running)'条件。因此,您应该(a。)将“doInBackground”下的代码分解为多个“while(运行)”块或(b。)在“doInBackground”代码中执行大量“isCancelled”检查,如“取消任务”中所述“在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;}
}

// ...
© www.soinside.com 2019 - 2024. All rights reserved.