当用户输入无效城市时,使用OpenWeatherMap的Android应用程序崩溃,如何处理API中的404代码?



我的应用程序已经实现了天气,并且正在使用OpenWeatherMap中的数据。

用户可以通过警报对话框代码输入他们想要天气的城市,但当他们输入无效城市时,应用程序崩溃。

这反过来将 URL 更改为:

http://api.openweathermap.org/data/2.5/weather?q={此处无效的城市} &units=metric&APPID={APP ID HERE}

并且 API 返回 {"cod":"404","消息":"找不到城市"},这会导致我的应用程序崩溃!

我的问题是:如何处理 404 代码,以便应用程序不会崩溃,但会通知用户他们需要输入有效的城市。- 如果这对你们来说是浪费时间,我很抱歉,但我仍在学习,对这一切很陌生...... 更详细的解释和非居高临下的指导方针将不胜感激,并将帮助我学习!

警报对话框如下:

private void showChangeCityDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(R.string.change_city_title);
final EditText cityInput = new EditText(MainActivity.this);
cityInput.setInputType(InputType.TYPE_CLASS_TEXT);
cityInput.setHint("Sofia,BG");
builder.setView(cityInput);
builder.setPositiveButton(R.string.submit, new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
if (cityInput.getText().toString().equals("")) {
Toast.makeText(MainActivity.this, "Please type a City name!", Toast.LENGTH_LONG).show();
return;
}
CityPreference cityPreference = new CityPreference(MainActivity.this);
cityPreference.setCity(cityInput.getText().toString());
String newCity = cityPreference.getCity();
renderWeatherData(newCity);
}
});
builder.show();
}

这是渲染天气数据的代码:

public void renderWeatherData(String city) {
WeatherTask weatherTask = new WeatherTask();
weatherTask.execute(new String[]{city + "&units=metric"});
}

崩溃时的错误是:

07-25 19:03:28.507 24691-25279/? E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
Process: com.vladimirtumbev.android.footballscorekeeper, PID: 24691
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
at org.json.JSONTokener.nextCleanInternal(JSONTokener.java:116)
at org.json.JSONTokener.nextValue(JSONTokener.java:94)
at org.json.JSONObject.<init>(JSONObject.java:156)
at org.json.JSONObject.<init>(JSONObject.java:173)
at data.JSONWeatherParser.getWeather(JSONWeatherParser.java:24)
at com.vladimirtumbev.android.footballscorekeeper.MainActivity$WeatherTask.doInBackground(MainActivity.java:465)
at com.vladimirtumbev.android.footballscorekeeper.MainActivity$WeatherTask.doInBackground(MainActivity.java:458)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
at java.lang.Thread.run(Thread.java:818)

我的两个扩展 AsyncTask 的类:

private class DownloadImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
@Override
protected Bitmap doInBackground(String... params) {
return downloadImage(params[0]);
}

@Override
protected void onPostExecute(Bitmap bitmap) {
iconView.setImageBitmap(bitmap);
}

private Bitmap downloadImage(String code) {
final DefaultHttpClient client = new DefaultHttpClient();
final HttpGet getRequest = new HttpGet(Utils.WEATHER_ICON_URL + code + ".png");
try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.e("DownloadImage", "Error:" + statusCode);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
inputStream = entity.getContent();
//decode contents from the stream
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
private class WeatherTask extends AsyncTask<String, Void, Weather> {
@Override
protected Weather doInBackground(String... params) {
String data = ((new WeatherHTTPClient()).getWeatherData(params[0]));
weather = JSONWeatherParser.getWeather(data);
weather.iconData = weather.currentCondition.getIcon();
new DownloadImageAsyncTask().execute(weather.iconData);
return weather;
}
@Override
protected void onPostExecute(Weather weather) {
super.onPostExecute(weather);
DecimalFormat decimalFormat = new DecimalFormat("#.#");
String tempFormat = decimalFormat.format(weather.currentCondition.getTemperature());
cityName.setText(weather.place.getCity() + "," + weather.place.getCountry());
temp.setText("" + tempFormat + "°C");
description.setText(weather.currentCondition.getCondition() + "(" + weather.currentCondition.getDescription() + ")");
}
}

我的 HTTP 帮助程序类:

public class WeatherHTTPClient {
public String getWeatherData(String place){
HttpURLConnection connection = null;
InputStream inputStream = null;
try {
connection = (HttpURLConnection) (new URL(Utils.WEATHER_BASE_URL + place + Utils.WEATHER_API_KEY)).openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
//            connection.setDoOutput(true);
connection.connect();
if(connection.getResponseCode() == 200) // 200 is ok
{
//Read the Response
StringBuffer stringBuffer = new StringBuffer();
inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line + "rn");
}
inputStream.close();
connection.disconnect();
return stringBuffer.toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

我的 JSON 天气解析器类:

public class JSONWeatherParser {
public static Weather getWeather(String data){
Weather weather = new Weather();
//Create JSON object from data
try {
JSONObject jsonObject = new JSONObject(data);
Place place = new Place();

JSONObject coordObj = Utils.getObject("coord", jsonObject);
place.setLat(Utils.getFloat("lat", coordObj));
place.setLon(Utils.getFloat("lon", coordObj));

//get Sys object
JSONObject sysObj = Utils.getObject("sys", jsonObject);
place.setCountry(Utils.getString("country",sysObj));
place.setCity(Utils.getString("name",jsonObject));
weather.place = place;
//get Weather info
JSONArray jsonArray = jsonObject.getJSONArray("weather");
JSONObject jsonWeather = jsonArray.getJSONObject(0);
weather.currentCondition.setWeatherId(Utils.getInt("id", jsonWeather));
weather.currentCondition.setDescription(Utils.getString("description", jsonWeather));
weather.currentCondition.setCondition(Utils.getString("main", jsonWeather));
weather.currentCondition.setIcon(Utils.getString("icon", jsonWeather));
JSONObject mainObj = Utils.getObject("main", jsonObject);
weather.currentCondition.setTemperature(Utils.getDouble("temp", mainObj));
JSONObject cloudObj = Utils.getObject("clouds", jsonObject);
weather.clouds.setPrecipitation(Utils.getInt("all", cloudObj));
return weather;
} catch (JSONException e) {
e.printStackTrace();
return null;
}

我还有一些带有二传手和getter的模型类,如果需要,可以添加它们。

谢谢你的帮助!!

这是堆栈跟踪中很重要的行

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference

你有NullPointerException(NPE(。您正在尝试获取 null 的字符串长度,这会导致它崩溃。堆栈跟踪中有一个行号,指向此调用发生的位置。所以找到那条线并用它包围

try { 
//line that throws exception
} catch (ExceptionType name) {
//do something in a case of exception       
}

WeatherHTTPClient类中,类似于

if(connection.getResponseCode() == 200) // 200 is ok
{

为响应代码 404 添加一个条件并相应地处理它。

你不能解析任何内容,所以你必须明确处理这种情况

public class JSONWeatherParser {
public static Weather getWeather(String data){
if (data == null) return null; // return back null 
Weather weather = new Weather();

在无法解析响应的情况下,您可以在 UI 中弹出一些消息

顺便说一下,HttpGet 和 HTTPClient 已被弃用,所以我建议你至少研究一下 Volley 或 Retrofit+Gson

还有滑动或毕加索加载图像

最新更新