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
andApiInterface
class for any wrong network address but found noneAdded
q=london
on my ApiInterface address, but it doesn't display any data nor search another city dataChecked 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;
}
}