I am using the MVVM architecture and this is how I implemented it:
GooglePlacesApi
I've created an api for reaching google api named GooglePlacesApi
interface GooglePlacesApi {
@GET("maps/api/place/autocomplete/json")
suspend fun getPredictions(
@Query("key") key: String = <GOOGLE_API_KEY>,
@Query("types") types: String = "address",
@Query("input") input: String
): GooglePredictionsResponse
companion object{
const val BASE_URL = "https://maps.googleapis.com/"
}
}
The @Query("types") field is for specifiying what are you looking for in the query, you can look for establishments etc.
Types can be found here
Models
So I created 3 models for this implementation:
GooglePredictionsResponse
The way the response looks if you are doing a GET request with postman is:
Google Prediction Response
You can see that we have an object with "predictions" key so this is our first model.
data class GooglePredictionsResponse(
val predictions: ArrayList<GooglePrediction>
)
GooglePredictionTerm
data class GooglePredictionTerm(
val offset: Int,
val value: String
)
GooglePrediction
data class GooglePrediction(
val description: String,
val terms: List<GooglePredictionTerm>
)
I only needed that information, if you need anything else, feel free to modify the models or create your own.
GooglePlacesRepository
And finally we create the repository to get the information (I'm using hilt to inject my dependencies, you can ignore those annotations if not using it)
@ActivityScoped
class GooglePlacesRepository @Inject constructor(
private val api: GooglePlacesApi,
){
suspend fun getPredictions(input: String): Resource<GooglePredictionsResponse>{
val response = try {
api.getPredictions(input = input)
} catch (e: Exception) {
Log.d("Rently", "Exception: ${e}")
return Resource.Error("Failed prediction")
}
return Resource.Success(response)
}
}
Here I've used an extra class I've created to handle the response, called Resource
sealed class Resource<T>(val data: T? = null, val message: String? = null){
class Success<T>(data: T): Resource<T>(data)
class Error<T>(message: String, data:T? = null): Resource<T>(data = data, message = message)
class Loading<T>(data: T? = null): Resource<T>(data = data)
}
View Model
Again I'm using hilt so ignore annotations if not using it.
@HiltViewModel
class AddApartmentViewModel @Inject constructor(private val googleRepository: GooglePlacesRepository): ViewModel(){
val isLoading = mutableStateOf(false)
val predictions = mutableStateOf(ArrayList<GooglePrediction>())
fun getPredictions(address: String) {
viewModelScope.launch {
isLoading.value = true
val response = googleRepository.getPredictions(input = address)
when(response){
is Resource.Success -> {
predictions.value = response.data?.predictions!!
}
}
isLoading.value = false
}
}
fun onSearchAddressChange(address: String){
getPredictions(address)
}
}
If you need any further help let me know
- I didn't include UI implementation because I assume it is individual but this is the easier part ;)