cece
cece

Reputation: 77

Android Java with running AsyncTask and loop

I have problems with AsyncTask in android programming. I am trying to load weather json file from OpenWeatherMap APT in a background thread which is AsyncTask.

I have a button in activity_main.xml will invoke the "findWeather" function. And DownloadTask method will download result file using url. However, when I click the button, the app crashed and I got the error showing in the last pic.

I'm really new to android, I think there are might be a problem with the while loop in DownloadTask class but I'm not sure about it...

This is my MainActivity.java file

public class MainActivity extends Activity {

   EditText cityName;
   TextView resultTextView;

   public void findWeather(View view) {

       Log.i("cityName", cityName.getText().toString());

       InputMethodManager mgr = (InputMethodManager)               
getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(cityName.getWindowToken(), 0);

try {
    String encodedCityName =        
URLEncoder.encode(cityName.getText().toString(), "UTF-8");

     DownloadTask task = new DownloadTask();
    task.execute("http://api.openweathermap.org/data/2.5/weather?q=" + encodedCityName+"&apiid=5e8119137ab2c795f32cbbc4b046c57f");
       } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
           Toast.makeText(getApplicationContext(), "Could not find weather", Toast.LENGTH_LONG);
       }
   }

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

       cityName = findViewById(R.id.cityNameEditText);
       resultTextView =  findViewById(R.id.resultTextView);
   }

   public class DownloadTask extends AsyncTask<String, Void, String> {

       @Override
       protected String doInBackground(String... urls) {

           String result = "";
           URL url;
           HttpURLConnection urlConnection = null;

           try {
               url = new URL(urls[0]);

               urlConnection = (HttpURLConnection) url.openConnection();

               InputStream in = urlConnection.getInputStream();

               InputStreamReader reader = new InputStreamReader(in);

               int data = reader.read();

               while (data != -1) {
                   System.out.print("while loop");
                   char current = (char) data;
                   result += current;
                   data = reader.read();
               }

               return result;

           } catch (Exception e) {
               Toast.makeText(getApplicationContext(), "Could not find weather", Toast.LENGTH_LONG);
           }

           return null;
       }

       @Override
       protected void onPostExecute(String result) {
           super.onPostExecute(result);

           try {
               String message = "";
               JSONObject jsonObject = new JSONObject(result);
               String weatherInfo = jsonObject.getString("weather");

               Log.i("Weather content", weatherInfo);

               JSONArray arr = new JSONArray(weatherInfo);
               for (int i = 0; i < arr.length(); i++) {
                  JSONObject jsonPart = arr.getJSONObject(i);

                   String main = "";
                   String description = "";

                   main = jsonPart.getString("main");
                   description = jsonPart.getString("description");

                   if (main != "" && description != "") {
                       message += main + ": " + description + "\r\n";
                   }
               }

               if (message != "") {
                   resultTextView.setText(message);
               } else {
                   Toast.makeText(getApplicationContext(), "Could not find weather", Toast.LENGTH_LONG);
               }
           } catch (JSONException e) {
               Toast.makeText(getApplicationContext(), "Could not find weather", Toast.LENGTH_LONG);
           }
       }
   }
}

This is my activity_main.xml

  <?xml version="1.0" encoding="utf-8"?>
  <android.support.constraint.ConstraintLayout                               
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context="com.example.wangshuang.weatherapp.MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="4dp"
        android:layout_marginTop="8dp"
        android:scaleType="matrix"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/weather" />

    <EditText
        android:id="@+id/cityNameEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:ems="10"
        android:hint="Enter a city"
        android:inputType="textPersonName"
        android:text="Enter a city"
        android:textSize="24sp"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="62dp" />

    <Button
        android:id="@+id/citybtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="60dp"
        android:onClick="findWeather"
        android:text="What's the weather"
        app:layout_constraintTop_toBottomOf="@+id/cityNameEditText"
        tools:layout_editor_absoluteX="118dp" />

    <TextView
        android:id="@+id/resultTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="112dp"
        android:text="TextView"
        app:layout_constraintTop_toBottomOf="@+id/citybtn"
        tools:layout_editor_absoluteX="176dp" />
</android.support.constraint.ConstraintLayout>

And this is the error...

enter image description here

Upvotes: 0

Views: 73

Answers (3)

Jay Thummar
Jay Thummar

Reputation: 2299

Please remove Toast from catch section

You are getting exception in doInBackground in catch section. So whenever you want to print the exception message just use

e.printstacktrace(); 

You can't use Toast in background thread. It should be used in UI thread.

Upvotes: 1

Reaz Murshed
Reaz Murshed

Reputation: 24211

The error is pretty clear. It cannot show toast inside the AsyncTask. So the simpler way of solving this problem is to remove all toasts from your AsyncTask and get the callback of the AsyncTask in your Activity and then take necessary action based on the callback from your AsyncTask.

To prepare a callback mechanism in your AsyncTask, you need to declare an interface first.

Create an interface, DownloadListener.java

public interface DownloadListener {
    void onListen(String message);
}

Now, implement your MainActivity like the following using the interface.

public class MainActivity extends Activity implements DownloadListener {

    EditText cityName;
    TextView resultTextView;

    public void findWeather(View view) {

        Log.i("cityName", cityName.getText().toString());

        InputMethodManager mgr = (InputMethodManager)
                getSystemService(Context.INPUT_METHOD_SERVICE);
        mgr.hideSoftInputFromWindow(cityName.getWindowToken(), 0);

        try {
            String encodedCityName =
                    URLEncoder.encode(cityName.getText().toString(), "UTF-8");

            DownloadTask task = new DownloadTask();
            task.execute("http://api.openweathermap.org/data/2.5/weather?q=" + encodedCityName + "&apiid=5e8119137ab2c795f32cbbc4b046c57f");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "Could not find weather", Toast.LENGTH_LONG);
        }
    }

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

        cityName = findViewById(R.id.cityNameEditText);
        resultTextView = findViewById(R.id.resultTextView);
    }

    @Override
    public void onListen(String message) {
        Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
    }

    public class DownloadTask extends AsyncTask<String, Void, String> {

        DownloadListener listener;

        public DownloadTask(DownloadListener listener) {
            this.listener = listener;
        }

        @Override
        protected String doInBackground(String... urls) {

            String result = "";
            URL url;
            HttpURLConnection urlConnection = null;

            try {
                url = new URL(urls[0]);
                urlConnection = (HttpURLConnection) url.openConnection();
                InputStream in = urlConnection.getInputStream();
                InputStreamReader reader = new InputStreamReader(in);

                int data = reader.read();
                while (data != -1) {
                    System.out.print("while loop");
                    char current = (char) data;
                    result += current;
                    data = reader.read();
                }

                return result;

            } catch (Exception e) {
                result = null;
            }

            return null;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);

            try {
                String message = "";
                JSONObject jsonObject = new JSONObject(result);
                String weatherInfo = jsonObject.getString("weather");

                Log.i("Weather content", weatherInfo);

                JSONArray arr = new JSONArray(weatherInfo);
                for (int i = 0; i < arr.length(); i++) {
                    JSONObject jsonPart = arr.getJSONObject(i);

                    String main = "";
                    String description = "";

                    main = jsonPart.getString("main");
                    description = jsonPart.getString("description");

                    if (main != "" && description != "") {
                        message += main + ": " + description + "\r\n";
                    }
                }

                if (message != "") {
                    resultTextView.setText(message);
                } else {
                    listener.httpResponseReceiver("Could not find weather");
                }
            } catch (JSONException e) {
                listener.httpResponseReceiver("Could not find weather");
            }
        }
    }
}

Upvotes: 0

Kapil G
Kapil G

Reputation: 4141

You cannot show a Toast in background thread as that is a UI element and requires UI thread to be executed. Hence it can only be shown in postExecute for example in the AsyncTask scenario.

Remove Toast.makeText(getApplicationContext(), "Could not find weather", Toast.LENGTH_LONG);

from the Exception and print the exception using e.printStackTrace() and see if you get any error.

Upvotes: 0

Related Questions