【问题标题】:AsyncTask onCancelled(Object) never invoked after asyncTask.cancel(true);AsyncTask onCancelled(Object) 从未在 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() 方法中被调用。

【问题讨论】:

    标签: java android multithreading android-studio android-asynctask


    【解决方案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; 是否为真。取消是为了给外部中断。您还有其他措施可以在内部结束操作:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多