Skip to Content
ExamplesQuery Layer Static Geojson

MapsGL Android - Wind speed text labels using custom GeoJSON

The points in this example are your own: 19 cities around Puget Sound, written into the activity as GeoJSON. A query layer reads the wind-speeds layer at each city and labels it with the value, with the city’s name beneath.

It is the Android port of the MapsGL JS Wind speed text labels using custom GeoJSON example. The complete activity ships in the MapsGL Android SDK demo  as QueryLayerStaticGeoJsonActivity.

The Puget Sound region under the wind speeds layer, with a bold wind speed and a city name at each of 19 cities

The sampled layer, at high quality

As in JS, the wind layer is requested at DataQuality.high, which is set on the layer before it is added. The labels sample this layer, so its quality sets the quality of the numbers:

val winds = WeatherService.WindSpeeds(controller.service) winds.layer.quality = DataQuality.high controller.addWeatherLayer(winds)

The activity keeps the layer’s code and passes it to the query layer, so the labels always sample the layer that was actually added.

Inline points with a nested name

Each feature is a Point with a place object holding a name, the same shape the places API returns. The collection is parsed and assigned to the descriptor before the source is registered:

val cities = GeoJSONSourceDescriptor(id = "cities") cities.data = FeatureCollection.fromJson(PUGET_SOUND_CITIES) controller.addSource(cities)

Because the shape matches, the query layer and its name label are the same as the ones used over API places.

Two text blocks on one query layer

DataQueryLayerDescriptor is the JS type: 'query' layer, with sampledLayerCode in place of queryLayer. Its paint has two TextPaint blocks. The first is the sampled value, large and bold. The second is the name, small and anchored below the value:

TextPaint( value = StyleValue.Expression(Expression.get("place.name")), size = StyleValue.Constant(12.0), color = StyleValue.Constant(Color.Black), outlineColor = StyleValue.Constant(Color.White), anchor = StyleValue.Constant(Anchor.TOP), offset = StyleValue.Constant(AnchorOffset(0.0, 20.0)), )

labelKeyPath = "place.name" tells the layer where the name lives on each feature. pitchWithMap and rotateWithMap are off, as in JS, so the labels stay upright and flat to the screen.

The value comes from the SDK, not the JS expression

The JS value wraps dataValue in a to-unit expression that treats the wind speed as a temperature and converts it from Celsius to Fahrenheit. The Android label uses the plain Expression.variable("dataValue"). The SDK has already converted that value from the wind layer’s own units into the map’s speed unit.

The demo adds three controls the JS example does not have:

  • Show names rebuilds the query layer with or without the name block. It starts on.
  • Label size scales both blocks and the gap between them, from half to twice the JS size.
  • Show units sets MapboxMapController.showTextLabelUnits, so 12 reads 12 mph. The labels reformat without being sampled again.

JS also sets fadeOpacity to false. Android has no such setting, so the labels fade in as symbols normally do.

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