如何阻止异常搜索 Unavailable/no 个城市?
How to stop exception from searching Unavailable/no cities?
我有一个天气应用程序,可以搜索在 EditText
上输入的任何城市,而且效果很好。
但问题是,每当我搜索不可用的城市或将 EditText
留空并单击搜索按钮时,应用程序崩溃并在我的 phone 上报告 "(my app) has stopped"
(这仅发生在我search an unavailable city/no city is searched), 它可以正确搜索任何有效的城市。
这是我的 Logcat 显示的内容(仅当搜索到不可用的城市时):
java.lang.NullPointerException: Attempt to invoke virtual method 'com.viz.lightweatherforecast.Retrofit.Example$Main com.viz.lightweatherforecast.Retrofit.Example.getMain()' on a null object reference
at com.viz.lightweatherforecast.FirstFragment.onResponse(FirstFragment.java:104)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=11=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCallwC8FyV4pyjrzrYL5U0mlYiviZw.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6819)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
和
java.lang.NullPointerException: Attempt to invoke virtual method 'com.viz.lightweatherforecast.first.PrettyTime com.viz.lightweatherforecast.Retrofit.Example.getDt()' on a null object reference
at com.viz.lightweatherforecast.Activity.HomeActivity.onResponse(HomeActivity.java:100)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=12=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCallwC8FyV4pyjrzrYL5U0mlYiviZw.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6819)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
没有搜索到城市时(EditText
为空)。
所以我试图停止对此负责的异常,并在搜索 unavailable/no 城市时写一个 toast/message 告诉用户“no city found
”。
请问我该怎么做?到目前为止,我已经尝试添加:
Log.d(TAG, "No City found");
在我的
@Override
public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
t.printStackTrace();
}
HomeActivity中的方法,还是崩溃了
这是我的具体代码:
HomeActivity.java:
public class HomeActivity extends AppCompatActivity {
// User current time
TextView time_field;
ImageView Search;
EditText textfield;
ConstraintLayout constraintLayout;
// For scheduling background image change
public static int count=0;
int[] drawable =new int[]{R.drawable.dubai,R.drawable.central_bank_of_nigeria,R.drawable.eiffel_tower,R.drawable.hong_kong,R.drawable.statue_of_liberty};
Timer _t;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
time_field = findViewById(R.id.textView9);
Search = findViewById(R.id.imageView4);
textfield = findViewById(R.id.textfield);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
final NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
assert navHostFragment != null;
final NavController navController = navHostFragment.getNavController();
NavigationUI.setupWithNavController(bottomNavigationView, navController);
Search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getWeatherData(textfield.getText().toString().trim());
FirstFragment firstFragment = (FirstFragment) navHostFragment.getChildFragmentManager().getFragments().get(0);
firstFragment.getWeatherData(textfield.getText().toString().trim());
constraintLayout = findViewById(R.id.layout);
constraintLayout.setBackgroundResource(R.drawable.dubai);
_t = new Timer();
_t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// run on ui thread
runOnUiThread(() -> {
if (count < drawable.length) {
constraintLayout.setBackgroundResource(drawable[count]);
count = (count + 1) % drawable.length;
}
});
}
}, 5000, 5000);
}
private void getWeatherData(String name) {
ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
Call<Example> call = apiInterface.getWeatherData(name);
call.enqueue(new Callback<Example>() {
@Override
public void onResponse(@NotNull Call<Example> call, @NotNull Response<Example> response) {
assert response.body() != null;
time_field.setText("Last Updated:" + " " + response.body().getDt());
}
@Override
public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
t.printStackTrace();
}
});
}
});
}
}
FirstFragment.java:
public class FirstFragment extends Fragment {
// User current time, current temperature, current condition, sunrise, sunset, temperature, pressure, humidity, wind_speed, visibility, clouds
TextView current_temp, current_output, rise_time, set_time, temp_out, Press_out, Humid_out, Ws_out, Visi_out, Cloud_out;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public FirstFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment SecondFragment.
*/
// TODO: Rename and change types and number of parameters
public static FirstFragment newInstance(String param1, String param2) {
FirstFragment fragment = new FirstFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_first, container, false);
// For displaying weather data
current_temp = rootView.findViewById(R.id.textView10);
current_output = rootView.findViewById(R.id.textView11);
rise_time = rootView.findViewById(R.id.textView25);
set_time = rootView.findViewById(R.id.textView26);
temp_out = rootView.findViewById(R.id.textView28);
Press_out = rootView.findViewById(R.id.textView29);
Humid_out = rootView.findViewById(R.id.textView30);
Ws_out = rootView.findViewById(R.id.textView33);
Visi_out = rootView.findViewById(R.id.textView34);
Cloud_out = rootView.findViewById(R.id.textView35);
return rootView;
}
public void getWeatherData(String name) {
ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
Call<Example> call = apiInterface.getWeatherData(name);
call.enqueue(new Callback<Example>() {
@Override
public void onResponse(@NotNull Call<Example> call, @NotNull Response<Example> response) {
assert response.body() !=null;
current_temp.setText(response.body().getMain().getTemp() + " ℃");
current_output.setText(response.body().getWeather().get(0).getDescription());
rise_time.setText(response.body().getSys().getSunrise() + " ");
set_time.setText(response.body().getSys().getSunset() + " ");
temp_out.setText(response.body().getMain().getTemp() + " ℃");
Press_out.setText(response.body().getMain().getPressure() + " hpa");
Humid_out.setText(response.body().getMain().getHumidity() + " %");
Ws_out.setText(response.body().getWind().getSpeed() + " Km/h");
Visi_out.setText(response.body().getVisibility() + " m");
Cloud_out.setText(response.body().getClouds().getAll()+ " %");
}
@Override
public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
t.printStackTrace();
}
});
}
}
编辑
Example.java:
public class Example {
@SerializedName("coord")
private Coord coord;
@SerializedName("weather")
private List<Weather> weather = null;
@SerializedName("base")
private String base;
@SerializedName("main")
private Main main;
@SerializedName("visibility")
private Integer visibility;
@SerializedName("wind")
private Wind wind;
@SerializedName("clouds")
private Clouds clouds;
@SerializedName("dt")
@Expose
private PrettyTime dt;
@SerializedName("sys")
private Sys sys;
@SerializedName("timezone")
private Integer timezone;
@SerializedName("id")
private Integer id;
@SerializedName("name")
private String name;
@SerializedName("cod")
private Integer cod;
public Coord getCoord() {
return coord;
}
public void setCoord(Coord coord) {
this.coord = coord;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public Main getMain() {
return main;
}
public void setMain(Main main) {
this.main = main;
}
public Integer getVisibility() {
return visibility;
}
public void setVisibility(Integer visibility) {
this.visibility = visibility;
}
public Wind getWind() {
return wind;
}
public void setWind(Wind wind) {
this.wind = wind;
}
public Clouds getClouds() {
return clouds;
}
public void setClouds(Clouds clouds) {
this.clouds = clouds;
}
public PrettyTime getDt() {
return dt;
}
public void setDt(PrettyTime dt) {
this.dt = dt;
}
public Sys getSys() {
return sys;
}
public void setSys(Sys sys) {
this.sys = sys;
}
public Integer getTimezone() {
return timezone;
}
public void setTimezone(Integer timezone) {
this.timezone = timezone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getCod() {
return cod;
}
public void setCod(Integer cod) {
this.cod = cod;
}
public class Clouds {
@SerializedName("all")
private Integer all;
public Integer getAll() {
return all;
}
public void setAll(Integer all) {
this.all = all;
}
}
public class Coord {
@SerializedName("lon")
private Double lon;
@SerializedName("lat")
private Double lat;
public Double getLon() {
return lon;
}
public void setLon(Double lon) {
this.lon = lon;
}
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
}
public class Main {
@SerializedName("temp")
private Double temp;
@SerializedName("feels_like")
private Double feelsLike;
@SerializedName("temp_min")
private Double tempMin;
@SerializedName("temp_max")
private Double tempMax;
@SerializedName("pressure")
private Integer pressure;
@SerializedName("humidity")
private Integer humidity;
public Double getTemp() {
return temp;
}
public void setTemp(Double temp) {
this.temp = temp;
}
public Double getFeelsLike() {
return feelsLike;
}
public void setFeelsLike(Double feelsLike) {
this.feelsLike = feelsLike;
}
public Double getTempMin() {
return tempMin;
}
public void setTempMin(Double tempMin) {
this.tempMin = tempMin;
}
public Double getTempMax() {
return tempMax;
}
public void setTempMax(Double tempMax) {
this.tempMax = tempMax;
}
public Integer getPressure() {
return pressure;
}
public void setPressure(Integer pressure) {
this.pressure = pressure;
}
public Integer getHumidity() {
return humidity;
}
public void setHumidity(Integer humidity) {
this.humidity = humidity;
}
}
public class Sys {
@SerializedName("type")
private Integer type;
@SerializedName("id")
private Integer id;
@SerializedName("country")
private String country;
@SerializedName("sunrise")
@Expose
private PrettyTime sunrise;
@SerializedName("sunset")
@Expose
private PrettyTime sunset;
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public PrettyTime getSunrise() {
return sunrise;
}
public void setSunrise(PrettyTime sunrise) {
this.sunrise = sunrise;
}
public PrettyTime getSunset() {
return sunset;
}
public void setSunset(PrettyTime sunset) {
this.sunset = sunset;
}
}
public class Weather {
@SerializedName("id")
private Integer id;
@SerializedName("main")
private String main;
@SerializedName("description")
private String description;
@SerializedName("icon")
private String icon;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getMain() {
return main;
}
public void setMain(String main) {
this.main = main;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
}
public class Wind {
@SerializedName("speed")
private Double speed;
@SerializedName("deg")
private Integer deg;
@SerializedName("gust")
private Double gust;
public Double getSpeed() {
return speed;
}
public void setSpeed(Double speed) {
this.speed = speed;
}
public Integer getDeg() {
return deg;
}
public void setDeg(Integer deg) {
this.deg = deg;
}
public Double getGust() {
return gust;
}
public void setGust(Double gust) {
this.gust = gust;
}
}
}
根据日志,您得到了带有正文的成功响应,但是 getMain
returns null
.
您可以通过在 getMain 周围添加一些空检查来防止这种情况。请确保在 api 文档中检查 null 的可能性。
public void onResponse(@NotNull Call<Example> call, @NotNull Response<Example> response) {
assert response.body() !=null;
if(response.body().getMain()==null && response.body().getWeather()!=null && all other field!=null){
yourErrorTextview.setText("No City found");
allOtherField.setText();
}
else if(response.body().getMain()!=null && response.body().getWeather()!=null && all other field!=null){
current_temp.setText(response.body().getMain().getTemp() + " ℃");
allOtherField.setText();
}}
您可以在捕获异常时使用 try catch 块,您可以吐司消息 city not found 这样您的应用就不会崩溃。
正如OP所说I just need the best method to handle the exceptions
让我为您的情况举两个例子,以避免崩溃并为 Activity 和 Fragment 显示 toast。
- try/catch
更新您的 Activity onResponse
,如下所示。
public void onResponse(Call<Example> call, Response<Example> response) {
try {
time_field.setText("Last Updated:" + " " + response.body().getDt());
} catch (Exception e) {
time_field.setText("Last Updated: Unknown");
Log.e("TAG", "No City found");
Toast.makeText(HomeActivity.this, "No City found", Toast.LENGTH_SHORT).show();
}
}
像下面这样更新你的片段`onResponse
public void onResponse(Call<Example> call, Response<Example> response) {
try {
current_temp.setText(response.body().getMain().getTemp() + " ℃");
current_output.setText(response.body().getWeather().get(0).getDescription());
rise_time.setText(response.body().getSys().getSunrise() + " ");
set_time.setText(response.body().getSys().getSunset() + " ");
temp_out.setText(response.body().getMain().getTemp() + " ℃");
Press_out.setText(response.body().getMain().getPressure() + " hpa");
Humid_out.setText(response.body().getMain().getHumidity() + " %");
Ws_out.setText(response.body().getWind().getSpeed() + " Km/h");
Visi_out.setText(response.body().getVisibility() + " m");
Cloud_out.setText(response.body().getClouds().getAll() + " %");
} catch (Exception e) {
Log.e("TAG", "No City found");
Toast.makeText(getActivity(), "No City found", Toast.LENGTH_SHORT).show();
}
}
- 空检查
更新您的 Activity onResponse
,如下所示。
public void onResponse(Call<Example> call, Response<Example> response) {
if (response.isSuccessful() && response.body() != null) {
time_field.setText("Last Updated:" + " " + response.body().getDt());
} else {
time_field.setText("Last Updated: Unknown");
Log.e("TAG", "No City found");
Toast.makeText(HomeActivity.this, "No City found", Toast.LENGTH_SHORT).show();
}
}
更新您的片段 onResponse
如下所示
public void onResponse(Call<Example> call, Response<Example> response) {
if (response.isSuccessful() && response.body() != null) {
current_temp.setText(response.body().getMain().getTemp() + " ℃");
current_output.setText(response.body().getWeather().get(0).getDescription());
rise_time.setText(response.body().getSys().getSunrise() + " ");
set_time.setText(response.body().getSys().getSunset() + " ");
temp_out.setText(response.body().getMain().getTemp() + " ℃");
Press_out.setText(response.body().getMain().getPressure() + " hpa");
Humid_out.setText(response.body().getMain().getHumidity() + " %");
Ws_out.setText(response.body().getWind().getSpeed() + " Km/h");
Visi_out.setText(response.body().getVisibility() + " m");
Cloud_out.setText(response.body().getClouds().getAll() + " %");
} else {
Log.e("TAG", "No City found");
Toast.makeText(getActivity(), "No City found", Toast.LENGTH_SHORT).show();
}
}
注意: 有一些空间可以改进您的代码并设计得更好,比如避免在搜索点击时额外调用 API,一个来自Activity 和片段中的另一个。但是所有这些建议都超出了这个问题的范围,所以我会坚持 I just need the best method to handle the exceptions
.
的 OP 请求
我有一个天气应用程序,可以搜索在 EditText
上输入的任何城市,而且效果很好。
但问题是,每当我搜索不可用的城市或将 EditText
留空并单击搜索按钮时,应用程序崩溃并在我的 phone 上报告 "(my app) has stopped"
(这仅发生在我search an unavailable city/no city is searched), 它可以正确搜索任何有效的城市。
这是我的 Logcat 显示的内容(仅当搜索到不可用的城市时):
java.lang.NullPointerException: Attempt to invoke virtual method 'com.viz.lightweatherforecast.Retrofit.Example$Main com.viz.lightweatherforecast.Retrofit.Example.getMain()' on a null object reference
at com.viz.lightweatherforecast.FirstFragment.onResponse(FirstFragment.java:104)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=11=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCallwC8FyV4pyjrzrYL5U0mlYiviZw.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6819)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
和
java.lang.NullPointerException: Attempt to invoke virtual method 'com.viz.lightweatherforecast.first.PrettyTime com.viz.lightweatherforecast.Retrofit.Example.getDt()' on a null object reference
at com.viz.lightweatherforecast.Activity.HomeActivity.onResponse(HomeActivity.java:100)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=12=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCallwC8FyV4pyjrzrYL5U0mlYiviZw.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6819)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
没有搜索到城市时(EditText
为空)。
所以我试图停止对此负责的异常,并在搜索 unavailable/no 城市时写一个 toast/message 告诉用户“no city found
”。
请问我该怎么做?到目前为止,我已经尝试添加:
Log.d(TAG, "No City found");
在我的
@Override
public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
t.printStackTrace();
}
HomeActivity中的方法,还是崩溃了
这是我的具体代码:
HomeActivity.java:
public class HomeActivity extends AppCompatActivity {
// User current time
TextView time_field;
ImageView Search;
EditText textfield;
ConstraintLayout constraintLayout;
// For scheduling background image change
public static int count=0;
int[] drawable =new int[]{R.drawable.dubai,R.drawable.central_bank_of_nigeria,R.drawable.eiffel_tower,R.drawable.hong_kong,R.drawable.statue_of_liberty};
Timer _t;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
time_field = findViewById(R.id.textView9);
Search = findViewById(R.id.imageView4);
textfield = findViewById(R.id.textfield);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
final NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
assert navHostFragment != null;
final NavController navController = navHostFragment.getNavController();
NavigationUI.setupWithNavController(bottomNavigationView, navController);
Search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getWeatherData(textfield.getText().toString().trim());
FirstFragment firstFragment = (FirstFragment) navHostFragment.getChildFragmentManager().getFragments().get(0);
firstFragment.getWeatherData(textfield.getText().toString().trim());
constraintLayout = findViewById(R.id.layout);
constraintLayout.setBackgroundResource(R.drawable.dubai);
_t = new Timer();
_t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// run on ui thread
runOnUiThread(() -> {
if (count < drawable.length) {
constraintLayout.setBackgroundResource(drawable[count]);
count = (count + 1) % drawable.length;
}
});
}
}, 5000, 5000);
}
private void getWeatherData(String name) {
ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
Call<Example> call = apiInterface.getWeatherData(name);
call.enqueue(new Callback<Example>() {
@Override
public void onResponse(@NotNull Call<Example> call, @NotNull Response<Example> response) {
assert response.body() != null;
time_field.setText("Last Updated:" + " " + response.body().getDt());
}
@Override
public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
t.printStackTrace();
}
});
}
});
}
}
FirstFragment.java:
public class FirstFragment extends Fragment {
// User current time, current temperature, current condition, sunrise, sunset, temperature, pressure, humidity, wind_speed, visibility, clouds
TextView current_temp, current_output, rise_time, set_time, temp_out, Press_out, Humid_out, Ws_out, Visi_out, Cloud_out;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public FirstFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment SecondFragment.
*/
// TODO: Rename and change types and number of parameters
public static FirstFragment newInstance(String param1, String param2) {
FirstFragment fragment = new FirstFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_first, container, false);
// For displaying weather data
current_temp = rootView.findViewById(R.id.textView10);
current_output = rootView.findViewById(R.id.textView11);
rise_time = rootView.findViewById(R.id.textView25);
set_time = rootView.findViewById(R.id.textView26);
temp_out = rootView.findViewById(R.id.textView28);
Press_out = rootView.findViewById(R.id.textView29);
Humid_out = rootView.findViewById(R.id.textView30);
Ws_out = rootView.findViewById(R.id.textView33);
Visi_out = rootView.findViewById(R.id.textView34);
Cloud_out = rootView.findViewById(R.id.textView35);
return rootView;
}
public void getWeatherData(String name) {
ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
Call<Example> call = apiInterface.getWeatherData(name);
call.enqueue(new Callback<Example>() {
@Override
public void onResponse(@NotNull Call<Example> call, @NotNull Response<Example> response) {
assert response.body() !=null;
current_temp.setText(response.body().getMain().getTemp() + " ℃");
current_output.setText(response.body().getWeather().get(0).getDescription());
rise_time.setText(response.body().getSys().getSunrise() + " ");
set_time.setText(response.body().getSys().getSunset() + " ");
temp_out.setText(response.body().getMain().getTemp() + " ℃");
Press_out.setText(response.body().getMain().getPressure() + " hpa");
Humid_out.setText(response.body().getMain().getHumidity() + " %");
Ws_out.setText(response.body().getWind().getSpeed() + " Km/h");
Visi_out.setText(response.body().getVisibility() + " m");
Cloud_out.setText(response.body().getClouds().getAll()+ " %");
}
@Override
public void onFailure(@NotNull Call<Example> call, @NotNull Throwable t) {
t.printStackTrace();
}
});
}
}
编辑
Example.java:
public class Example {
@SerializedName("coord")
private Coord coord;
@SerializedName("weather")
private List<Weather> weather = null;
@SerializedName("base")
private String base;
@SerializedName("main")
private Main main;
@SerializedName("visibility")
private Integer visibility;
@SerializedName("wind")
private Wind wind;
@SerializedName("clouds")
private Clouds clouds;
@SerializedName("dt")
@Expose
private PrettyTime dt;
@SerializedName("sys")
private Sys sys;
@SerializedName("timezone")
private Integer timezone;
@SerializedName("id")
private Integer id;
@SerializedName("name")
private String name;
@SerializedName("cod")
private Integer cod;
public Coord getCoord() {
return coord;
}
public void setCoord(Coord coord) {
this.coord = coord;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public Main getMain() {
return main;
}
public void setMain(Main main) {
this.main = main;
}
public Integer getVisibility() {
return visibility;
}
public void setVisibility(Integer visibility) {
this.visibility = visibility;
}
public Wind getWind() {
return wind;
}
public void setWind(Wind wind) {
this.wind = wind;
}
public Clouds getClouds() {
return clouds;
}
public void setClouds(Clouds clouds) {
this.clouds = clouds;
}
public PrettyTime getDt() {
return dt;
}
public void setDt(PrettyTime dt) {
this.dt = dt;
}
public Sys getSys() {
return sys;
}
public void setSys(Sys sys) {
this.sys = sys;
}
public Integer getTimezone() {
return timezone;
}
public void setTimezone(Integer timezone) {
this.timezone = timezone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getCod() {
return cod;
}
public void setCod(Integer cod) {
this.cod = cod;
}
public class Clouds {
@SerializedName("all")
private Integer all;
public Integer getAll() {
return all;
}
public void setAll(Integer all) {
this.all = all;
}
}
public class Coord {
@SerializedName("lon")
private Double lon;
@SerializedName("lat")
private Double lat;
public Double getLon() {
return lon;
}
public void setLon(Double lon) {
this.lon = lon;
}
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
}
public class Main {
@SerializedName("temp")
private Double temp;
@SerializedName("feels_like")
private Double feelsLike;
@SerializedName("temp_min")
private Double tempMin;
@SerializedName("temp_max")
private Double tempMax;
@SerializedName("pressure")
private Integer pressure;
@SerializedName("humidity")
private Integer humidity;
public Double getTemp() {
return temp;
}
public void setTemp(Double temp) {
this.temp = temp;
}
public Double getFeelsLike() {
return feelsLike;
}
public void setFeelsLike(Double feelsLike) {
this.feelsLike = feelsLike;
}
public Double getTempMin() {
return tempMin;
}
public void setTempMin(Double tempMin) {
this.tempMin = tempMin;
}
public Double getTempMax() {
return tempMax;
}
public void setTempMax(Double tempMax) {
this.tempMax = tempMax;
}
public Integer getPressure() {
return pressure;
}
public void setPressure(Integer pressure) {
this.pressure = pressure;
}
public Integer getHumidity() {
return humidity;
}
public void setHumidity(Integer humidity) {
this.humidity = humidity;
}
}
public class Sys {
@SerializedName("type")
private Integer type;
@SerializedName("id")
private Integer id;
@SerializedName("country")
private String country;
@SerializedName("sunrise")
@Expose
private PrettyTime sunrise;
@SerializedName("sunset")
@Expose
private PrettyTime sunset;
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public PrettyTime getSunrise() {
return sunrise;
}
public void setSunrise(PrettyTime sunrise) {
this.sunrise = sunrise;
}
public PrettyTime getSunset() {
return sunset;
}
public void setSunset(PrettyTime sunset) {
this.sunset = sunset;
}
}
public class Weather {
@SerializedName("id")
private Integer id;
@SerializedName("main")
private String main;
@SerializedName("description")
private String description;
@SerializedName("icon")
private String icon;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getMain() {
return main;
}
public void setMain(String main) {
this.main = main;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
}
public class Wind {
@SerializedName("speed")
private Double speed;
@SerializedName("deg")
private Integer deg;
@SerializedName("gust")
private Double gust;
public Double getSpeed() {
return speed;
}
public void setSpeed(Double speed) {
this.speed = speed;
}
public Integer getDeg() {
return deg;
}
public void setDeg(Integer deg) {
this.deg = deg;
}
public Double getGust() {
return gust;
}
public void setGust(Double gust) {
this.gust = gust;
}
}
}
根据日志,您得到了带有正文的成功响应,但是 getMain
returns null
.
您可以通过在 getMain 周围添加一些空检查来防止这种情况。请确保在 api 文档中检查 null 的可能性。
public void onResponse(@NotNull Call<Example> call, @NotNull Response<Example> response) {
assert response.body() !=null;
if(response.body().getMain()==null && response.body().getWeather()!=null && all other field!=null){
yourErrorTextview.setText("No City found");
allOtherField.setText();
}
else if(response.body().getMain()!=null && response.body().getWeather()!=null && all other field!=null){
current_temp.setText(response.body().getMain().getTemp() + " ℃");
allOtherField.setText();
}}
您可以在捕获异常时使用 try catch 块,您可以吐司消息 city not found 这样您的应用就不会崩溃。
正如OP所说I just need the best method to handle the exceptions
让我为您的情况举两个例子,以避免崩溃并为 Activity 和 Fragment 显示 toast。
- try/catch
更新您的 Activity onResponse
,如下所示。
public void onResponse(Call<Example> call, Response<Example> response) {
try {
time_field.setText("Last Updated:" + " " + response.body().getDt());
} catch (Exception e) {
time_field.setText("Last Updated: Unknown");
Log.e("TAG", "No City found");
Toast.makeText(HomeActivity.this, "No City found", Toast.LENGTH_SHORT).show();
}
}
像下面这样更新你的片段`onResponse
public void onResponse(Call<Example> call, Response<Example> response) {
try {
current_temp.setText(response.body().getMain().getTemp() + " ℃");
current_output.setText(response.body().getWeather().get(0).getDescription());
rise_time.setText(response.body().getSys().getSunrise() + " ");
set_time.setText(response.body().getSys().getSunset() + " ");
temp_out.setText(response.body().getMain().getTemp() + " ℃");
Press_out.setText(response.body().getMain().getPressure() + " hpa");
Humid_out.setText(response.body().getMain().getHumidity() + " %");
Ws_out.setText(response.body().getWind().getSpeed() + " Km/h");
Visi_out.setText(response.body().getVisibility() + " m");
Cloud_out.setText(response.body().getClouds().getAll() + " %");
} catch (Exception e) {
Log.e("TAG", "No City found");
Toast.makeText(getActivity(), "No City found", Toast.LENGTH_SHORT).show();
}
}
- 空检查
更新您的 Activity onResponse
,如下所示。
public void onResponse(Call<Example> call, Response<Example> response) {
if (response.isSuccessful() && response.body() != null) {
time_field.setText("Last Updated:" + " " + response.body().getDt());
} else {
time_field.setText("Last Updated: Unknown");
Log.e("TAG", "No City found");
Toast.makeText(HomeActivity.this, "No City found", Toast.LENGTH_SHORT).show();
}
}
更新您的片段 onResponse
如下所示
public void onResponse(Call<Example> call, Response<Example> response) {
if (response.isSuccessful() && response.body() != null) {
current_temp.setText(response.body().getMain().getTemp() + " ℃");
current_output.setText(response.body().getWeather().get(0).getDescription());
rise_time.setText(response.body().getSys().getSunrise() + " ");
set_time.setText(response.body().getSys().getSunset() + " ");
temp_out.setText(response.body().getMain().getTemp() + " ℃");
Press_out.setText(response.body().getMain().getPressure() + " hpa");
Humid_out.setText(response.body().getMain().getHumidity() + " %");
Ws_out.setText(response.body().getWind().getSpeed() + " Km/h");
Visi_out.setText(response.body().getVisibility() + " m");
Cloud_out.setText(response.body().getClouds().getAll() + " %");
} else {
Log.e("TAG", "No City found");
Toast.makeText(getActivity(), "No City found", Toast.LENGTH_SHORT).show();
}
}
注意: 有一些空间可以改进您的代码并设计得更好,比如避免在搜索点击时额外调用 API,一个来自Activity 和片段中的另一个。但是所有这些建议都超出了这个问题的范围,所以我会坚持 I just need the best method to handle the exceptions
.