简体   繁体   中英

Return string from method using Retrofit 2 for java Android

I'm attempting to query google maps api to get the placeId of a location based on lat/lng. The issue I'm having is the my code moves to the return statement before the API responds and as a result the return string is null instead of the placeId from the api. Can someone help me figure out what I'm missing?
EDITED
I have changed the getPlaceId method to return null and simply assign the getPlaceId from the response to a public variable. I get the data from the API but it looks as if the json isn't being parsed, as a result the variable is still null.

getPlaceId method using retrofit
EDITED

String lat = "39.748378", lng = "-91.857558", placeId;

 Map<String, String> query = new HashMap<>();
    query.put("latlng", lat+","+lng);
    query.put("key","API_KEY");

public void getPlaceId(final Map<String, String> query) {
    String BASE_URL = "https://maps.googleapis.com/maps/";
    Retrofit retrofit;

    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(logging)
            .build();

    retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();
    PlacesInterface service = retrofit.create(PlacesInterface.class);
    Call<PlacesFoo> call = service.loadPlace(query);
    call.enqueue(new Callback<PlacesFoo>() {
      @Override
      public void onResponse(Call<PlacesFoo> call, Response<PlacesFoo> response) {
        if(response.isSuccessful()) {
          Log.e("getPlaceId", " Valid Response: " + response.body());
          placeId = response.body().getResults().get(0).getPlaceId();
        } else {
          System.out.println(response.errorBody());
        }
      }

      @Override
      public void onFailure(Call<PlacesFoo> call, Throwable t) {
        t.printStackTrace();
        Log.e("getPlaceId", " Error Response: " + t);
      }
    });
    //return placeId;
  }

Interface for API

public interface PlacesInterface {
   
    // https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=API_KEY
    @GET("api/geocode/json")
    Call<PlacesFoo> loadPlace(@QueryMap Map<String, String> options);

}

POJO for API reply

public class PlacesFoo {

    @SerializedName("plus_code")
    @Expose
    private PlusCode plusCode;
    @SerializedName("results")
    @Expose
    private List<Result> results = null;
    @SerializedName("status")
    @Expose
    private String status;

    public PlusCode getPlusCode() {
        return plusCode;
    }

    public void setPlusCode(PlusCode plusCode) {
        this.plusCode = plusCode;
    }

    public List<Result> getResults() {
        return results;
    }

    public void setResults(List<Result> results) {
        this.results = results;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public class AddressComponent {

        @SerializedName("long_name")
        @Expose
        private String longName;
        @SerializedName("short_name")
        @Expose
        private String shortName;
        @SerializedName("types")
        @Expose
        private List<String> types = null;

        public String getLongName() {
            return longName;
        }

        public void setLongName(String longName) {
            this.longName = longName;
        }

        public String getShortName() {
            return shortName;
        }

        public void setShortName(String shortName) {
            this.shortName = shortName;
        }

        public List<String> getTypes() {
            return types;
        }

        public void setTypes(List<String> types) {
            this.types = types;
        }

    }

    public class Bounds {

        @SerializedName("northeast")
        @Expose
        private Northeast_ northeast;
        @SerializedName("southwest")
        @Expose
        private Southwest_ southwest;

        public Northeast_ getNortheast() {
            return northeast;
        }

        public void setNortheast(Northeast_ northeast) {
            this.northeast = northeast;
        }

        public Southwest_ getSouthwest() {
            return southwest;
        }

        public void setSouthwest(Southwest_ southwest) {
            this.southwest = southwest;
        }

    }

    public class Geometry {

        @SerializedName("location")
        @Expose
        private Location location;
        @SerializedName("location_type")
        @Expose
        private String locationType;
        @SerializedName("viewport")
        @Expose
        private Viewport viewport;
        @SerializedName("bounds")
        @Expose
        private Bounds bounds;

        public Location getLocation() {
            return location;
        }

        public void setLocation(Location location) {
            this.location = location;
        }

        public String getLocationType() {
            return locationType;
        }

        public void setLocationType(String locationType) {
            this.locationType = locationType;
        }

        public Viewport getViewport() {
            return viewport;
        }

        public void setViewport(Viewport viewport) {
            this.viewport = viewport;
        }

        public Bounds getBounds() {
            return bounds;
        }

        public void setBounds(Bounds bounds) {
            this.bounds = bounds;
        }

    }

    public class Location {

        @SerializedName("lat")
        @Expose
        private Double lat;
        @SerializedName("lng")
        @Expose
        private Double lng;

        public Double getLat() {
            return lat;
        }

        public void setLat(Double lat) {
            this.lat = lat;
        }

        public Double getLng() {
            return lng;
        }

        public void setLng(Double lng) {
            this.lng = lng;
        }

    }

    public class Northeast {

        @SerializedName("lat")
        @Expose
        private Double lat;
        @SerializedName("lng")
        @Expose
        private Double lng;

        public Double getLat() {
            return lat;
        }

        public void setLat(Double lat) {
            this.lat = lat;
        }

        public Double getLng() {
            return lng;
        }

        public void setLng(Double lng) {
            this.lng = lng;
        }

    }

    public class Northeast_ {

        @SerializedName("lat")
        @Expose
        private Double lat;
        @SerializedName("lng")
        @Expose
        private Double lng;

        public Double getLat() {
            return lat;
        }

        public void setLat(Double lat) {
            this.lat = lat;
        }

        public Double getLng() {
            return lng;
        }

        public void setLng(Double lng) {
            this.lng = lng;
        }

    }

    public class PlusCode {

        @SerializedName("compound_code")
        @Expose
        private String compoundCode;
        @SerializedName("global_code")
        @Expose
        private String globalCode;

        public String getCompoundCode() {
            return compoundCode;
        }

        public void setCompoundCode(String compoundCode) {
            this.compoundCode = compoundCode;
        }

        public String getGlobalCode() {
            return globalCode;
        }

        public void setGlobalCode(String globalCode) {
            this.globalCode = globalCode;
        }

    }

    public class PlusCode_ {

        @SerializedName("compound_code")
        @Expose
        private String compoundCode;
        @SerializedName("global_code")
        @Expose
        private String globalCode;

        public String getCompoundCode() {
            return compoundCode;
        }

        public void setCompoundCode(String compoundCode) {
            this.compoundCode = compoundCode;
        }

        public String getGlobalCode() {
            return globalCode;
        }

        public void setGlobalCode(String globalCode) {
            this.globalCode = globalCode;
        }

    }

    public class Result {

        @SerializedName("address_components")
        @Expose
        private List<AddressComponent> addressComponents = null;
        @SerializedName("formatted_address")
        @Expose
        private String formattedAddress;
        @SerializedName("geometry")
        @Expose
        private Geometry geometry;
        @SerializedName("place_id")
        @Expose
        private String placeId;
        @SerializedName("plus_code")
        @Expose
        private PlusCode_ plusCode;
        @SerializedName("types")
        @Expose
        private List<String> types = null;

        public List<AddressComponent> getAddressComponents() {
            return addressComponents;
        }

        public void setAddressComponents(List<AddressComponent> addressComponents) {
            this.addressComponents = addressComponents;
        }

        public String getFormattedAddress() {
            return formattedAddress;
        }

        public void setFormattedAddress(String formattedAddress) {
            this.formattedAddress = formattedAddress;
        }

        public Geometry getGeometry() {
            return geometry;
        }

        public void setGeometry(Geometry geometry) {
            this.geometry = geometry;
        }

        public String getPlaceId() {
            return placeId;
        }

        public void setPlaceId(String placeId) {
            this.placeId = placeId;
        }

        public PlusCode_ getPlusCode() {
            return plusCode;
        }

        public void setPlusCode(PlusCode_ plusCode) {
            this.plusCode = plusCode;
        }

        public List<String> getTypes() {
            return types;
        }

        public void setTypes(List<String> types) {
            this.types = types;
        }

    }

    public class Southwest {

        @SerializedName("lat")
        @Expose
        private Double lat;
        @SerializedName("lng")
        @Expose
        private Double lng;

        public Double getLat() {
            return lat;
        }

        public void setLat(Double lat) {
            this.lat = lat;
        }

        public Double getLng() {
            return lng;
        }

        public void setLng(Double lng) {
            this.lng = lng;
        }

    }

    public class Southwest_ {

        @SerializedName("lat")
        @Expose
        private Double lat;
        @SerializedName("lng")
        @Expose
        private Double lng;

        public Double getLat() {
            return lat;
        }

        public void setLat(Double lat) {
            this.lat = lat;
        }

        public Double getLng() {
            return lng;
        }

        public void setLng(Double lng) {
            this.lng = lng;
        }

    }

    public class Viewport {

        @SerializedName("northeast")
        @Expose
        private Northeast northeast;
        @SerializedName("southwest")
        @Expose
        private Southwest southwest;

        public Northeast getNortheast() {
            return northeast;
        }

        public void setNortheast(Northeast northeast) {
            this.northeast = northeast;
        }

        public Southwest getSouthwest() {
            return southwest;
        }

        public void setSouthwest(Southwest southwest) {
            this.southwest = southwest;
        }
    }
}

Retrofit supports synchronous and asynchronous request execution. Users define the concrete execution by setting a return type (synchronous) or not (asynchronous) to service methods.

Edit You need to pass the result from the Asynchronous call through interface

 public interface MyCallback {
    void onSuccess(String placeId);
    void onError(String error);
}

and your call will be like

getPlaceId(new MyCallback() {
        @Override
        public void onSuccess(String placeId) {
            // here you get place Id you can do your work with id
            Log.e("PlaceID",placeId);
        }

        @Override
        public void onError(String error) {
            // in case of error occurred
        }
    });

Retrofit call

  private void getPlaceId(MyCallback myCallback) {
    .....
    .....
    PlacesInterface service = retrofit.create(PlacesInterface .class);
    Call<PlacesFoo> call = service.loadPlace(query);
    call.enqueue(new Callback<PlacesFoo>() {
        @Override
        public void onResponse(@NotNull Call<PlacesFoo> call, @NotNull Response<PlacesFoo> response) {
            if (response.isSuccessful()) {
                String placeId = response.body().getResults().get(0).getPlaceId();
                myCallback.onSuccess(placeId);

            } else {
                if (response.errorBody() != null) {
                    myCallback.onError(response.errorBody().toString());
                }

            }
        }

        @Override
        public void onFailure(@NotNull Call<PlacesFoo> call, @NotNull Throwable t) {
            t.printStackTrace();
            myCallback.onError(t.getLocalizedMessage());
        }
    });

}

to know the difference between Asynchronous and Synchronous request check this

first create an interface like below:

public interface OnPlaceIdFoundListener {
    void onPlaceIdFound(String placeId);
}

second you should change signature and body of getPlaceId method like below (see "@@here@@:!!!!" sign):

public void getPlaceId(final Map<String, String> query, OnPlaceIdFoundListener callback) {
    String BASE_URL = "https://maps.googleapis.com/maps/";
    Retrofit retrofit;

    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(logging)
            .build();

    retrofit = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();
    PlacesInterface service = retrofit.create(PlacesInterface.class);
    Call<PlacesFoo> call = service.loadPlace(query);
    call.enqueue(new Callback<PlacesFoo>() {
        @Override
        public void onResponse(Call<PlacesFoo> call, Response<PlacesFoo> response) {
            if(response.isSuccessful()) {
                Log.e("getPlaceId", " Valid Response: " + response.body());
                String placeId = response.body().getResults().get(0).getPlaceId();
                callback.onPlaceIdFound(placeId); // @@here@@!!!!!
            } else {
                System.out.println(response.errorBody());
                callback.onPlaceIdFound(""); // @@here@@!!!!!

            }
        }

        @Override
        public void onFailure(Call<PlacesFoo> call, Throwable t) {
            t.printStackTrace();
            callback.onPlaceIdFound(""); // @@here@@!!!!!
            Log.e("getPlaceId", " Error Response: " + t);
        }
    });
    //return placeId;
}

then use your method.

getPlaceId(query, new OnPlaceIdFoundListener() {
    @Override
    public void onPlaceIdFound(String placeId) {
         Log.d("TAG", "place id is found = "+ placeId);
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM