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.
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 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.
I 've problem with display data in ListView. I get data from Retrofit response, but my activity, which should display this data, is just beeing blank, all the time. I am sure, that I've receiving data, I've checked it, in console.
Model class
public class itemList_model {
#SerializedName("results")
private List<itemList_Results> results;
public List<itemList_Results> getResults() {
return results;
}
public static class itemList_Results{
#SerializedName("title")
String title;
#SerializedName("vote_average")
Double vote;
#SerializedName("genre_ids")
List<Integer> genresId;
#SerializedName("release_date")
String releaseDate;
public itemList_Results(String title, Double vote, String releaseDate) {
this.title = title;
this.vote = vote;
this.releaseDate = releaseDate;
}
public String getTitle() {
return title;
}
public Double getVote() {
return vote;
}
public List<Integer> getGenresId() {
return genresId;
}
public String getReleaseDate() {
return releaseDate;
}
}
public class itemList_genresId{
#SerializedName("genre_ids")
int id;
public int getId() {
return id;
}
}
}
adapter class
public class genres_adapter extends ArrayAdapter<itemList_model.itemList_Results> {
RetrofitCalls calls;
public genres_adapter(#NonNull Context context, ArrayList<itemList_model.itemList_Results> list) {
super(context, 0, list);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View itemView = convertView;
if (itemView == null){
itemView = LayoutInflater.from(getContext()).inflate(R.layout.genres_item_view, parent, false);
}
itemList_model.itemList_Results model = getItem(position);
TextView title = itemView.findViewById(R.id.title);
title.setText(model.getTitle());
TextView vote = itemView.findViewById(R.id.vote);
vote.setText(String.valueOf(model.getVote()));
TextView release = itemView.findViewById(R.id.release);
release.setText(model.getReleaseDate());
return itemView;
}
}
activity java class
ArrayList<itemList_model.itemList_Results> arrayList;
genres_adapter adapter;
String title = "";
Double average_votes = 0.0;
String date = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_genres_list_view);
arrayList = new ArrayList<itemList_model.itemList_Results>();
adapter = new genres_adapter(this, arrayList);
ListView listView = (ListView) findViewById(R.id.genres_listView);
listView.setAdapter(adapter);
getListViewItems();
}
public void getListViewItems(){
String url = "https://api.themoviedb.org/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiCall api = retrofit.create(apiCall.class);
Call<itemList_model> call = api.getHorror();
call.enqueue(new Callback<itemList_model>() {
#Override
public void onResponse(Call<itemList_model> call, Response<itemList_model> response) {
if (!response.isSuccessful()) {
Log.i(TAG, "onResponse: " + response.code());
}
List<itemList_model.itemList_Results> list = response.body().getResults();
for (itemList_model.itemList_Results model : list){
title =model.getTitle();
average_votes = Double.valueOf(model.getVote());
date =model.getReleaseDate();
}
list.add(new itemList_model.itemList_Results(title,average_votes,date));
}
#Override
public void onFailure(Call<itemList_model> call, Throwable t) {
Log.i(TAG, "onFailure: "+t.getMessage());
}
});
}
activity, that contains ListView, is called activity_genres_list_view
activity which will be used by adapter, is called genres_item_view
I'm guess, it's about data from list, maybe it's not being added?
Apparently, you should add your list to adapter after you received it:
adapter.addAll(list);
I cannot see any notifyDataSetChanged() call in your code. When the response is found from the Retrofit call, you need to update the list which was passed to the adapter and call notifyDataSetChanged on your adapter to see the effect.
Hence you might consider doing something like the following.
public void getListViewItems(){
String url = "https://api.themoviedb.org/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiCall api = retrofit.create(apiCall.class);
Call<itemList_model> call = api.getHorror();
call.enqueue(new Callback<itemList_model>() {
#Override
public void onResponse(Call<itemList_model> call, Response<itemList_model> response) {
if (!response.isSuccessful()) {
Log.i(TAG, "onResponse: " + response.code());
}
// Do not create a new list here. Use the arrayList which was declared before and passed to the adapter
// List<itemList_model.itemList_Results> list = response.body().getResults();
// Clear the arrayList before pushing new data
arrayList.clear();
for (itemList_model.itemList_Results model : list){
title =model.getTitle();
average_votes = Double.valueOf(model.getVote());
date = model.getReleaseDate();
// Add the data into the arrayList instead of the list
arrayList.add(new itemList_model.itemList_Results(title,average_votes,date));
}
// Now call notifyDataSetChanged on your adapter to see the changes in the ListView
adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<itemList_model> call, Throwable t) {
Log.i(TAG, "onFailure: "+t.getMessage());
}
});
}
Hope that fixes your problem.
Nothing appear because you are setting adapter before getting information :
adapter = new genres_adapter(this, arrayList);//array list is still empty here
listView.setAdapter(adapter);
getListViewItems();
what yo should do is setting adapter once you get the list ! or call notifydatasetChanged on your adapter after you get your informations !
{
.....
arrayList.add(new itemList_model.itemList_Results(title,average_votes,date));
.....
}
adapter.notifyDataSetChanged();
I am new to retrofit 2 and i am trying to get json array data but getting null, this is the url for getting the data.
But the funny thing is when i try to debug inside onResponse i am getting success message as well as response.body data. What is the problem here?
https://xenzet.com/GameCheat/viewgamesjson.php
this is json data
[
{
"gameid":"2",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/counter strike 1.6.png",
"Games_Name":"1"
},
{
"gameid":"3",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/gta.ico",
"Games_Name":"vice city sucjlfsdrgefdsrhag"
},
{
"gameid":"4",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/pubg.png",
"Games_Name":"pubg"
},
{
"gameid":"5",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/doom.png",
"Games_Name":"Doom Enternal"
},
{
"gameid":"6",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/for.png",
"Games_Name":"Fornite"
},
{
"gameid":"9",
"gameIcon":"https:\/\/xenzet.com\/GameCheat\/uploads\/dota2.png",
"Games_Name":"dota2"
}
]
this is the method which is trying to get data
public void fetch_information() {
ApiInterface = ApiClient.getApiClient().create(Api.class);
Call<List<Games>> call = ApiInterface.GetGames();
call.enqueue(new Callback<List<Games>>() {
#Override
public void onResponse(Call<List<Games>> call, Response<List<Games>> response) {
if(response.isSuccessful()) {
gameslist = response.body();
gamescounter = gameslist.size();
adapter = new GameRecyclerViewAdapter(GamesActivity.this, gameslist);
recyclerView.setAdapter(adapter);
}
}
#Override
public void onFailure(Call<List<Games>> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
this is ApiClient
public class ApiClient {
public static String Base_URL ;
public static Retrofit retrofit;
public static Retrofit getApiClient()
{
if (retrofit == null)
{
Base_URL ="https://xenzet.com/GameCheat/";
retrofit = new Retrofit.Builder().baseUrl(Base_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}
}
and Api
public interface Api {
#GET("viewgamesjson.php")
Call<List<Games>> GetGames();
}
and in OnCreate i am calling fetch information method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_games);
gameslist = new ArrayList<Games>();
RecyclerView recyclerView = findViewById(R.id.recyclerview_gameslist);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
fetch_information();
Toast.makeText(getApplicationContext(),"" +gamescounter, Toast.LENGTH_SHORT).show();
adapter = new GameRecyclerViewAdapter(this, gameslist);
recyclerView.setAdapter(adapter);
adapter.setClickListener((GameRecyclerViewAdapter.ItemClickListener) this);
}
trying to fill data of game list in recycler view but fails as it null.
this is logcat
2019-05-27 14:03:43.261 1261-1261/com.example.quizgames E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.quizgames, PID: 1261
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setAdapter(android.support.v7.widget.RecyclerView$Adapter)' on a null object reference
at com.example.quizgames.GamesActivity$1.onResponse(GamesActivity.java:109)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:70)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
This is class Games
public class Games {
#SerializedName("gameid")
#Expose
private String gameid;
#SerializedName("gameIcon")
#Expose
private String gameIcon;
#SerializedName("Games_Name")
#Expose
private String gamesName;
public String getGameid() {
return gameid;
}
public void setGameid(String gameid) {
this.gameid = gameid;
}
public String getGameIcon() {
return gameIcon;
}
public void setGameIcon(String gameIcon) {
this.gameIcon = gameIcon;
}
public String getGamesName() {
return gamesName;
}
public void setGamesName(String gamesName) {
this.gamesName = gamesName;
}
// public Games(String Gameid,String Gameicon,String GameName)
// {
// this.gameid = Gameid;
// this.gameIcon = Gameicon;
// this.gamesName = GameName;
//
// }
}
This is recycler view
class GameRecyclerViewAdapter extends RecyclerView.Adapter<GameRecyclerViewAdapter.ViewHolder> {
private List<Games> mGames;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
GameRecyclerViewAdapter(Context context, List<Games> games) {
this.mInflater = LayoutInflater.from(context);
this.mGames = games;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.gameitem, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Games Game = mGames.get(position);
String Gameid = Game.getGameid();
String Gameicon = Game.getGameIcon();
String Gamename = Game.getGamesName();
holder.GameNameTxt.setText(Gamename);
Glide.with(holder.GameIconImage.getContext()).load(Game.getGameIcon()).thumbnail(0.1f).
placeholder(R.color.colorPrimary).diskCacheStrategy(DiskCacheStrategy.NONE).into(holder.GameIconImage);
}
// total number of rows
#Override
public int getItemCount() {
return mGames == null ? 0 : mGames.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView GameNameTxt;
ImageView GameIconImage;
ViewHolder(View itemView) {
super(itemView);
GameNameTxt = itemView.findViewById(R.id.gamename);
GameIconImage = itemView.findViewById(R.id.imageView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
Add data in your Adapter in side onResponse Method
add fetch_information() in oncreate
#Override
public void onResponse(Call<List<Games>> call, Response<List<Games>> response) {
if(response.isSuccessful()) {
gameslist = response.body();
adapter = new GameRecyclerViewAdapter(MainActivity.this, gameslist);
//change your Activity name here insted of MainActivity
recyclerView.setAdapter(adapter);
}
}
I didn't check where you make mistake. But this code implementation returning me list having 10 data inside list.
public interface APIInterface {
#GET()
Call<List<ViewGame>> viewgamesjson(#Url String url);
}
This is model class:
public class ViewGame {
String gameid,gameIcon,Games_Name;
public String getGameid() {
return gameid;
}
public void setGameid(String gameid) {
this.gameid = gameid;
}
public String getGameIcon() {
return gameIcon;
}
public void setGameIcon(String gameIcon) {
this.gameIcon = gameIcon;
}
public String getGames_Name() {
return Games_Name;
}
public void setGames_Name(String games_Name) {
Games_Name = games_Name;
}
}
This is APiClient Class:
public class APIClient {
static Retrofit retrofit = null;
public static String Base_URL = "https://xenzet.com/GameCheat/";
public static APIInterface getInterface() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(Base_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit.create(APIInterface.class);
}
}
And this is API Call:
private void viewGame() {
Call<List<ViewGame>> call = APIClient.getInterface().viewgamesjson("https://xenzet.com/GameCheat/viewgamesjson.php");
call.enqueue(new Callback<List<ViewGame>>() {
#Override
public void onResponse(Call<List<ViewGame>> call, Response<List<ViewGame>> response) {
try {
Global.dismissProgress();
if (response.isSuccessful() && response.body() != null) {
Global.dismissProgress();
Global.printLog("size===", response.body().size() + "");
} else {
Global.dismissProgress();
}
} catch (Exception e) {
e.printStackTrace();
Global.dismissProgress();
}
}
#Override
public void onFailure(Call<List<ViewGame>> call, Throwable t) {
Global.dismissProgress();
try {
Global.showToast(SplashActivity.this, getString(R.string.something_wrong));
} catch (Exception e) {
e.printStackTrace();
}
call.cancel();
t.printStackTrace();
}
});
}
The problem is, that you set up your list adapter in onCreate(), where gameslist is still null.
adapter = new GameRecyclerViewAdapter(this, gameslist);
recyclerView.setAdapter(adapter);
When you call the setAdapter() method, the recyclerView will ask the adapter for the number of items; and in getItemCount() I suppose, you have something like return gameslist.count(). Since gameslist is still null, this causes the NPE.
To fix it, change getItemCount() to something like this:
return gameslist == null ? 0 : gameslist.size()
EDIT
I checked your URL (with Postman), and it appears that the content-type of the response is text/html and not application/json as it should be. I suppose that therefore the response isn't converted using Gson and thus you end up with null.
I have 5 fragments inside my activity where one fragment stays active at one time. Clicking on a recyclerview item opens another fragment and puts current fragment in the backstack.
The same code was working fine some days ago, but now the app is throwing NotSerializableException whenever I click the home button to put the app in background. I have tried putting the initializing the variables inside onStart and then giving the null value in onStop but that didn't work.
Fragment Code:
public class PaperListFragment extends Fragment implements Serializable {
private static final String TAG = "PaperListFragment";
private static final String QUESTIONS_FRAGMENT_TAG = "questions_fragment";
private static final String ADD_PAPER_FRAGMENT_TAG = "add_paper_fragment";
private OnFragmentActiveListener mOnFragmentActiveListener;
private TextView mHeadingText;
private Bundle mOutState;
private FirebaseAuth mAuth;
private DatabaseReference mDatabaseReference;
private ProgressBar mProgressBar;
private OnItemClickListener mOnItemClickListener;
private FloatingActionButton mFab;
private RecyclerView mRecyclerViewPaper;
private ArrayList<Paper> mPaperList = new ArrayList<>();
private Subject mSubject = new Subject();
private Exam mExam = new Exam();
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_recycler_list, container, false);
mProgressBar = (ProgressBar) rootView.findViewById(R.id.progressbar_news);
mFab = (FloatingActionButton) rootView.findViewById(R.id.floatingActionButton);
mProgressBar.setVisibility(View.VISIBLE);
Log.d(TAG, "onCreateView: Fragment created");
mAuth = FirebaseAuth.getInstance();
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
if (mAuth.getCurrentUser() == null) {
startActivity(new Intent(getActivity(), LoginActivity.class));
getActivity().finish();
return null;
}
if (getArguments() != null) {
mOnFragmentActiveListener = (OnFragmentActiveListener) getArguments().getSerializable(Keys.FRAGMENT_ACTIVE_LISTENER);
mSubject = (Subject) getArguments().getSerializable(Keys.SUBJECT_KEY);
mExam = (Exam) getArguments().getSerializable(Keys.EXAMS_KEY);
}
mRecyclerViewPaper = (RecyclerView) rootView.findViewById(R.id.recycler_list);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()) {
#Override
public boolean canScrollVertically() {
return false;
}
};
mRecyclerViewPaper.setLayoutManager(layoutManager);
Log.d(TAG, "onCreateView: Layout Manager Set.");
mFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startAddPaperFragment();
}
});
mOnItemClickListener = new OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView.ViewHolder holder, int position) {
Log.d(TAG, "onItemClicked: Clicked item position is: "+ position);
QuestionListFragment questionFragment = new QuestionListFragment();
questionFragment.setRetainInstance(true);
startFragment(position, questionFragment, QUESTIONS_FRAGMENT_TAG);
}
#Override
public void OnItemLongClicked(RecyclerView.ViewHolder holder, int position) {
}
};
mHeadingText = (TextView) rootView.findViewById(R.id.heading_textview);
mHeadingText.setText(mExam.getExam_name()+" > "+ mSubject.getSubject_name());
if (mOutState != null) {
mPaperList = (ArrayList<Paper>) mOutState.getSerializable(Keys.PAPER_LIST_KEY);
updateUI();
} else {
updateUIFromDatabase();
}
return rootView;
}
private void startFragment(int position, Fragment fragment, String fragmentTag) {
Paper paper = new Paper();
if (mPaperList.size() > 0) {
paper = mPaperList.get(position);
}
Bundle args = new Bundle();
args.putSerializable(Keys.EXAMS_KEY, mExam);
args.putSerializable(Keys.SUBJECT_KEY, mSubject);
args.putSerializable(Keys.PAPER, paper);
args.putSerializable(Keys.FRAGMENT_ACTIVE_LISTENER, mOnFragmentActiveListener);
fragment.setArguments(args);
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
fragmentTransaction.replace(R.id.questions_fragment_container, fragment, fragmentTag);
fragmentTransaction.addToBackStack(fragmentTag);
fragmentTransaction.commit();
}
private void startAddPaperFragment() {
AddPaperFragment addPaperFragment = new AddPaperFragment();
addPaperFragment.setRetainInstance(true);
startFragment(0, addPaperFragment, ADD_PAPER_FRAGMENT_TAG);
}
private void updateUIFromDatabase() {
if (getArguments() != null){
Exam exam = (Exam) getArguments().getSerializable(Keys.EXAMS_KEY);
Subject subject = (Subject) getArguments().getSerializable(Keys.SUBJECT_KEY);
DatabaseReference paperReference =
mDatabaseReference
.child(Keys.APP_DATA_KEY)
.child(Keys.EXAM_PAPERS)
.child(exam.getExam_name())
.child(subject.getSubject_name());
Query query = paperReference.orderByChild(Keys.TIME_ADDED);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mPaperList.clear();
for (DataSnapshot paperChild : dataSnapshot.getChildren()) {
mPaperList.add(paperChild.getValue(Paper.class));
}
updateUI();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
private void updateUI() {
PaperRecyclerAdapter adapter = new PaperRecyclerAdapter(
getActivity(),
mRecyclerViewPaper,
mPaperList,
mOnItemClickListener
);
mRecyclerViewPaper.setAdapter(adapter);
mProgressBar.setVisibility(View.GONE);
}
#Override
public void onResume() {
super.onResume();
if (getArguments()!=null){
mOnFragmentActiveListener.onFragmentActive(
this,
"Topics"
);
}
}
#Override
public void onPause() {
super.onPause();
mOutState = new Bundle();
mOutState.putSerializable(Keys.PAPER_LIST_KEY, mPaperList);
}
}
Exception:
2018-12-26 17:49:38.344 14834-14834/in.crazybytes.bankmaniaadmin E/AndroidRuntime: FATAL EXCEPTION: main
Process: in.crazybytes.bankmaniaadmin, PID: 14834
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = in.crazybytes.bankmaniaadmin.activities.QuestionsActivity)
at android.os.Parcel.writeSerializable(Parcel.java:1526)
at android.os.Parcel.writeValue(Parcel.java:1474)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.support.v4.app.FragmentState.writeToParcel(FragmentState.java:124)
at android.os.Parcel.writeTypedArray(Parcel.java:1306)
at android.support.v4.app.FragmentManagerState.writeToParcel(FragmentManager.java:639)
at android.os.Parcel.writeParcelable(Parcel.java:1495)
at android.os.Parcel.writeValue(Parcel.java:1401)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3697)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by: java.io.NotSerializableException: com.google.firebase.auth.internal.zzj
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1224)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1584)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1549)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1472)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1218)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1584)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1549)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1472)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1218)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at android.os.Parcel.writeSerializable(Parcel.java:1521)
at android.os.Parcel.writeValue(Parcel.java:1474)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.support.v4.app.FragmentState.writeToParcel(FragmentState.java:124)
at android.os.Parcel.writeTypedArray(Parcel.java:1306)
at android.support.v4.app.FragmentManagerState.writeToParcel(FragmentManager.java:639)
at android.os.Parcel.writeParcelable(Parcel.java:1495)
at android.os.Parcel.writeValue(Parcel.java:1401)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3697)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Note: The weird thing is that one of fragment has the exact same code and is hosted inside the same activity, but when that fragment is active and app goes to background, interestingly the app is not crashing.
**Exam Model Class:
package in.crazybytes.bankmaniaadmin.models;
import java.io.Serializable;
public class Exam implements Serializable {
private String mExam_name;
private String mExam_key;
private Long mTime_added;
private int mNum_subjects;
private int mNum_questions;
public Exam(String exam_name, String exam_key, Long time_added, int num_subjects, int num_questions) {
mExam_name = exam_name;
mExam_key = exam_key;
mTime_added = time_added;
mNum_subjects = num_subjects;
mNum_questions = num_questions;
}
public Exam() {
}
public String getExam_name() {
return mExam_name;
}
public void setExam_name(String exam_name) {
mExam_name = exam_name;
}
public String getExam_key() {
return mExam_key;
}
public void setExam_key(String exam_key) {
mExam_key = exam_key;
}
public Long getTime_added() {
return mTime_added;
}
public void setTime_added(Long time_added) {
mTime_added = time_added;
}
public int getNum_subjects() {
return mNum_subjects;
}
public void setNum_subjects(int num_subjects) {
mNum_subjects = num_subjects;
}
public int getNum_questions() {
return mNum_questions;
}
public void setNum_questions(int num_questions) {
mNum_questions = num_questions;
}
}
Paper Model Class
package in.crazybytes.bankmaniaadmin.models;
import java.io.Serializable;
public class Paper implements Serializable {
private String mPaper_name;
private String mPaper_key;
private Long mTime_added;
private int mNum_questions;
public Paper(String paper_name, String paper_key, Long time_added, int num_questions) {
mPaper_name = paper_name;
mPaper_key = paper_key;
mTime_added = time_added;
mNum_questions = num_questions;
}
public Paper() {
}
public String getPaper_key() {
return mPaper_key;
}
public void setPaper_key(String paper_key) {
mPaper_key = paper_key;
}
public Long getTime_added() {
return mTime_added;
}
public void setTime_added(Long time_added) {
mTime_added = time_added;
}
public int getNum_questions() {
return mNum_questions;
}
public void setNum_questions(int num_questions) {
mNum_questions = num_questions;
}
public String getPaper_name() {
return mPaper_name;
}
public void setPaper_name(String paper_name) {
mPaper_name = paper_name;
}
}
Subject Model Class:
package in.crazybytes.bankmaniaadmin.models;
import java.io.Serializable;
public class Subject implements Serializable {
private String mSubject_name;
private String mSubject_key;
private Long mTime_added;
private int mNum_papers;
private int mNum_questions;
public Subject(String subject_name, String subject_key, Long time_added, int num_papers, int num_questions) {
mSubject_name = subject_name;
mSubject_key = subject_key;
mTime_added = time_added;
mNum_papers = num_papers;
mNum_questions = num_questions;
}
public Subject() {
}
public String getSubject_name() {
return mSubject_name;
}
public void setSubject_name(String subject_name) {
mSubject_name = subject_name;
}
public String getSubject_key() {
return mSubject_key;
}
public void setSubject_key(String subject_key) {
mSubject_key = subject_key;
}
public Long getTime_added() {
return mTime_added;
}
public void setTime_added(Long time_added) {
mTime_added = time_added;
}
public int getNum_papers() {
return mNum_papers;
}
public void setNum_papers(int num_papers) {
mNum_papers = num_papers;
}
public int getNum_questions() {
return mNum_questions;
}
public void setNum_questions(int num_questions) {
mNum_questions = num_questions;
}
}
Somehow QuestionsActivity is getting into the fragment save state, even if you don't intend for that to happen. While QuestionsActivity is being serialized, another object that is not serializable is being encountered. That's why you see TextViews and other things attempting to get serialized because all the instance variables of QuestionsActivity get serialized by default.
My best guess for why this is happening is due to this line:
args.putSerializable(Keys.FRAGMENT_ACTIVE_LISTENER, mOnFragmentActiveListener);
But it's difficult to know for sure without seeing where OnFragmentActiveListener is defined. I'm assuming either QuestionsActivity implements OnFragmentActiveListener, or QuestionsActivity defines OnFragmentActiveListener as an inner class. Either way, if you put an OnFragmentActiveListener into fragment arguments, you will encounter an exception because you indirectly are storing the entire QuestionsActivity as a fragment arg too. When a fragment stops, all fragment args become part of the fragment save state. And that's the cause of the error.
I would suggest not passing the OnFragmentActiveListener around as a fragment arg. If the OnFragmentActiveListener comes from the activity, just use getActivity() to get a reference to the activity and then get a reference to the listener.
I also noticed PaperListFragment implements Serializable and I'm assuming you did the same thing for QuestionsActivity. You probably did this to get around compile errors. But this has led to runtime errors because the instance variables on both of these classes are not all serializable. So to avoid more runtime issues, I would suggest never having activities or fragments implement serializable because these classes are inherently not serializable due to their members.