3

I know there a lot of AsyncTask questions about this but none happened to help me.

I got an AsyncTask that handles some HTML parsing using Jsoup.

I debugged the app countless times(really) and after doInBackground() method called i get the values i want to send to onPostExecute() method but the problem the onPostExecute() method is never called.

I guess it's something simple that slip through me.

Just relevant code.

MainActivity.java:

private HtmlPage htmlPage = new HtmlPage();

    private static final String ASYNC_TASK_TAG = "AsyncTask";

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Getting the HTML document from a background thread
        new GetHtmlDocument("someUrlString").execute();

        if (this.htmlPage.getHtmlDocument() != null)
        {
            new GetHtmlDocument("someUrlString").cancel(true);
        }

        while (this.htmlPage.getHtmlDocument() == null)
        {
            if (this.htmlPage.getHtmlDocument() != null)
            {
                new GetHtmlDocument("someUrlString").cancel(true);
            }
            else
            {
                new GetHtmlDocument("someUrlString").execute();
            }
        }
    }

AsyncTask inner class:

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");

            // Get the HTML http://www.lyricsplanet.com/ document
            HtmlPage htmlPage = new HtmlPage(getParsedDocument(this.url));

            return 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");
        }
    }

Method used in onPostExecute():

public void setHtmlPage(HtmlPage htmlPage)
    {
        this.htmlPage = htmlPage;
    }

HtmlPage.java:

public class HtmlPage
{
    private Document htmlDocument;

    public HtmlPage(Document htmlDocument)
    {
        this.htmlDocument = htmlDocument;
    }
}

Method that used in doInBackground():

   public Document getParsedDocument(String url)
    {
        try
        {
            return Jsoup.connect(url).get();
        }
        catch (IOException e) // On error
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null; // Failed to connect to the url
    }

I guess the problem is with the main Thread that never gets a chance to call onPostExecute() method or something with the Generic parameters of my AsyncTask or something with my implementation of my AsyncTask class.

Any suggestions will be very appreciated.

EDIT:

I forgot about the W/art: Suspending all threads took: 1.1ms warning. I get that for running the app. But when i debug the app i don't get that and i clearly see that the HtmlPage object that's been generated in the doInBackground() method get the value i want.

God
  • 1,238
  • 2
  • 18
  • 45
  • It's not entirely clear why you're cancelling the task right after starting it in onCreate(), this might be the problem. – Egor Apr 09 '16 at 18:14
  • @Egor If i get what i wanted from the `AsyncTask` which is a not null `HtmlPage` object i just cancel the `AsyncTask` execution. And BTW even if i remove that line it stays exactly the same. – God Apr 09 '16 at 18:21
  • AsyncTask is just that - async, the execution runs on a different thread, so you can't expect to call execute() and have the result on the next line of code. – Egor Apr 09 '16 at 18:22
  • @Egor I know but removing the cancel statements isn't the issue unfortunately. – God Apr 09 '16 at 18:27
  • @Egor What about the `Suspending all threads` warning? – God Apr 09 '16 at 18:28

2 Answers2

1

It's because your onCreate() kicks off the AsyncTask then polls via the while loop, waiting for completed data. It's starving off any other thread. You need to handle the result asynchronously. Try using a Handler and have onPostExecute() send a message when it is done.

Larry Schiefer
  • 15,687
  • 2
  • 27
  • 33
  • By `Handler` you referring to something like that http://stackoverflow.com/questions/11713625/android-handler-for-asynctask ----- or an interface that initialize on the main `Thread` and that is a part of the `AsyncTask` class properties? Thank you for your help man. – God Apr 10 '16 at 05:07
  • Can you refer to this? http://stackoverflow.com/questions/36528668/asynctask-oncancelledobject-never-invoked-after-asynctask-canceltrue – God Apr 10 '16 at 10:41
  • You could use a `Handler` created in your `onCreate`. Or, if done properly, do the action directly in the `onPostExecute`. You need to be careful with `AsyncTask` as it is not life cycle aware and if allowed to directly manipulate UI components it can cause problems. This article will help explain: http://po.st/Cei3m2 – Larry Schiefer Apr 10 '16 at 13:28
1

Just call new GetHtmlDocument("someUrlString").execute(); and wait result in the onPostExecute(). There is no need to use while loop (that blocks your UI thread) or to call cancel() (actually it doesn't do anything by default, check link at the bottom).

Be aware,

AsyncTask should only be used for tasks/operations that take quite few seconds;

AsyncTasks are executed serially on a single background thread (from API 11). So long running worker can block others;

Some other gotchas.

Maxim G
  • 1,479
  • 1
  • 15
  • 23