Back to blog
June 11, 2025
3 min read

Using Google Maps in Kotlin

Learn how to integrate Google Maps and add markers in your Kotlin apps

Using Google Maps in Kotlin

Let’s explore how to integrate Google Maps and add markers in your Kotlin apps.

Project Setup

Dependencies

// build.gradle.kts
dependencies {
    implementation("com.google.android.gms:play-services-maps:18.2.0")
    implementation("com.google.android.gms:play-services-location:21.1.0")
}

API Key Setup

<!-- AndroidManifest.xml -->
<application>
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="YOUR_API_KEY" />
</application>

Basic Map Integration

XML Layout

<!-- activity_main.xml -->
<fragment
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Map Initialization

class MainActivity : AppCompatActivity(), OnMapReadyCallback {
    private lateinit var map: GoogleMap

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    override fun onMapReady(googleMap: GoogleMap) {
        map = googleMap

        // Set initial camera position
        val initialLocation = LatLng(-6.2088, 106.8456) // Jakarta
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(initialLocation, 12f))

        // Enable user location
        map.isMyLocationEnabled = true

        // Enable zoom controls
        map.uiSettings.isZoomControlsEnabled = true
    }
}

Map Markers

Adding Markers

// Basic marker
val marker = map.addMarker(
    MarkerOptions()
        .position(LatLng(-6.2088, 106.8456))
        .title("Jakarta")
        .snippet("Capital of Indonesia")
)

// Custom marker
val customMarker = map.addMarker(
    MarkerOptions()
        .position(LatLng(-6.2088, 106.8456))
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.custom_marker))
        .anchor(0.5f, 0.5f)
)

// Marker click listener
map.setOnMarkerClickListener { marker ->
    Toast.makeText(this, marker.title, Toast.LENGTH_SHORT).show()
    true
}

Map Controls

Camera Controls

// Camera movement
fun moveCamera(latLng: LatLng, zoom: Float = 15f) {
    map.animateCamera(
        CameraUpdateFactory.newLatLngZoom(latLng, zoom),
        1000,
        null
    )
}

// Camera bounds
fun fitBounds(locations: List<LatLng>) {
    val builder = LatLngBounds.builder()
    locations.forEach { builder.include(it) }
    map.animateCamera(
        CameraUpdateFactory.newLatLngBounds(builder.build(), 100),
        1000,
        null
    )
}

Location Services

Location Updates

class LocationManager(
    private val context: Context,
    private val lifecycleOwner: LifecycleOwner
) {
    private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
    private val locationRequest = LocationRequest.create().apply {
        priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        interval = 10000
    }

    fun startLocationUpdates(callback: (Location) -> Unit) {
        if (ActivityCompat.checkSelfPermission(
                context,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            fusedLocationClient.requestLocationUpdates(
                locationRequest,
                object : LocationCallback() {
                    override fun onLocationResult(locationResult: LocationResult) {
                        locationResult.lastLocation?.let { callback(it) }
                    }
                },
                Looper.getMainLooper()
            )
        }
    }
}

Custom Map Features

Custom Overlays

// Custom ground overlay
val groundOverlay = map.addGroundOverlay(
    GroundOverlayOptions()
        .position(LatLng(-6.2088, 106.8456), 1000f, 1000f)
        .image(BitmapDescriptorFactory.fromResource(R.drawable.overlay))
        .transparency(0.5f)
)

// Custom polyline
val polyline = map.addPolyline(
    PolylineOptions()
        .add(LatLng(-6.2088, 106.8456))
        .add(LatLng(-6.2188, 106.8556))
        .color(Color.RED)
        .width(5f)
)

Best Practices

Map State Management

// Save map state
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    map?.let { googleMap ->
        outState.putParcelable("map_state", googleMap.cameraPosition)
    }
}

// Restore map state
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
    savedInstanceState.getParcelable<CameraPosition>("map_state")?.let { position ->
        map?.moveCamera(CameraUpdateFactory.newCameraPosition(position))
    }
}

Common Patterns

Map Utilities

// 1. Marker manager
class MarkerManager(private val map: GoogleMap) {
    private val markers = mutableMapOf<String, Marker>()

    fun addMarker(id: String, position: LatLng, title: String) {
        markers[id] = map.addMarker(
            MarkerOptions()
                .position(position)
                .title(title)
        )
    }

    fun removeMarker(id: String) {
        markers[id]?.remove()
        markers.remove(id)
    }

    fun updateMarker(id: String, position: LatLng) {
        markers[id]?.position = position
    }
}

// 2. Location tracker
class LocationTracker(
    private val context: Context,
    private val onLocationUpdate: (LatLng) -> Unit
) {
    private val locationManager = LocationManager(context, lifecycleOwner)

    fun startTracking() {
        locationManager.startLocationUpdates { location ->
            onLocationUpdate(LatLng(location.latitude, location.longitude))
        }
    }
}

Conclusion

Google Maps integration in Kotlin requires:

  • Proper project setup
  • Understanding map controls
  • Managing markers
  • Handling location updates
  • Following best practices
  • Using common patterns

Remember to:

  • Handle permissions
  • Manage map state
  • Optimize performance
  • Handle errors
  • Test on different devices
  • Follow Google Maps guidelines

Stay tuned for more Kotlin tips and tricks!