AsyncTask onCancelled(Object) 从未在 asyncTask.cancel(true) 之后调用;

Posted

技术标签:

【中文标题】AsyncTask onCancelled(Object) 从未在 asyncTask.cancel(true) 之后调用;【英文标题】:AsyncTask onCancelled(Object) never invoked after asyncTask.cancel(true); 【发布时间】:2016-07-31 10:23:35 【问题描述】:

正如文档所说,onCancelled(Object) 应该在以下时间被调用:

cancel(boolean) 被调用并且 doInBackground(Object[]) 已经完成。

在我的AsyncTask 中,我调用了this.cancel(true);,但从未调用过onCancelled(Object) 方法。

这里只贴相关代码。

MainActivity.java

 AsyncTask.Status asyncTaskStatus = new GethtmlDocument(urlString).execute().getStatus();

异步任务

private class GetHtmlDocument extends AsyncTask<String,Void,HtmlPage>
    
        private String url;

        /**
         * Constructor.
         *
         * @param url Url to parse from in the web.
         */
        public GetHtmlDocument(String url)
        
            this.url = url;
        

        @Override
        protected void onPreExecute()
        
            Log.d(MainActivity.ASYNC_TASK_TAG, "onPreExecute() called");
        

        @Override
        protected HtmlPage doInBackground(String... params)
        
            //android.os.Debug.waitForDebugger();
            Log.d(MainActivity.ASYNC_TASK_TAG, "doInBackground() called");

            if (this.isCancelled())
            
                return null;
            
            else
            


                HtmlPage htmlPage = new HtmlPage(getParsedDocument(this.url));

                return htmlPage;
            
        

        /**
         * Runs on the UI thread after doInBackground().
         * The specified result is the value returned by doInBackground().
         * This method won't be invoked if the asynchronous task was cancelled.
         *
         * @param htmlPage
         */
        @Override
        protected void onPostExecute(HtmlPage htmlPage)
        
            Log.d(MainActivity.ASYNC_TASK_TAG, "onPostExecute() called");

            if (htmlPage.getHtmlDocument() != null)
            
                this.cancel(true);
            

            setHtmlPage(htmlPage);
        

        /**
         * A task can be cancelled at any time by invoking cancel(boolean).
         * Invoking this method will cause subsequent calls to isCancelled() to return true.
         * After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns.
         * To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
         *
         * @param htmlPage
         *
         */
        @Override
        protected void onCancelled(HtmlPage htmlPage)
        
            Log.d(MainActivity.ASYNC_TASK_TAG, "onCancelled() called");
        


    

我调试了应用程序,我确定this.cancel(true);AsyncTask onPostExecute() 方法中被调用。

【问题讨论】:

【参考方案1】:

这仅仅是因为您在 AsyncTask 完成工作后调用了this.cancel(true)

意思是,您可以取消 AsyncTask,而它在 doInBackground 中执行其工作,并且在其状态为“完成”之后

来自文档,

可以通过调用cancel(boolean) 随时取消任务。 调用此方法将导致对isCancelled() 的后续调用 返回真。调用此方法后,onCancelled(Object),改为 的onPostExecute(Object) 将在之后调用 doInBackground(Object[]) 返回。确保任务被取消 你应该尽快检查返回值 isCancelled() 定期从doInBackground(Object[]),如果可能的话 (例如在循环内。)

所以很明显,onCancelled 方法是在 AsyncTask 执行任务时在 doInBackground 完成之前调用的,onCancelled(Object) 显然是为了调用“INSTEADonPostExecute 的取消事件。 cancel(true)method 旨在“中断”AsyncTask 的操作。

还有,我想知道你为什么要取消任务?您可以简单地检查结果是否为 null 并仅在其不为 null 时才执行 onPostExecute,如下所示:

@Override
protected void onPostExecute(HtmlPage htmlPage)

    if (htmlPage.getHtmlDocument() != null)
       Log.d(MainActivity.ASYNC_TASK_TAG, "onPostExecute() called");
       setHtmlPage(htmlPage);
    

@Override
protected void onPostExecute(HtmlPage htmlPage)

    Log.d(MainActivity.ASYNC_TASK_TAG, "onPostExecute() called");
    if (htmlPage.getHtmlDocument() != null)
       return;
    

    setHtmlPage(htmlPage);

【讨论】:

让我解决这个问题。当onPostExecute() 被调用时,AsyncTask 会自然终止吗? 没有。来自 Doc:onPostExecute(Result),在后台计算完成后在 UI 线程上调用。 onPostExecute 的执行后,AsyncTask 自然终止。但是你可以控制onPostExecute 来退出,就像返回一样。提供cancel(true) 是为了让您/用户控制异步任务的后台执行,例如如果需要太多时间,我们需要取消它。 cancel(true) 方法提供了在执行后台操作时取消 AsyncTask 的机会。而且,如果你能解释为什么要在onPostExecute 中取消任务,我可以解释更多 @God 如果能解决您的问题,请接受我的回答。谢谢 首先谢谢你。第二 - 我使用Jsoup 来解析doInBackground() 方法中的HTML 页面。问题是解析并不总是成功,因此 htmlPage 对象为空。我想知道doInBackground() 何时成功解析页面,然后将onPostExecute() 中的值分配给HtmlPage 的全局变量,并且不会再次调用doInBackground(),因此它无法更改全局 HtmlPage 再次为空。 它可以在 onPostExecute 中通过检查 HtmlPage 是否为空并相应地设置一个全局变量来完成。无需取消。并且,如果您在 doinbackground 中执行循环操作,并且如果在任何迭代中 HtmlPage 为空,则需要停止它,那么只需在每次迭代时检查 if(HtmlPage == null) 并检查 return HtmlPage; 是否为真。取消是为了给外部中断。您还有其他措施可以在内部结束操作:-)

以上是关于AsyncTask onCancelled(Object) 从未在 asyncTask.cancel(true) 之后调用;的主要内容,如果未能解决你的问题,请参考以下文章

如果超时或无法访问服务器,Fire base 不会调用 onCancelled

Android多线程的四种方式:Handler、AsyncTask、ThreadPoolExector、IntentService

AsyncTask - 等待其他 Asynctask 的执行

AsyncTask 替代背景图像下载? (AsyncTask ---------已弃用)

AsyncTask 坑 哪些线程可以调用AsyncTask

AsyncTask 坑 AsyncTask对象生命周期