Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Google places autoComplete textfield implementation in jetpack compose android

Did anyone implement google autocomplete suggestion text field or fragment in a jetpack compose project? If so kindly guide or share code snippets as I'm having difficulty in implementing it.

Update

Here is the intent that I'm triggering to open full-screen dialog, but when I start typing within it gets closed, and also I'm unable to figure out what the issue is and need a clue about handling on activity result for reading the result of the predictions within this compose function.

    Places.initialize(context, "sa")

    val fields = listOf(Place.Field.ID, Place.Field.NAME)

    val intent = Autocomplete.IntentBuilder(
        AutocompleteActivityMode.FULLSCREEN,fields).build(context)

        startActivityForResult(context as MainActivity,intent, AUTOCOMPLETE_REQUEST_CODE, Bundle.EMPTY)
                            
like image 995
Ali Nawaz Avatar asked Mar 27 '26 18:03

Ali Nawaz


2 Answers

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 ;)
like image 176
Tom Avatar answered Mar 29 '26 06:03

Tom


@Composable
fun MyComponent() {
    val context = LocalContext.current

    val intentLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.StartActivityForResult()
    ) {
        when (it.resultCode) {
            Activity.RESULT_OK -> {
                it.data?.let {
                    val place = Autocomplete.getPlaceFromIntent(it)
                    Log.i("MAP_ACTIVITY", "Place: ${place.name}, ${place.id}")
                }
            }
            AutocompleteActivity.RESULT_ERROR -> {
                it.data?.let {
                    val status = Autocomplete.getStatusFromIntent(it)
                    Log.i("MAP_ACTIVITY", "Place: ${place.name}, ${place.id}")
                }
            }
            Activity.RESULT_CANCELED -> {
                // The user canceled the operation.
            }
        }
    }

    val launchMapInputOverlay = {
        Places.initialize(context, YOUR_API_KEY)
        val fields = listOf(Place.Field.ID, Place.Field.NAME)
        val intent = Autocomplete
            .IntentBuilder(AutocompleteActivityMode.OVERLAY, fields)
            .build(context)
        intentLauncher.launch(intent)
    }

    Column {
        Button(onClick = launchMapInputOverlay) {
            Text("Select Location")
        }
    }
}
like image 45
levi Avatar answered Mar 29 '26 07:03

levi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!