即使使用取消方法也无法取消 AsyncTask 中的 doInBackground 进程

Posted

技术标签:

【中文标题】即使使用取消方法也无法取消 AsyncTask 中的 doInBackground 进程【英文标题】:Can't cancel doInBackground process in AsyncTask even using cancel method 【发布时间】:2013-11-03 01:35:37 【问题描述】:

我已经在 onCreate() 方法中声明了扩展 AsyncTask 的 FileUploadTask 实例

                FileUploadTask uploadTask= null;

并通过以下代码执行后台方法

                    public class UploadFiles implements OnClickListener

                    ....

                    if(SOTCNetStat.chkConnectionStatus(UploadResult.this))
                                uploadTask=new FileUploadTask();
                                uploadTask.execute("");
                            
                            else
                            
                                Toast.makeText(UploadResult.this, getResources().getString(R.string.Text_CheckNetworkConnections) , Toast.LENGTH_LONG).show();                              
                            
                    ....

                

有一个取消按钮来取消后台进程

                cancel.setOnClickListener(new OnClickListener() 
                @Override
                        public void onClick(View v) 
                            // TODO Auto-generated method stub
                            Log.d(TAG,"cancel button clicked.....");
                            //FileUploadTask uploadTask= new FileUploadTask();
                            if(uploadTask!=null)
                            
                                Log.d(TAG,"click event null checking....");
                                uploadTask.cancel(true);
                            


                        

                

在 FileUploadTask 类中声明了一个布尔值来检查运行状态

        public class FileUploadTask extends AsyncTask<String, Integer, String> 
        ....
            boolean isRunning=true;

doInBackground 方法

    @Override
        protected String doInBackground(String... arg0) 

            for(int i=0; i<fp.size(); i++)
                index = i+1;

                if(isCancelled() && !isRunning)
                
                    Log.d(TAG,"Cancel 1 Condition Checked ["+i+"]");
                    Log.d(TAG,"doInBackground canceled");
                    break;

                
                else
                
                    Log.d(TAG,"Cancel 1 Canceled ["+i+"]");
                

                file1 = new File(fp.get(i));

                String urlString = Constants.UPLOAD_URL;

                try 

                    Log.e("doInBackground", "urlString: " + urlString);

                    Log.e("doInBackground", "domainPref: " + domainName);

                    urlString = urlString.replace("domain", URLEncoder.encode(domainName, "UTF-8"));

                 catch (UnsupportedEncodingException e) 
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                




                try 

                    HttpClient client = new DefaultHttpClient();
                    HttpPost post = new HttpPost(urlString);
                    FileBody bin1 = new FileBody(file1);

                    ProgressMultipart reqEntity = new ProgressMultipart(new ProgressListener() 

                        @Override
                        public void transferred(long num) 
                            //publishProgress((int) ((num / (float) file1.length() ) * 100));

                            publishProgress((int) ((num / (float) totalSize ) * 100));
                        
                    );

                    reqEntity.addPart("userfile", bin1);
                    if(getIntent().hasExtra("show_id"))
                    
                        //String showId = getIntent().getStringExtra("show_id");
                        reqEntity.addPart("mobileshow", new StringBody("1"));
                        reqEntity.addPart("show_ids", new StringBody(getIntent().getStringExtra("show_id")));
                    
                    reqEntity.addPart("Filename", new StringBody(file1.getName()));
                    reqEntity.addPart("user_id", new StringBody("2"));
                    reqEntity.addPart("privateasset", new StringBody("true"));
                    reqEntity.addPart("uploadtype", new StringBody("Normal"));
                    reqEntity.addPart("version_num", new StringBody("1"));

                    totalSize = reqEntity.getContentLength();

                    post.setEntity(reqEntity);

                    System.err.println("post :"+post.toString());

                    //to be check the cancel operation
                    if(isCancelled() && !isRunning)
                    
                        Log.d(TAG,"Cancel 2 Condition Checked ["+i+"]");
                        Log.d(TAG,"File Uploading Cancelled in doInBackground method");
                        break;
                    
                    else
                    
                        Log.d(TAG,"Cancel 2 Canceled ["+i+"]");
                    

                    HttpResponse response = client.execute(post);

                    resEntity = response.getEntity();
                    response_str = EntityUtils.toString(resEntity);
                 
    ....
    return response_str;
    

和重载的 onCancelled 方法

@Override
        protected void onCancelled() 
            // TODO Auto-generated method stub
            Log.d(TAG,"onCancelled() method called");
            super.onCancelled();

        

        @Override
        protected void onCancelled(String result) 
            // TODO Auto-generated method stub
            Log.d(TAG,"onCancelled(String) method called");

            isRunning=false;


            this.cancel(true);

        

我尝试了很多并探索了。即使使用取消方法,我也无法在后台停止上传过程。请任何人提供解决问题的方法 我提到的一些链接

http://www.technotalkative.com/cancel-asynctask-in-android/

http://developer.android.com/reference/android/os/AsyncTask.html

【问题讨论】:

【参考方案1】:

您似乎错过了AsyncTask 的工作原理。 onCancelled() 方法只会在doInBackground() 完成后调用,类似于onPostExecute() 方法。在uploadTask.cancel(true) 被调用后,它不会像你想象的那样立即被调用。您使用它的方式,您不需要onCancelled() 方法或isRunning 变量(当前在您的代码中isRunning 永远不会更改为false,因此您的isCancelled() 检查永远不会起作用)。删除onCancelled() 方法和isRunning 变量,您的AsyncTask 将起作用。

【讨论】:

两者都被删除。但是上传完成并没有取消它 if(isCancelled()) break; 在我在代码中提到的 for 循环和 catch 之前的相同代码中。然后我删除了两个 onCancelled() 方法。 还有其他事情发生。您的client.execute() 调用创建了一个单独的线程(与执行donInBackground() 的线程不同),并且该单独的线程通过定期调用您传递给reqEntitytransferred() 方法来更新下载状态。显然您不能取消这个单独的线程(不过,需要在您使用的 API 中验证这种限制)。顺便说一句,这里实际上不需要使用 AsyncTask。 如果 ProgressMultipart 不允许取消进度,请尝试在 AsyncTask 中使用 this approach(进行一些调整,因为您要读取字节而不是行)并添加 publishProgress()打电话给它。您在循环中读取输入流并在读取流时更新进度对话框,能够在循环期间检查isCancelled() 注意:我可能对client.execute() 创建一个单独的线程有误,但我的建议仍然有效。【参考方案2】:

勾选这个,取消异步任务后写这个条件。

if(asynctask.iscancel())
break;

它可能对你有帮助。 :)

http://developer.android.com/reference/android/os/AsyncTask.html

【讨论】:

以上是关于即使使用取消方法也无法取消 AsyncTask 中的 doInBackground 进程的主要内容,如果未能解决你的问题,请参考以下文章

如何取消Android中的AsyncTask?

差异b / w在AsyncTask Android中取消(true)和取消(false)

Android开发--取消AsyncTask

带有进度对话框取消的 Android AsyncTask

Android - 强制取消 AsyncTask

即使取消订阅,订阅者也会触发