Created
May 20, 2021 14:06
-
-
Save NinoDLC/8818ab9d14b4c13467052df9b107422e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class NearbyRestaurantsRepository { | |
private static final String TYPE = "restaurant"; | |
// Round the GPS coordinate to avoid re-querying Google for a position that would be only a few meters away | |
private static final int GPS_SCALE = 2; | |
@NonNull | |
private final NearbyRestaurantsApi nearbyRestaurantsApi; | |
// We store all responses here, maybe sometimes we will avoid querying server if a similar query is asked | |
private final LruCache<NearbyRestaurantsQuery, NearbyRestaurantsResponse> cache = new LruCache<>(500); | |
public NearbyRestaurantsRepository(@NonNull NearbyRestaurantsApi nearbyRestaurantsApi) { | |
this.nearbyRestaurantsApi = nearbyRestaurantsApi; | |
} | |
@MainThread | |
@NonNull | |
public LiveData<NearbyRestaurantsResponse> getNearbyRestaurants(double latitude, double longitude, int radius) { | |
final MutableLiveData<NearbyRestaurantsResponse> nearbyRestaurantsResponseMutableLiveData = new MutableLiveData<>(); | |
NearbyRestaurantsQuery query = generateQuery(latitude, longitude, radius); | |
// 1. We search in our cache a similar query | |
NearbyRestaurantsResponse existing = cache.get(query); | |
if (existing != null) { | |
// 2a. We found a similar query already existing, great ! No need to waste resources with an API call on Google's servers | |
nearbyRestaurantsResponseMutableLiveData.setValue(existing); | |
} else { | |
// 2b. Nothing similar in cache, query Google ! | |
nearbyRestaurantsApi.getNearbyRestaurants( | |
latitude + "," + longitude, | |
radius, | |
TYPE, | |
null | |
).enqueue(new Callback<NearbyRestaurantsResponse>() { | |
@Override | |
public void onResponse(@NonNull Call<NearbyRestaurantsResponse> call, @NonNull Response<NearbyRestaurantsResponse> response) { | |
NearbyRestaurantsResponse body = response.body(); | |
// 3. Save the result for next time if it's good... | |
if (response.isSuccessful() && body != null && body.isSuccessful()) { | |
cache.put(query, body); | |
} | |
nearbyRestaurantsResponseMutableLiveData.setValue(body); | |
} | |
@Override | |
public void onFailure(@NonNull Call<NearbyRestaurantsResponse> call, @NonNull Throwable t) { | |
t.printStackTrace(); | |
} | |
}); | |
} | |
return nearbyRestaurantsResponseMutableLiveData; | |
} | |
// We use a LruCache as a cache, and its keys are unique (which is provided by the Object.hashCode() and Object.equals(Object other) | |
// functions). That's why I overrode these functions in the NearbyRestaurantsQuery object. | |
// Thanks to the reduction of the scale (we lose "precision" of the GPS coordinates) we can avoid querying servers when location | |
// is just a few meters aways of the first one we did. | |
// This is a cheap (and fast) way to cache location-related queries, as we are not actually comparing true distance between points. | |
// A way to improve this would be to : | |
// 1/ Use a database (persistence across sessions). Check "GetRestaurantDetailsUseCase" for an example ! | |
// 2/ Use a way to compare distance between the queried location and all the others. We would do the API call only if all persisted | |
// responses are above the "maximum distance" threshold or the response is too "old". | |
private NearbyRestaurantsQuery generateQuery(double latitude, double longitude, int radius) { | |
return new NearbyRestaurantsQuery( | |
BigDecimal.valueOf(latitude).setScale(GPS_SCALE, RoundingMode.HALF_UP), | |
BigDecimal.valueOf(longitude).setScale(GPS_SCALE, RoundingMode.HALF_UP), | |
radius | |
); | |
} | |
} | |
public class NearbyRestaurantsQuery { | |
@NonNull | |
private final BigDecimal lat; | |
@NonNull | |
private final BigDecimal lng; | |
private final int radius; | |
public NearbyRestaurantsQuery(@NonNull BigDecimal lat, @NonNull BigDecimal lng, int radius) { | |
this.lat = lat; | |
this.lng = lng; | |
this.radius = radius; | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
NearbyRestaurantsQuery that = (NearbyRestaurantsQuery) o; | |
return radius == that.radius && | |
lat.equals(that.lat) && | |
lng.equals(that.lng); | |
} | |
@Override | |
public int hashCode() { | |
return Objects.hash(lat, lng, radius); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment