Search code examples
androidretrofit2darksky

Retrofit onResponse and onFailure methods not getting called


When I make a call to the DarkSky API, for certain locations, my onResponse and onFailure methods are not triggered. I've tested tons of locations in the US, and everything is fine. I tested London, and that was fine, but when I test Chennai, India, neither method is triggered. I also tested the URL being called and there is a response when I put it into a web browser, but it's not triggering the onReponse() method in the app.

I've seen some people say it's because the call is asynchronous, but I don't know why it would work with 100% consistency for certain cities but not others.

Calling class:


import android.content.Context;
import android.content.SharedPreferences;
import android.widget.TextView;

import androidx.preference.PreferenceManager;

import com.jggdevelopment.simpleweather.BuildConfig;
import com.jggdevelopment.simpleweather.fragments.MasterFragment;
import com.jggdevelopment.simpleweather.models.Forecast;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class WeatherAPIUtils {

    private static String baseUrl = "https://api.darksky.net/forecast/" + BuildConfig.darkSkyAPI_KEY + "/";
    private static TextView temperatureView;
    private static TextView highTemp;
    private static TextView lowTemp;
    private static TextView description;
    private static TextView precipitationChance;
    private static SharedPreferences prefs;

    /**
     * uses retrofit to call the DarkSky API using the API key in the baseURL
     * @return WeatherService
     */
    private static WeatherService getWeatherService() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        return retrofit.create(WeatherService.class);
    }

    /**
     * Pulls weather data from the DarkSky API using the provided location.
     * On success, it updates the views in MasterFragment
     * @param lat latitude of location
     * @param lon longitude of location
     * @param fragment MasterFragment
     */
    public static void getCurrentWeatherData(Double lat, Double lon, final MasterFragment fragment) {
        WeatherService service = getWeatherService();
        prefs = fragment.getActivity().getSharedPreferences("com.jggdevelopment.simpleweather", Context.MODE_PRIVATE);

        if (prefs.getBoolean("useCelsius", false)) {
            service.getWeatherSI(lat, lon, "si").enqueue(new Callback<Forecast>() {
                @Override
                public void onResponse(Call<Forecast> call, Response<Forecast> response) {
                    if (response.isSuccessful()) {
                        fragment.updateConditions(response.body());
                    }
                }

                @Override
                public void onFailure(Call<Forecast> call, Throwable t) {

                }
            });
        } else {
            service.getWeatherImperial(lat, lon).enqueue(new Callback<Forecast>() {
                @Override
                public void onResponse(Call<Forecast> call, Response<Forecast> response) {
                    if (response.isSuccessful()) {
                        fragment.updateConditions(response.body());
                    }
                }

                @Override
                public void onFailure(Call<Forecast> call, Throwable t) {

                }
            });
        }
    }
}

POJO:


import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Forecast {

    @SerializedName("currently")
    @Expose
    private Currently currently;
    @SerializedName("daily")
    @Expose
    private Daily daily;
    @SerializedName("flags")
    @Expose
    private Flags flags;
    @SerializedName("hourly")
    @Expose
    private Hourly hourly;
    @SerializedName("latitude")
    @Expose
    private Double latitude;
    @SerializedName("longitude")
    @Expose
    private Double longitude;
    @SerializedName("minutely")
    @Expose
    private Minutely minutely;
    @SerializedName("offset")
    @Expose
    private Integer offset;
    @SerializedName("timezone")
    @Expose
    private String timezone;

    public Currently getCurrently() {
        return currently;
    }

    public void setCurrently(Currently currently) {
        this.currently = currently;
    }

    public Daily getDaily() {
        return daily;
    }

    public void setDaily(Daily daily) {
        this.daily = daily;
    }

    public Flags getFlags() {
        return flags;
    }

    public void setFlags(Flags flags) {
        this.flags = flags;
    }

    public Hourly getHourly() {
        return hourly;
    }

    public void setHourly(Hourly hourly) {
        this.hourly = hourly;
    }

    public Double getLatitude() {
        return latitude;
    }

    public void setLatitude(Double latitude) {
        this.latitude = latitude;
    }

    public Double getLongitude() {
        return longitude;
    }

    public void setLongitude(Double longitude) {
        this.longitude = longitude;
    }

    public Minutely getMinutely() {
        return minutely;
    }

    public void setMinutely(Minutely minutely) {
        this.minutely = minutely;
    }

    public Integer getOffset() {
        return offset;
    }

    public void setOffset(Integer offset) {
        this.offset = offset;
    }

    public String getTimezone() {
        return timezone;
    }

    public void setTimezone(String timezone) {
        this.timezone = timezone;
    }

}```

Solution

  • put log in url on failure like this

    @Override
            public void onFailure(Call<Response> call, Throwable t) {
                t.printStackTrace();
    
    
            }
    

    also add loggin intercepter to log the request and response

    public static OkHttpClient getHttpClient() {
    
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    
    
    
            //TODO : remove logging interceptors as it is to be used for development purpose
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(300, TimeUnit.SECONDS)
                    .readTimeout(300,TimeUnit.SECONDS).
                            addInterceptor(logging).
                            build();
    
            return client;
        }
    

    add it here like this

     private static WeatherService getWeatherService() {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .client(getHttpClient())
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
    
            return retrofit.create(WeatherService.class);
        }
    

    By doing this at least you will be able to identify the issue