I have a Weather app that searches for any city typed on the EditText and it works very well.
But the problem is that the app crashes and reports "(my app) has stopped" on my phone whenever I search for an unavailable city or I leave the EditText empty and click the search button(this only happens when I search an unavailable city/no city is searched), It can search any valid city correctly.
Here's what my Logcat displays(only when an unavailable city is searched):
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$1.onResponse(FirstFragment.java:104)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$3wC8FyV4pyjrzrYL5U0mlYiviZw.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)
and
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$1$2.onResponse(HomeActivity.java:100)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$3wC8FyV4pyjrzrYL5U0mlYiviZw.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)
when no city is searched(EditText is empty).
So I'm trying to stop the exception responsible for that and as well write a toast/message to tell the user "no city found" when an unavailable/no city is searched.
Please how do I do that? So far, I've tried adding:
Log.d(TAG, "No City found");
on my
#Override
public void onFailure(#NotNull Call<Example> call, #NotNull Throwable t) {
t.printStackTrace();
}
the method in HomeActivity, but it still crashes.
Here's my specific code:
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();
}
});
}
}
EDIT
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;
}
}
}
As OP said I just need the best method to handle the exceptions
Let me give two examples for your case to avoid the crash and show toast for both Activity and Fragment.
try/catch
Update your Activity onResponse like below.
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();
}
}
Update your Fragment `onResponse like below
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();
}
}
null check
Update your Activity onResponse like below.
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();
}
}
Update your Fragment onResponse like below
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();
}
}
Note: There is a bit of scope to improve your code and design a better, like to avoid an extra call to API on search click, one from Activity and another in the fragment. But all those suggestion will be out of the scope of this question, So I will stick to OP request which is I just need the best method to handle the exceptions.
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();
}}
According to the log you get a success response with a body but getMain returns null.
You can prevent this by adding some null checks around getMain. Make sure to check the possibility of null in the api documentation.
You can use try catch block in catch you are getting exception you can toast message city not found so your app will not crash.
Related
This question already has an answer here:
Get Local timezone using City Name in Java
(1 answer)
Closed 1 year ago.
My weather App displays Datetime(last updated), Sunrise, and Sunset data from OpenWeatherMap in the form of milliseconds(i.e 1620792785).
I'm trying to convert it to a real-time format (i.e hh:mm a).
I tried using this code for dt in my example class:
public String getPrettyDate() {
SimpleDateFormat HMM = new SimpleDateFormat("hh:mm a", Locale.US);
final Date date = new Date(dt*1000);
return HMM.format(date);
}
It converted the time well, but it didn't display the data accurately(i.e when it was 3pm here, it showed 9pm).
I as well checked this site for a similar issue but found none.
So I want to:
Convert the dt accurately
Convert Sunrise and Sunset time accurately
using the right codes and classes.
Edit:
My app can search for any city, so I'm not getting for a particular timezone but for all cities
My JSON Response:
{
"coord":{
"lon":-0.1257,
"lat":51.5085
},
"weather":[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04d"
}
],
"base":"stations",
"main":{
"temp":289.16,
"feels_like":288.07,
"temp_min":286.87,
"temp_max":290.76,
"pressure":1009,
"humidity":48
},
"visibility":10000,
"wind":{
"speed":0.45,
"deg":109,
"gust":2.68
},
"clouds":{
"all":100
},
"dt":1620830862,
"sys":{
"type":2,
"id":2019646,
"country":"GB",
"sunrise":1620792785,
"sunset":1620848444
},
"timezone":3600,
"id":2643743,
"name":"London",
"cod":200
}
My Example class:
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")
private Integer 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 Integer getDt() {
return dt;
}
public void setDt(Integer 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")
private Integer sunrise;
#SerializedName("sunset")
private Integer 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 Integer getSunrise() {
return sunrise;
}
public void setSunrise(Integer sunrise) {
this.sunrise = sunrise;
}
public Integer getSunset() {
return sunset;
}
public void setSunset(Integer 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;
}
}
public String getPrettyDate() {
SimpleDateFormat HMM = new SimpleDateFormat("hh:mm a", Locale.US);
final Date date = new Date(dt*1000);
return HMM.format(date);
}
}
My Activity class(Where i called dt):
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().getPrettyDate());
}
#Override
public void onFailure(#NotNull Call<Example> call, #NotNull Throwable t) {
t.printStackTrace();
}
});
}
});
}
}
My FirstFragment class(Where i called sunrise and sunset):
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();
}
});
}
}
tl;dr
Instant // Represents a moment, a point on the timeline, as seen in UTC (an offset of zero), with resolution of nanoseconds.
.ofEpochSecond( 1_620_792_785L ) // Returns a `Instant`.
.atZone(
ZoneId.of( "Africa/Tunis" ) // Returns a `ZoneId`.
) // Returns a `ZonedDateTime`.
.format(
DateTimeFormatter
.ofLocalizedTime( FormatStyle.MEDIUM ) // Returns a `DateTimeFormatter`.
.withLocale( Locale.US ) ; // Returns another `DateTimeFormatter` rather than altering the original, per immutable objects pattern.
) // Returns a `String`.
Details
This has been covered many times on Stack Overflow. So I’ll be brief. Search to learn more.
in the form of milliseconds(i.e 1620792785)
No, that looks like a count of whole seconds, not milliseconds, since 1970-01-01T00:00Z.
Never use the terrible legacy date-time classes. Use only java.time classes.
Parse your count of whole seconds since first moment of 1970 UTC as a Instant.
Instant instant = Instant.ofEpochSecond( 1_620_792_785L ) ;
To see that same moment using the wall-clock time kept by the people of a particular region, apply a time zone (ZoneId) to get a ZonedDateTime.
Specify a real time zone name in format of Continent/Region. Apparently your zone is six hours behind UTC. Several time zones currently share that offset-from-UTC. I arbitrarily chose one of them, America/Managua. So replace with your particular time zone.
ZoneId z = ZoneId.of( "America/Managua" ) ;
ZonedDateTime z = instant.atZone( z ) ;
To generate text representing that value, use a DateTimeFormatter object. Such an object can automatically localize by calling DateTimeFormatter.ofLocalizedTime.
Android 26 and later has java.time built-in. For earlier Android, most of the java.time functionality is available through “API desugaring” in the latest tooling.
Any city
After editing, you changed the nature of your Question to ask about how to change time zones according to any arbitrary city name the user may enter.
No magic solution there. You must translate from the user's entered city to a particular time zone name. I know of no library to do that. Mapping from a city name is tricky, as city names are far from unique For example, Paris France, Paris Texas. And many Springfield towns in the United States.
Usually an app asks the user to select their desired time zone. You can prompt for continent to narrow down the list.
To get a list of all time zones currently known at runtime by calling:
Set< String > timeZoneNames = ZoneId.getAvailableZoneIds() ;
See the excellent Answer by Ole V.V. to the original of your now-duplicate Question.
I'm working on a weather app, and currently on the part of developing a search city button. My major aim is to enable the button search and display any city data typed on the edittext.
I have created an edittext and search button, I have also as well connected them with my retrofit parsed classes.
I followed this youtube tutorial for some help https://www.youtube.com/watch?v=SrVY2la7lCI
and also got a little help from this post How to get "weather" object data from OpenWeatherMap API Using Retrofit. They were all able to display their weather data for any searched city.
But if i use this address(that they used) on my ApiInterface weather?appid=9c547bfc852923c3b30d0d62a5ae35e8&units=metric, it returns the following error:
java.lang.NullPointerException: Attempt to invoke virtual method 'com.viz.realtimeweather.Retrofit.Main com.com.viz.realtimeweather.Retrofit.Example.getMain()' on a null object reference
at com.viz.realtimeweather.FirstFragment$1.onResponse(FirstFragment.java:109)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$3wC8FyV4pyjrzrYL5U0mlYiviZw.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)
and displays no data.
Then when I added a query to it. i.e q=london, it returned no error but still displays no data. I feel the problem lies somewhere else but I don't know exactly where. Also, that cannot be a solution because I need to enable the app to search any location, not just a particular city.
So far, I have:
Checked in and out of all my parsed networking classes for mistakes but found none
Checked both my ApiClient and ApiInterface class for any wrong network address but found none
Added q=london on my ApiInterface address, but it doesn't display any data nor search another city data
Checked this site for any related issue on the weather but found none.
Using https://stackoverflow.com/help/minimal-reproducible-example, I will share my code for help.
I am using OpenWeatherMap API Format:
{
"coord":{
"lon":-122.08,
"lat":37.39
},
"weather":[
{
"id":800,
"main":"Clear",
"description":"clear sky",
"icon":"01d"
}
],
"base":"stations",
"main":{
"temp":282.55,
"feels_like":281.86,
"temp_min":280.37,
"temp_max":284.26,
"pressure":1023,
"humidity":100
},
"visibility":16093,
"wind":{
"speed":1.5,
"deg":350
},
"clouds":{
"all":1
},
"dt":1560350645,
"sys":{
"type":1,
"id":5122,
"message":0.0139,
"country":"US",
"sunrise":1560343627,
"sunset":1560396563
},
"timezone":-25200,
"id":420006353,
"name":"Mountain View",
"cod":200
}
My JSON response(when I don't add a query):
{
"cod":"400",
"message":"Nothing to geocode"
}
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());
int id = Objects.requireNonNull(navController.getCurrentDestination()).getId();
navController.popBackStack();
navController.navigate(id);
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(String.valueOf(response.body().getDt()));
}
#Override
public void onFailure(#NotNull Call<Example> call, #NotNull Throwable t) {
t.printStackTrace();
}
});
}
});
}
}
First Fragment.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);
// Use activity data
FragmentActivity fa = getActivity();
assert fa != null;
EditText textfield = fa.findViewById(R.id.textfield);
getWeatherData(textfield.getText().toString().trim());
return rootView;
}
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;
current_temp.setText(response.body().getMain().getTemp() + " ℃");
current_output.setText(response.body().getWeatherList().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();
}
});
}
}
ApiClient.java:
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(){ //creating object
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl("http://api.openweathermap.org/data/2.5/")
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
ApiInterface.java:
public interface ApiInterface {
#GET("weather?appid=9c547bfc852923c3b30d0d62a5ae35e8&units=metric")
Call<Example> getWeatherData(#Query("q") String name);
}
Example.java:
public class Example {
#SerializedName("main")
private Main main;
#SerializedName("weather")
private List<Weather> weatherList;
#SerializedName("visibility")
private Visibility visibility;
#SerializedName("wind")
private Wind wind;
#SerializedName("clouds")
private Clouds clouds;
#SerializedName("dt")
private Dt dt;
#SerializedName("sys")
private Sys sys;
#SerializedName("name")
private Name name;
public Main getMain() {
return main;
}
public void setMain(Main main) {
this.main = main;
}
public List<Weather> getWeatherList() {
return weatherList;
}
public void setWeatherList(List<Weather> weatherList) {
this.weatherList = weatherList;
}
public Visibility getVisibility() {
return visibility;
}
public void setVisibility(Visibility 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 Dt getDt() {
return dt;
}
public void setDt(Dt dt) {
this.dt = dt;
}
public Sys getSys() {
return sys;
}
public void setSys(Sys sys) {
this.sys = sys;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
}
Main.java:
public class Main {
#SerializedName("temp")
String temp;
#SerializedName("pressure")
String pressure;
#SerializedName("humidity")
String humidity;
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getPressure() {
return pressure;
}
public void setPressure(String pressure) {
this.pressure = pressure;
}
public String getHumidity() {
return humidity;
}
public void setHumidity(String humidity) {
this.humidity = humidity;
}
}
EDIT
dt.java:
public class Dt {
#SerializedName("dt")
#Expose
private PrettyTime dt;
public PrettyTime getDt() {
return dt;
}
public void setDt(PrettyTime dt) {
this.dt = dt;
}
}
The problem is that you're receiving a 400 Bad Request from calling http://api.openweathermap.org/data/2.5/weather?appid=9c547bfc852923c3b30d0d62a5ae35e8&units=metric
or even
http://api.openweathermap.org/data/2.5/weather?appid=9c547bfc852923c3b30d0d62a5ae35e8&units=metric&q=
Anything that doesn't fall into the range [200; 300[ retrofit considers an error and will not give you a body(), hence the null pointer because body() is null. On the other hand, errorBody() will have the string you want.
To consume the error body you can simply do errorBody().string() but be careful because it behaves as a stream and can only be consumed once.
As to why your request is falling, that seems to be because you're lacking some query parameters to allow the open weather api to return weather for a given coordinate. Adding a simple q=lisbon seems to solve the issue:
http://api.openweathermap.org/data/2.5/weather?appid=9c547bfc852923c3b30d0d62a5ae35e8&units=metric&q=lisbon
will return 200 OK and retrofit body() method will return something. Maybe you're sending it empty?
After a discussion and also from my comments to the question the model mapping the JSON response was not correct and all that was required was to map the response correctly to the Java model.
I'm new to Retrofit, I have an activity hosting 3 fragments for a weather app. My FirstFragment is where the
current weather data will be displayed using OpenWeatherMap One call API https://openweathermap.org/api/one-call-api. I noticed that retrofit request calls cannot be made on the fragment class, so
I tried using my Activity class and everything worked properly except these following lines:
call.enqueue(new Callback<WeatherResponse>() {
#Override
public void onResponse(#NonNull Call < WeatherResponse > call, #NonNull Response < WeatherResponse > response) {
if (response.code() == 200) {
WeatherResponse weatherResponse = response.body();
assert weatherResponse != null;
time_zone.setText(response.body().getTimezone());
time_field.setText(response.body().getCurrent.getDt());
current_temp.setText(response.body().getCurrent().getTemp()+" ℃");
current_output.setText(response.body().getCurrent().getWeather().getDescription);
rise_time.setText(response.body().getCurrent().getSunrise()+" AM");
set_time.setText(response.body().getCurrent().getSunset()+" PM");
temp_out.setText(response.body().getCurrent().getTemp()+" ℃");
Press_out.setText(response.body().getCurrent().getPressure()+" hpa");
Humid_out.setText(response.body().getCurrent().getHumidity()+" %");
Ws_out.setText(response.body().getCurrent).getWind_speed()+" Km/h");
Visi_out.setText(response.body().getCurrent().getVisibility()+" m");
UV_out.setText(response.body().getCurrent().getUvi());
showing error Cannot resolve Symbol "response". What can be done to fix it, please?
My full code:
HomeActivity.java
public class HomeActivity extends AppCompatActivity {
public static String BaseUrl = "http://api.openweathermap.org/";
public static String AppId = "";
public static String lat = "9.0574";
public static String lon = "7.4898";
// User Timezone name, current time, current temperature, current condition, sunrise, sunset, temperature, pressure, humidity, wind_speed, visibility, UV Index
TextView time_zone, time_field, current_temp, current_output, rise_time, set_time, temp_out, Press_out, Humid_out, Ws_out, Visi_out, UV_out;
ConstraintLayout constraintLayout;
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_zone = findViewById(R.id.textView9);
time_field = findViewById(R.id.textView4);
current_temp = findViewById(R.id.textView10);
current_output = findViewById(R.id.textView11);
rise_time = findViewById(R.id.textView25);
set_time = findViewById(R.id.textView26);
temp_out = findViewById(R.id.textView28);
Press_out = findViewById(R.id.textView29);
Humid_out = findViewById(R.id.textView30);
Ws_out = findViewById(R.id.textView33);
Visi_out = findViewById(R.id.textView34);
UV_out = findViewById(R.id.textView35);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
NavController navController = Navigation.findNavController(this, R.id.fragment);
NavigationUI.setupWithNavController(bottomNavigationView, navController);
constraintLayout = findViewById(R.id.layout);
constraintLayout.setBackgroundResource(R.drawable.dubai);
_t = new Timer();
_t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() { // run on ui thread
#Override
public void run() {
if (count < drawable.length) {
constraintLayout.setBackgroundResource(drawable[count]);
count = (count + 1) % drawable.length;
}
}
});
}
}, 5000, 5000);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
WeatherService service = retrofit.create(WeatherService.class);
Call<WeatherResponse> call = service.getCurrentWeatherData(lat, lon, AppId);
call.enqueue(new Callback<WeatherResponse>() {
#Override
public void onResponse(#NonNull Call < WeatherResponse > call, #NonNull Response < WeatherResponse > response) {
if (response.code() == 200) {
WeatherResponse weatherResponse = response.body();
assert weatherResponse != null;
time_zone.setText(response.body().getTimezone());
time_field.setText(response.body().getCurrent.getDt());
current_temp.setText(response.body().getCurrent().getTemp()+" ℃");
current_output.setText(response.body().getCurrent().getWeather().getDescription);
rise_time.setText(response.body().getCurrent().getSunrise()+" AM");
set_time.setText(response.body().getCurrent().getSunset()+" PM");
temp_out.setText(response.body().getCurrent().getTemp()+" ℃");
Press_out.setText(response.body().getCurrent().getPressure()+" hpa");
Humid_out.setText(response.body().getCurrent().getHumidity()+" %");
Ws_out.setText(response.body().getCurrent).getWind_speed()+" Km/h");
Visi_out.setText(response.body().getCurrent().getVisibility()+" m");
UV_out.setText(response.body().getCurrent().getUvi());
}
}
}
}
WeatherService.java
public interface WeatherService {
#GET("data/2.5/weather?")
Call<WeatherResponse> getCurrentWeatherData(#Query("lat") String lat, #Query("lon") String lon, #Query("APPID") String app_id);
}
JSON Response:
{
"lat":9.08,
"lon":7.4,
"timezone":"Africa/Lagos",
"timezone_offset":3600,
"current":{
"dt":1609157237,
"sunrise":1609134244,
"sunset":1609175993,
"temp":305.15,
"feels_like":304.63,
"pressure":1012,
"humidity":29,
"dew_point":284.9,
"uvi":8.32,
"clouds":82,
"visibility":5000,
"wind_speed":1.5,
"wind_deg":200,
"weather":[
{
"id":721,
"main":"Haze",
"description":"haze",
"icon":"50d"
}
]
}
I converted my JSON to GSON using http://www.jsonschema2pojo.org/
Current.java:
public class Current {
#SerializedName("dt")
#Expose
private Integer dt;
#SerializedName("sunrise")
#Expose
private Integer sunrise;
#SerializedName("sunset")
#Expose
private Integer sunset;
#SerializedName("temp")
#Expose
private Double temp;
#SerializedName("feels_like")
#Expose
private Double feelsLike;
#SerializedName("pressure")
#Expose
private Integer pressure;
#SerializedName("humidity")
#Expose
private Integer humidity;
#SerializedName("dew_point")
#Expose
private Double dewPoint;
#SerializedName("uvi")
#Expose
private Double uvi;
#SerializedName("clouds")
#Expose
private Integer clouds;
#SerializedName("visibility")
#Expose
private Integer visibility;
#SerializedName("wind_speed")
#Expose
private Double windSpeed;
#SerializedName("wind_deg")
#Expose
private Integer windDeg;
#SerializedName("weather")
#Expose
private List<Weather> weather = null;
public Integer getDt() {
return dt;
}
public void setDt(Integer dt) {
this.dt = dt;
}
public Integer getSunrise() {
return sunrise;
}
public void setSunrise(Integer sunrise) {
this.sunrise = sunrise;
}
public Integer getSunset() {
return sunset;
}
public void setSunset(Integer sunset) {
this.sunset = sunset;
}
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 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 Double getDewPoint() {
return dewPoint;
}
public void setDewPoint(Double dewPoint) {
this.dewPoint = dewPoint;
}
public Double getUvi() {
return uvi;
}
public void setUvi(Double uvi) {
this.uvi = uvi;
}
public Integer getClouds() {
return clouds;
}
public void setClouds(Integer clouds) {
this.clouds = clouds;
}
public Integer getVisibility() {
return visibility;
}
public void setVisibility(Integer visibility) {
this.visibility = visibility;
}
public Double getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(Double windSpeed) {
this.windSpeed = windSpeed;
}
public Integer getWindDeg() {
return windDeg;
}
public void setWindDeg(Integer windDeg) {
this.windDeg = windDeg;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
}
Weather.java:
public class Weather {
#SerializedName("id")
#Expose
private Integer id;
#SerializedName("main")
#Expose
private String main;
#SerializedName("description")
#Expose
private String description;
#SerializedName("icon")
#Expose
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;
}
}
WeatherResponse.java:
public class WeatherResponse {
#SerializedName("lat")
#Expose
private Double lat;
#SerializedName("lon")
#Expose
private Double lon;
#SerializedName("timezone")
#Expose
private String timezone;
#SerializedName("timezone_offset")
#Expose
private Integer timezoneOffset;
#SerializedName("current")
#Expose
private Current current;
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
public Double getLon() {
return lon;
}
public void setLon(Double lon) {
this.lon = lon;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public Integer getTimezoneOffset() {
return timezoneOffset;
}
public void setTimezoneOffset(Integer timezoneOffset) {
this.timezoneOffset = timezoneOffset;
}
public Current getCurrent() {
return current;
}
public void setCurrent(Current current) {
this.current = current;
}
}
I also want to make my fragment class make use of the Activity data, how to do that, please?
This piece of code is outside of onCreate
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
WeatherService service = retrofit.create(WeatherService.class);
Call < WeatherResponse > call = service.getCurrentWeatherData(lat, lon, AppId);
// .... etc.
It needs to be inside a method; onCreate for example.
You can only have declarations and default assignments in the class body. Any other code must be within a method body.
You probably closed the brace of onCreate to early accidentally.
Note: This also explains why you get so many errors. You just have so many lines of code which are, to the compiler, totally out of place and thus marks everything as incorrect.
It might be rather something alike this:
#Override
public void onResponse(#NonNull Call<WeatherResponse> call, #NonNull Response <WeatherResponse> response) {
if (response.code() == 200) {
WeatherResponse weatherResponse = response.body();
time_zone.setText(weatherResponse.getTimezone());
time_field.setText(weatherResponse.getCurrent.getDt());
current_temp.setText(weatherResponse.getCurrent().getTemp()+" ℃");
rise_time.setText(weatherResponse.getCurrent().getSunrise()+" AM");
set_time.setText(weatherResponse.getCurrent().getSunset()+" PM");
temp_out.setText(weatherResponse.getCurrent().getTemp()+" ℃");
Press_out.setText(weatherResponse.getCurrent().getPressure()+" hpa");
Humid_out.setText(weatherResponse.getCurrent().getHumidity()+" %");
Ws_out.setText(weatherResponse.getCurrent).getWind_speed()+" Km/h");
Visi_out.setText(weatherResponse.getCurrent().getVisibility()+" m");
UV_out.setText(weatherResponse.getCurrent().getUvi());
}
}
Make sure to have class WeatherResponse and Current properly annotated.
That ? in the URL is useless.
make sure your enqueue() looks like this
call.enqueue(new Callback<WeatherResponse>() {
#Override
public void onResponse(#NotNull Call<WeatherResponse> call, #NotNull Response<WeatherResponse> response) {
if (response.body() != null) {
//...
}
}
#Override
public void onFailure(#NotNull Call<WeatherResponse> call, #NotNull Throwable t) {
t.printStackTrace();
}
});
This is an app that uses the Firebase database.
I have added all the data in firebase and now I need to retrieve it and display using listview.
I tried to fetch and show the data in my app from firebase but the app is stopping every time.
Take a look at the screenshot
This is the Country model class
Country.java
public class Country {
private String name;
private String total;
private String newCases;
private String totalDeaths;
private String newDeaths;
private String totalRecovered;
private String activeCases;
private String seriousCases;
public Country() {
}
public Country(String name, String total, String newCases, String totalDeaths, String newDeaths, String totalRecovered, String activeCases, String seriousCases) {
this.name = name;
this.total = total;
this.newCases = newCases;
this.totalDeaths = totalDeaths;
this.newDeaths = newDeaths;
this.totalRecovered = totalRecovered;
this.activeCases = activeCases;
this.seriousCases = seriousCases;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTotal() {
return total;
}
public void setTotal(String total) {
this.total = total;
}
public String getNewCases() {
return newCases;
}
public void setNewCases(String newCases) {
this.newCases = newCases;
}
public String getTotalDeaths() {
return totalDeaths;
}
public void setTotalDeaths(String totalDeaths) {
this.totalDeaths = totalDeaths;
}
public String getNewDeaths() {
return newDeaths;
}
public void setNewDeaths(String newDeaths) {
this.newDeaths = newDeaths;
}
public String getTotalRecovered() {
return totalRecovered;
}
public void setTotalRecovered(String totalRecovered) {
this.totalRecovered = totalRecovered;
}
public String getActiveCases() {
return activeCases;
}
public void setActiveCases(String activeCases) {
this.activeCases = activeCases;
}
public String getSeriousCases() {
return seriousCases;
}
public void setSeriousCases(String seriousCases) {
this.seriousCases = seriousCases;
}
}
This is the Activity class
Country_List.java
public class Country_List extends AppCompatActivity {
ListView listView;
FirebaseDatabase firebaseDatabase;
DatabaseReference reff;
ArrayList<String> countries;
ArrayAdapter<String> adapter;
Country country;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_country__list);
listView = (ListView) findViewById(R.id.listView);
country = new Country();
firebaseDatabase = FirebaseDatabase.getInstance();
reff = firebaseDatabase.getReference().child("country");
countries = new ArrayList<>();
adapter = new ArrayAdapter<>(Country_List.this, R.layout.country_info, R.id.country_info_list, countries);
reff.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds: dataSnapshot.getChildren()){
country = ds.getValue(Country.class);
countries.add("Country Name:" + country.getName().toString() + "\n" + "Total Cases:" + country.getTotal().toString() + "\n" + "New Cases:" + country.getNewCases().toString() + "\n" + "Total Deaths:" + country.getTotalDeaths().toString() + "\n" + "New Deaths:" + country.getNewCases().toString() + "Total Recovered:" + country.getTotalRecovered().toString() + "Active Cases:" + country.getActiveCases().toString() + "\n" + "Serious Cases:" + country.getSeriousCases().toString());
}
listView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
StackTrace
com.google.firebase.database.DatabaseException: Failed to convert value of type java.lang.Long to String
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertString(com.google.firebase:firebase-database##19.2.1:425)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-database##19.2.1:216)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToType(com.google.firebase:firebase-database##19.2.1:178)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.access$100(com.google.firebase:firebase-database##19.2.1:47)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(com.google.firebase:firebase-database##19.2.1:592)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.deserialize(com.google.firebase:firebase-database##19.2.1:562)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertBean(com.google.firebase:firebase-database##19.2.1:432)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.deserializeToClass(com.google.firebase:firebase-database##19.2.1:231)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToCustomClass(com.google.firebase:firebase-database##19.2.1:79)
at com.google.firebase.database.DataSnapshot.getValue(com.google.firebase:firebase-database##19.2.1:203)
at com.example.covid_19explorer.Country_List$1.onDataChange(Country_List.java:40)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##19.2.1:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##19.2.1:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##19.2.1:55)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
To solve this, you please change all the properties in your Country class to be of type long, except the name, which should remain a String. Please also change all the setters and getters. Your class should look like this:
public class Country {
private String name;
private long total, newCases, totalDeaths, newDeaths, totalRecovered, activeCases, seriousCases;
public Country() {}
public Country(String name, long total, long newCases, long totalDeaths, long newDeaths, long totalRecovered, long activeCases, long seriousCases) {
this.name = name;
this.total = total;
this.newCases = newCases;
this.totalDeaths = totalDeaths;
this.newDeaths = newDeaths;
this.totalRecovered = totalRecovered;
this.activeCases = activeCases;
this.seriousCases = seriousCases;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public long getNewCases() {
return newCases;
}
public void setNewCases(long newCases) {
this.newCases = newCases;
}
public long getTotalDeaths() {
return totalDeaths;
}
public void setTotalDeaths(long totalDeaths) {
this.totalDeaths = totalDeaths;
}
public long getNewDeaths() {
return newDeaths;
}
public void setNewDeaths(long newDeaths) {
this.newDeaths = newDeaths;
}
public long getTotalRecovered() {
return totalRecovered;
}
public void setTotalRecovered(long totalRecovered) {
this.totalRecovered = totalRecovered;
}
public long getActiveCases() {
return activeCases;
}
public void setActiveCases(long activeCases) {
this.activeCases = activeCases;
}
public long getSeriousCases() {
return seriousCases;
}
public void setSeriousCases(long seriousCases) {
this.seriousCases = seriousCases;
}
}
There is one more thing that you need to do, which is to change the type for the newCases property in the database this time, to be of type long, as it is a String now. That plus sign (+) is not recommended to be added in the database, you should add it programmatically.
I am again trying to use TMBD api. I am using a recyclerview to map the data into a list.But the response I am getting from the retrofit response is null.
Main Activity:
public class MainActivity extends AppCompatActivity {
public final static String BASE_URL="https://api.themoviedb.org";
public final static String apiKey="<ApiKey>";
public final static String language="en-US";
public final static String TAG="tag";
#BindView(R.id.recyclerView)
RecyclerView movieList;
DisplayAdapter adapter;
MovieResponse result;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiInterface apiInterface=retrofit.create(ApiInterface.class);
apiInterface.getMovies(apiKey,language,1)
.enqueue(new Callback<MovieResponse>() {
#Override
public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) {
if(response.isSuccessful())
{
result=response.body();
Log.e(TAG, "onCreate: "+result );
}
}
#Override
public void onFailure(Call<MovieResponse> call, Throwable t) { }
});
Log.e(TAG, "onCreate: "+result );
adapter=new DisplayAdapter(getApplicationContext(),result);
RecyclerView.LayoutManager layoutManager=new GridLayoutManager(getApplicationContext(),1);
movieList.setLayoutManager(layoutManager);
movieList.setAdapter(adapter);
}
}
Response Class:
public class MovieResponse {
private int page;
private int total_results;
private int total_pages;
private List<ResultsBean> results;
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getTotal_results() {
return total_results;
}
public void setTotal_results(int total_results) {
this.total_results = total_results;
}
public int getTotal_pages() {
return total_pages;
}
public void setTotal_pages(int total_pages) {
this.total_pages = total_pages;
}
public List<ResultsBean> getResults() {
return results;
}
public void setResults(List<ResultsBean> results) {
this.results = results;
}
public static class ResultsBean {
private double popularity;
private int vote_count;
private boolean video;
private String poster_path;
private int id;
private boolean adult;
private String backdrop_path;
private String original_language;
private String original_title;
private String title;
private double vote_average;
private String overview;
private String release_date;
private List<Integer> genre_ids;
public double getPopularity() {
return popularity;
}
public void setPopularity(double popularity) {
this.popularity = popularity;
}
public int getVote_count() {
return vote_count;
}
public void setVote_count(int vote_count) {
this.vote_count = vote_count;
}
public boolean isVideo() {
return video;
}
public void setVideo(boolean video) {
this.video = video;
}
public String getPoster_path() {
return poster_path;
}
public void setPoster_path(String poster_path) {
this.poster_path = poster_path;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isAdult() {
return adult;
}
public void setAdult(boolean adult) {
this.adult = adult;
}
public String getBackdrop_path() {
return backdrop_path;
}
public void setBackdrop_path(String backdrop_path) {
this.backdrop_path = backdrop_path;
}
public String getOriginal_language() {
return original_language;
}
public void setOriginal_language(String original_language) {
this.original_language = original_language;
}
public String getOriginal_title() {
return original_title;
}
public void setOriginal_title(String original_title) {
this.original_title = original_title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getVote_average() {
return vote_average;
}
public void setVote_average(double vote_average) {
this.vote_average = vote_average;
}
public String getOverview() {
return overview;
}
public void setOverview(String overview) {
this.overview = overview;
}
public String getRelease_date() {
return release_date;
}
public void setRelease_date(String release_date) {
this.release_date = release_date;
}
public List<Integer> getGenre_ids() {
return genre_ids;
}
public void setGenre_ids(List<Integer> genre_ids) {
this.genre_ids = genre_ids;
}
}
}
The Api Interface:
public interface ApiInterface {
#GET("3/movie/popular")
Call<MovieResponse> getMovies(
#Query("api_key") String apiKey,
#Query("language")String language,
#Query("page")int page
);
}
I am learning the concept of api calling. I dont understand why the response is null. If anybody could explai the reason it will be very helpfull.
This can be several things from what you posted.
It can be that the Java models don't match the JSON. You'd have to double check this.
It can be that you're getting an error, in which case retrofit does not have a response.body(), but rather a response.errorBody(). You can check this by debugging and checking response.erroeBody().string().
Or it could to be a classic example of asynch behaviour being handled like it's synchronous.
adapter=new DisplayAdapter(getApplicationContext(),result);
In this case you're using result, but it's assigned inside the retrofit callback which most likely finished after you create the adapter and hence result is still null.
You can move the creation of the adapter and setting it to the list inside the callback:
public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) {
if(response.isSuccessful())
{
result=response.body();
Log.e(TAG, "onCreate: "+result );
adapter=new DisplayAdapter(getApplicationContext(),result);
RecyclerView.LayoutManager layoutManager=new GridLayoutManager(getApplicationContext(),1);
movieList.setLayoutManager(layoutManager);
movieList.setAdapter(adapter);
}
}
These are the only things that come to mind. Hope it helps.
EDIT
After taking a look at the github project, the only thing I found that is crashing the app is inside DisplayAdapter.java line 44:
holder.movieRating.setText((int) listOfMovies.getResults().get(position).getVote_average());
When you call setText that accepts an int you are in fact calling a method that will look in your strings.xml for a string with the id equal to the int you passed in. In this case, you are passing the vote average as an int. I'm guessing that what you want is to display the vote average, so the solution is to convert the double vote average to a string. This can easily be achieved with String.valueOf:
holder.movieRating.setText(String.valueOf(listOfMovies.getResults().get(position).getVote_average()));
Perhaps the most interesting bit is in the log message android.content.res.Resources$NotFoundException: String resource ID #0x7. This is thrown when trying to look for the string that doesn't exist.