0

I am new to android and this is my first use of JSoup and Async task. I want to be able to get aviation weather forecasts in my app from this website (aviationweather.gov).

The table data I am trying to parse with Jsoup looks like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<HTML>
<HEAD>
<TITLE>ADDS - TAFS form results</TITLE>
<LINK REL="StyleSheet" type="text/css" HREF="/layout/awc/mystyle.css">
</HEAD>
<BODY BGCOLOR="#FFFFFF">
  <TABLE SUMMARY="This table is used for formatting purposes only" BORDER=0 CELLPADDING=3 CELLSPACING=0>
    <TR VALIGN="top">
      <TD ALIGN="left" COLSPAN="2">
        <H2>Aviation Digital Data Service (ADDS)</H2>
        Output produced by TAFs form (1417&#160;UTC&nbsp;22 November 2013)<BR>
        found at <A HREF="http://www.aviationweather.gov/adds/tafs/"> http://www.aviationweather.gov/adds/tafs/</A><BR>&#160;<BR>
      </TD>
    </TR>
    <TR VALIGN="top">
      <TD ALIGN="left" COLSPAN="2">
        <PRE><font face="Monospace,Courier" size="+1">TAF EGXC 221321Z 2215/2224 01010KT 9999 SCT035 
     PROB30 
     TEMPO 2216/2224 BKN020
       </font></PRE>
        <PRE><font face="Monospace,Courier" size="+1">TAF EGOV 221323Z 2215/2218 01008KT 9999 FEW020
       </font></PRE>
        <PRE><font face="Monospace,Courier" size="+1">TAF EGXE 221047Z 2212/2217 34008KT 9999 FEW020 SCT030 
     TEMPO 2212/2215 -SHRA SCT018
       </font></PRE>
      </TD>
    </TR>
  </TABLE>
</BODY>
</HTML>

The amount of rows of the table relates to how many airfields weather the user asks for.

I am calling the Async task when an imagebutton is clicked by this code:

new getPage().execute();

getPage() looks like this:

private class getPage extends AsyncTask<String, Void, String> {

    ProgressDialog prog;

    protected void onPreExecute() {
        prog = new ProgressDialog(Weathergrabber.this);
        prog.setMessage("Loading....");
        prog.show();
    }

    @Override
    protected String doInBackground(String... params) {
        try {
            // lets format the icaos the user is interested in
            if (etICAO1.getText().toString().length() > 0) {
                icaos = etICAO1.getText().toString();
            }

            if (etICAO1.getText().toString().length() == 0) {
                // editText is empty

            }

            if (etICAO2.getText().toString().length() > 0) {
                icaos = icaos + "+" + etICAO2.getText().toString();
            }

            if (etICAO2.getText().toString().length() == 0) {
                // editText is empty

            }

            if (etICAO3.getText().toString().length() > 0) {
                icaos = icaos + "+" + etICAO3.getText().toString();
            }

            if (etICAO3.getText().toString().length() == 0) {
                // editText is empty

            }

            if (etICAO4.getText().toString().length() > 0) {
                icaos = icaos + "+" + etICAO4.getText().toString();
            }

            if (etICAO4.getText().toString().length() == 0) {
                // editText is empty

            }

            if (etICAO5.getText().toString().length() > 0) {
                icaos = icaos + "+" + etICAO5.getText().toString();
            }

            if (etICAO5.getText().toString().length() == 0) {
                // editText is empty

            }

            if (etICAO6.getText().toString().length() > 0) {
                icaos = icaos + "+" + etICAO6.getText().toString();
            }

            if (etICAO6.getText().toString().length() == 0) {
                // editText is empty

            }

            if (etICAO7.getText().toString().length() > 0) {
                icaos = icaos + "+" + etICAO7.getText().toString();
            }

            if (etICAO7.getText().toString().length() == 0) {
                // editText is empty

            }

            if (etICAO8.getText().toString().length() > 0) {
                icaos = icaos + "+" + etICAO8.getText().toString();
            }

            if (etICAO8.getText().toString().length() == 0) {
                // editText is empty

            }

            // now lets format the webaddress
            finalWebAddress = websitePart1 + icaos + websitePart2;
            // try to get the data
            Toast.makeText(getApplicationContext(),
                    "Collecting data from " + finalWebAddress,
                    Toast.LENGTH_LONG).show();

            Document doc;
            doc = Jsoup.connect(finalWebAddress).userAgent("Mozilla").get();
            Element tableElement = doc.select("tr").first();

            theWeather = doc.title();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return theWeather;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        prog.dismiss();
        tvWeather.setText(result);
    }
}

I was hoping that the textview tvWeather would have the table data added to it, but the application is crashing with a logcat of:

11-22 14:46:43.100: E/AndroidRuntime(2507): FATAL EXCEPTION: AsyncTask #1
11-22 14:46:43.100: E/AndroidRuntime(2507): java.lang.RuntimeException: An error occured while executing doInBackground()
11-22 14:46:43.100: E/AndroidRuntime(2507):     at android.os.AsyncTask$3.done(AsyncTask.java:299)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.lang.Thread.run(Thread.java:856)
11-22 14:46:43.100: E/AndroidRuntime(2507): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
11-22 14:46:43.100: E/AndroidRuntime(2507):     at android.os.Handler.<init>(Handler.java:121)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at android.widget.Toast$TN.<init>(Toast.java:361)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at android.widget.Toast.<init>(Toast.java:97)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at android.widget.Toast.makeText(Toast.java:254)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at com.Weathergrabber$getPage.doInBackground(Weathergrabber.java:293)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at com.Weathergrabber$getPage.doInBackground(Weathergrabber.java:1)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
11-22 14:46:43.100: E/AndroidRuntime(2507):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)

As I said I am new to using AsyncTask and Jsoup so am not sure where the error lies. Hopefully I have provided enough detail to help generate an answer.

Thanks;

Andy

andy
  • 391
  • 13
  • 33
  • Why was this question marked down? I tried to give as much information as I could and hadn't been able to find any similar issues when searching. – andy Nov 23 '13 at 03:58
  • Seems it's downvoted, because there's bunch of question about the same exception ('RuntimeException: Can't create handler inside thread that has not called Looper.prepare()') at stackoverflow. And your question looks like simple duplicate of this one: http://stackoverflow.com/questions/5009816/android-cant-create-handler-inside-thread-that-has-not-called-looper-prepare – sandrstar Nov 23 '13 at 09:32
  • 1
    I have a way to go before that post looks like a duplicate to me! I will search broader terms in future and try to find similar exceptions and not just my specific implementation. Thanks. – andy Nov 23 '13 at 11:49

1 Answers1

1

I see your problem there. You are trying to make a Toast in the background thread. You can only make a Toast in the ui thread.

Try something like:

new Handler().post(new Runnable() {
    @Override
    public void run() {
        // Code here will run in UI thread
    }
});

Or you could also call the toast as a progress message from the AsyncTask using AsyncTask's publishProgress and onProgressUpdate methods. onProgressUpdate

spierce7
  • 14,797
  • 13
  • 65
  • 106
  • Thanks for the reply. I'm new to logcat, could you show me how I could have spotted that error myself from the logcat I posted? – andy Nov 22 '13 at 16:22
  • @andy Sure, there are a few ways you could have easily figured this out. The key is the way that exceptions happen in Java. Exceptions with proper try/catch block hierarchies cause other exceptions to be thrown. There are 2 exceptions in the Stack trace you posted. The second exception is at the top, and the exception that caused the second exception to be thrown is below it (the first exception. This is the one that we really care about), it is denoted by the "Caused by", saying the exception above was caused by this exception here. If you follow that exception, you see... – spierce7 Nov 23 '13 at 05:54
  • If you follow that exception, you see that your async task is called (com.Weathergrabber$getPage.doInBackground), then Toast.makeText is called. From the exception, you can logically see that there is a problem here while calling Toast.makeText (as everything after that is happening within Toast.makeText. That pinpoints you to something is going on with the Toast. If you read the first exception's text (remember, the one on the bottom) it's vaguely talking about some weird threading issue. It's not clear that it want's the main thread, but that should cause us to remember that... – spierce7 Nov 23 '13 at 05:59
  • but that should cause us to remember that View's can only be created and manipulated in the main/ui thread (common android knowledge). So all that described above is one way you could do it, or you could just take the message text, do a google search on it, and find other people that had the same problem :-P Best of luck! – spierce7 Nov 23 '13 at 06:01