Skip to content

Add live realtime data

In this example you will learn how to add a live GeoJSON source. We have set up a lambda function that returns a new GeoJSON point every time it is called.

First we will create a GeoJSONSource.

kotlin
try {
    style.addSource(GeoJsonSource(ID_GEOJSON_SOURCE, URI(URL_GEOJSON_SOURCE)))
} catch (malformedUriException: URISyntaxException) {
    Timber.e(malformedUriException, "Invalid URL")
}

Next we will create a SymbolLayer that uses the source.

kotlin
val layer = SymbolLayer(ID_GEOJSON_LAYER, ID_GEOJSON_SOURCE)
layer.setProperties(
    PropertyFactory.iconImage("plane"),
    PropertyFactory.iconAllowOverlap(true)
)
style.addLayer(layer)

We use define a Runnable and use android.os.Handler with a android.os.Looper to update the GeoJSON source every 2 seconds.

kotlin
private inner class RefreshGeoJsonRunnable(
    private val mapMetricsMap: MapMetricsMap,
    private val handler: Handler
) : Runnable {
    override fun run() {
        val geoJsonSource = mapMetricsMap.style!!.getSource(ID_GEOJSON_SOURCE) as GeoJsonSource
        geoJsonSource.setUri(URL_GEOJSON_SOURCE)
        val features = geoJsonSource.querySourceFeatures(null)
        setIconRotation(features)
        handler.postDelayed(this, 2000)
    }
}

Bonus: set icon rotation

You can set the icon rotation of the icon when ever the point is updated based on the last two points.

kotlin
if (features.size != 1) {
    Timber.e("Expected only one feature")
    return
}

val feature = features[0]
val geometry = feature.geometry()
if (geometry !is Point) {
    Timber.e("Expected geometry to be a point")
    return
}

if (lastLocation == null) {
    lastLocation = geometry
    return
}

mapMetricsMap.style!!.getLayer(ID_GEOJSON_LAYER)!!.setProperties(
    PropertyFactory.iconRotate(calculateRotationAngle(lastLocation!!, geometry)),
)