Reputation: 77
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...
Upvotes: 0
Views: 73
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
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
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