Skip to Content
AdvancedCustom Sources

MapsGL Android - Custom Data Sources

Data sources are responsible for loading and providing the necessary data for a map layer. Because sources are created and cached separately from their layers, one source can back multiple layers with different styles. A layer must reference a source id for that data to be drawn. Sources are configured with a source descriptor (a concrete type of SourceDescriptor) and registered on the map with MapController.addSource — in this SDK, descriptors live under com.xweather.mapsgl.sources.source.spec (Kotlin can also import the same types via com.xweather.mapsgl.sources typealiases).

The following source descriptors are supported. See the linked API reference for fields and defaults:

DescriptorDescription
ImageSourceDescriptorRaster tile sources for image-based layers. API docs.
EncodedSourceDescriptorEncoded raster tile sources (binary / weather pipeline). API docs.
VectorSourceDescriptorVector tiles (Mapbox Vector Tile  format). API docs.
GeoJSONSourceDescriptorGeoJSON-backed sources (remote URL or in-memory data on the runtime source). API docs.

Adding Data Sources

Register a source that matches the data you want to draw before adding layers that reference it.

Vector tiles (Kotlin)

Tile URLs are strings (not java.net.URL on the descriptor). Templates support {z}, {x}, {y}, and {s} (subdomain index). When authenticator on the descriptor is null, MapController.addSource supplies WeatherService.authenticator from the controller so path templates such as [CLIENT_ID]_[CLIENT_SECRET] or {accessKey} are expanded on each request.

import com.xweather.mapsgl.map.MapController import com.xweather.mapsgl.sources.source.spec.VectorSourceDescriptor val alertsSource = VectorSourceDescriptor(id = "alerts").apply { url = "https://maps{s}.aerisapi.com/[CLIENT_ID]_[CLIENT_SECRET]/alerts/{z}/{x}/{y}/0.pbf" } val source = controller.addSource(alertsSource)

VectorSourceDescriptor is used because the data is MVT. The id is the source id layers will reference.

To limit fetch zoom, set minZoom / maxZoom on the descriptor (floats):

val alertsSource = VectorSourceDescriptor(id = "alerts").apply { url = "https://maps{s}.aerisapi.com/[CLIENT_ID]_[CLIENT_SECRET]/alerts/{z}/{x}/{y}/0.pbf" minZoom = 4f maxZoom = 8f } val source = controller.addSource(alertsSource)

To change the tile URL template after the source exists, cast the runtime source to VectorTileSource and assign tileURL (from the shared tile base type):

// `source` is the DataSource returned from addSource (source as? com.xweather.mapsgl.sources.VectorTileSource)?.let { it.tileURL = "https://maps{s}.aerisapi.com/[CLIENT_ID]_[CLIENT_SECRET]/alerts/{z}/{x}/{y}/20220506111000.pbf" } // or fetch by id (controller.getSource("alerts") as? com.xweather.mapsgl.sources.VectorTileSource)?.let { it.tileURL = "https://maps{s}.aerisapi.com/[CLIENT_ID]_[CLIENT_SECRET]/alerts/{z}/{x}/{y}/20220506111000.pbf" }

Raster (ImageSourceDescriptor / ImageTileSource), vector (VectorSourceDescriptor / VectorTileSource), and encoded (EncodedSourceDescriptor / XweatherEncodedTileSource) follow the same general pattern: configure the descriptor, call addSource, then optionally adjust tileURL on the concrete tile source.

GeoJSON

GeoJSONSourceDescriptor carries URL-related fields used when the map creates a GeoJSONSource. For a remote dataset (example: earthquakes API with format=geojson):

import com.xweather.mapsgl.sources.source.spec.GeoJSONSourceDescriptor val earthquakesSource = GeoJSONSourceDescriptor(id = "earthquakes").apply { url = "https://data.api.xweather.com/earthquakes/search?query=mag:1&limit=200&format=geojson&client_id=[CLIENT_ID]&client_secret=[CLIENT_SECRET]" } val source = controller.addSource(earthquakesSource)

The descriptor does not currently expose an inline JSON property. For static GeoJSON, register the source then assign a Mapbox FeatureCollection on the runtime object:

import com.mapbox.geojson.FeatureCollection import com.xweather.mapsgl.sources.GeoJSONSource import com.xweather.mapsgl.sources.source.spec.GeoJSONSourceDescriptor val geoJSONString = """ { "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [ -117.7805, 38.1714 ] }, "properties": { "report": { "id": "nn00838438", "timestamp": 1651863279, "dateTimeISO": "2022-05-06T11:54:39-07:00", "updatedTimestamp": 1651863515, "updatedDateTimeISO": "2022-05-06T11:58:35-07:00", "mag": 1.7, "type": "mini", "depthKM": 1.7, "depthMI": 1.06, "region": "37 km SE of Mina, Nevada", "location": "37 km SE of Mina, Nevada" }, "loc": { "long": -117.7805, "lat": 38.1714 } } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ -155.38716125488, 19.248332977295 ] }, "properties": { "report": { "id": "hv73004612", "timestamp": 1651863228, "dateTimeISO": "2022-05-06T08:53:48-10:00", "updatedTimestamp": 1651863409, "updatedDateTimeISO": "2022-05-06T08:56:49-10:00", "mag": 1.83000004, "type": "mini", "depthKM": 32.25, "depthMI": 20.04, "region": "10 km ENE of Pāhala, Hawaii", "location": "10 km ENE of Pāhala, Hawaii" }, "loc": { "long": -155.38716125488, "lat": 19.248332977295 } } }] } """.trimIndent() controller.addSource(GeoJSONSourceDescriptor(id = "earthquakes")) val geoSource = controller.getSource("earthquakes") as GeoJSONSource geoSource.data = FeatureCollection.fromJson(geoJSONString)

To update URL or in-memory data later, mutate the GeoJSONSource instance (there are no setURL / setData helpers; use url / data properties):

import com.mapbox.geojson.FeatureCollection import com.xweather.mapsgl.sources.GeoJSONSource val geoSource = controller.getSource("earthquakes") as GeoJSONSource geoSource.url = "https://data.api.xweather.com/earthquakes/search?query=mag:1&limit=200&from=-7days&to=now&format=geojson&client_id=[CLIENT_ID]&client_secret=[CLIENT_SECRET]" val geoJSONString = """ { "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [ -117.7805, 38.1714 ] }, "properties": { "report": { "id": "nn00838438", "timestamp": 1651863279, "dateTimeISO": "2022-05-06T11:54:39-07:00", "updatedTimestamp": 1651863515, "updatedDateTimeISO": "2022-05-06T11:58:35-07:00", "mag": 1.7, "type": "mini", "depthKM": 1.7, "depthMI": 1.06, "region": "37 km SE of Mina, Nevada", "location": "37 km SE of Mina, Nevada" }, "loc": { "long": -117.7805, "lat": 38.1714 } } }] } """.trimIndent() geoSource.data = FeatureCollection.fromJson(geoJSONString)

addSource returns DataSource (common supertype). Use safe casts as shown when you need tile- or GeoJSON-specific APIs.

After sources are registered, add layers that reference each source id.

controller.addSource(GeoJSONSourceDescriptor(id = "earthquakes")) val geoSource = controller.getSource("earthquakes") as GeoJSONSource geoSource.data = FeatureCollection.fromJson(geoJSONString) controller.addLayer( CircleLayerDescriptor( id = "earthquake-circles", source = "earthquakes", sourceLayer = null, ), beforeID = null, )

Removing Data Sources

Pass the same source id you used when adding the source:

controller.removeSource("earthquakes")

If that id is registered, it is removed from the controller and listeners are notified; associated caches are dropped as part of source teardown.

© 2026 Xweather (opens in a new tab)Terms of Service (opens in a new tab)Privacy Policy (opens in a new tab)