Data class:data class ArcGisMapData(var map: ArcGISMap, var graphicOverlays: List<GraphicsOverlay>, var locationDisplay: LocationDisplay)
Composable function:@Composablefun EsriMap(map:ArcGISMap,locationDisplay:LocationDisplay,graphicsOverlays:List<GraphicOverlay>){val mapState by mapViewModel.mapStateFlow.collectAsStateWithLifeCycle()MapView(modifier = Modifier .fillMaxSize(), arcGISMap = mapState.map, graphicsOverlays = mapState.graphicOverlays, locationDisplay = mapState.locationDisplay)
ViewModel Classclass MapViewModel : ViewModel() {private val _mapStateDataFlow = MutableStateFlow(ArcGisMapData(map = ArcGISMap(Basemap(WebTiledLayer.create("https://tile.openstreetmap.org/{level}/{col}/{row}.png"))), graphicOverlays = listOf(GraphicsOverlay()),locationDisplay = LocationDisplay())val mapStateFlow = _mapStateDataFlow.asStateFlow()init{viewmodelScope.launch{val wmsService =WmsService(url = "http://geodata.nationaalgeoregister.nl/cbsprovincies/ows?SERVICE=WMS&request=Getcapabilities")wmsService.load().onSuccess { val wmsLayer = WmsLayer(wmsService.serviceInfo!!.layerInfos)wmsLayer.load().onSuccess { Timber.d("load success")// TODO("Load new instance of ArcGIS Map with wms added to operational layer") }.onFailure { exception -> Timber.e(exception, "Failed to load WMS layer" )// Handle error, e.g., show a message to the user }}.onFailure { e -> Timber.e(e, "Failed to load WMS Service: ${entry.path}" )}}}
@NishanKhadka Thanks for clarifying! I believe you would need to retrieve the sublayerInfos which should help load all the WMS layers from the service without providing the layerName:
val layerInfos = wmsService.serviceInfo!!.layerInfos[0].sublayerInfos val wmsLayer = WmsLayer(layerInfos) wmsLayer.load().onSuccess { // Add to map's operational layers... }
Just to note, each layerInfo may contain subLayers, and the subLayers may contain additional subLayers. I would inspect the service you are using to configure which layers to/not to display on the MapView.
@Shubham_Sharma Thank you for your guidance! It now make sense to use the WmsService class to load the layers available and configure which layers/sublayers to load on the map. Then load it using the WmsLayer class. Accepting this as solution! Thanks again!
Thank you for the quick response @Shubham_Sharma, I have the context and apikey for ArcGIS environement provided from the app's application class.What I am struggling with is displaying the WMS overlay on the map. For instance, if I follow the sample example provided and add the WMS layer the following way:
val map = ArcGISMap(Basemap(WebTiledLayer.create("https://tile.openstreetmap.org/{level}/{col}/{row}.png")))val wmsLayer = WmsLayer(url = "https://nowcoast.noaa.gov/geoserver/observations/weather_radar/wms",layerNames = listOf("conus_base_reflectivity_mosaic"))map.operationalLayers.add(wmsLayer)_mapStateDataFlow.update { dataState -> dataState.copy(map = map)}wmsLayer.load().onSuccess { Timber.d("load successful")}.onFailure { Timber.d("Failed to load")}
It loads and displays the WMS layer on the map.
But, if I do not know the layerNames, then I will need to use
https://nowcoast.noaa.gov/geoserver/observations/weather_radar/wms?service=WMS&request=GetCapabilities
as specified in WmsLayer (ArcGIS Runtime SDK for Android 100.15.6)
But when I do the following:
val map = ArcGISMap(Basemap(WebTiledLayer.create("https://tile.openstreetmap.org/{level}/{col}/{row}.png")))val wmsService = WmsService(url = "https://nowcoast.noaa.gov/geoserver/observations/weather_radar/wms?service=WMS&request=GetCapabilities")wmsService.load().onSuccess { if (wmsService.serviceInfo != null) {val wmsLayer = WmsLayer(wmsService.serviceInfo!!.layerInfos) wmsLayer.isVisible = true map.operationalLayers.add(wmsLayer)_mapStateDataFlow.update { dataState -> dataState.copy(map = map)} wmsLayer.load().onSuccess { Timber.d("load successful")}.onFailure { Timber.d("Failed to load")} }}
The log comes as load successful, but I don't see any overlay on the map. I have attached screenshots below of when I do it as in the Kotlin Sample with known layerName (WMS overlay is displayed) and another where I do not know the layerNames (WMS overlay not displayed). Please do let me know if I am missing something.One thing I noticed is : when I do it as in the sample - and log the url from the WmsLayer instance,
val wmsLayer = WmsLayer(url = "https://nowcoast.noaa.gov/geoserver/observations/weather_radar/wms",layerNames = listOf("conus_base_reflectivity_mosaic"))Timber.d("url is ${wmsLayer.url}") //prints above url
I get the provided url "https://nowcoast.noaa.gov/geoserver/observations/weather_radar/wms" from it.
But when I do the same thing after creating the WmsLayer from WmsLayer(wmsService.serviceInfo!!.layerInfos),
val wmsService = WmsService(url = "https://nowcoast.noaa.gov/geoserver/observations/weather_radar/wms?service=WMS&request=GetCapabilities")wmsService.load().onSuccess { if (wmsService.serviceInfo != null) {val wmsLayer = WmsLayer(wmsService.serviceInfo!!.layerInfos) Timber.d("url is ${wmsLayer.url}") // prints empty string}
I get empty url. I wonder if that's why I do not get the overlays displayed as there is no url to fetch from.
While reading the code I noticed that you are using a LocationDisplay with the Composable MapView. To be able to set a LocationDisplay, you would need to define an ApplicationContext:
ArcGISEnvironment.applicationContext = this // Alternatively, you can set the application context using the // LocationDisplay helper function from a Composable scope: // Checks that ArcGISEnvironment.applicationContext is set and if not, sets one. val myLocationDisplay = rememberLocationDisplay()
I can load a WMS layer by modifying your code using the above changes:
import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.ViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import com.arcgismaps.ApiKey import com.arcgismaps.ArcGISEnvironment import com.arcgismaps.mapping.ArcGISMap import com.arcgismaps.mapping.Basemap import com.arcgismaps.mapping.layers.WebTiledLayer import com.arcgismaps.mapping.layers.WmsLayer import com.arcgismaps.mapping.layers.WmsService import com.arcgismaps.mapping.view.GraphicsOverlay import com.arcgismaps.mapping.view.LocationDisplay import com.arcgismaps.toolkit.geoviewcompose.MapView import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // authentication with an API key or named user is // required to access basemaps and other location services ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.API_KEY) // application context is required for LocationDisplay ArcGISEnvironment.applicationContext = this setContent { SampleAppTheme { EsriMap() } } } @Composable fun EsriMap() { val mapViewModel: MapViewModel = viewModel() val mapState by mapViewModel.mapStateFlow.collectAsStateWithLifecycle() MapView( modifier = Modifier .fillMaxSize(), arcGISMap = mapState.map, graphicsOverlays = mapState.graphicOverlays, locationDisplay = mapState.locationDisplay ) } } class MapViewModel : ViewModel() { private val _mapStateDataFlow = MutableStateFlow( ArcGisMapData( map = ArcGISMap(Basemap(WebTiledLayer.create("https://tile.openstreetmap.org/{level}/{col}/{row}.png"))), graphicOverlays = listOf(GraphicsOverlay()), locationDisplay = LocationDisplay() ) ) val mapStateFlow = _mapStateDataFlow.asStateFlow() init { viewModelScope.launch { val wmsService = WmsService(url = "http://geodata.nationaalgeoregister.nl/cbsprovincies/ows?SERVICE=WMS&request=Getcapabilities") wmsService.load().onSuccess { val wmsLayer = WmsLayer(wmsService.serviceInfo!!.layerInfos) wmsLayer.load().onSuccess { Log.e("TAG", "load success") }.onFailure { exception -> Log.e("TAG", "${exception.message}: Failed to load WMS layer") } }.onFailure { exception -> Log.e("TAG", "${exception.message}: Failed to load WMS layer") } } } } data class ArcGisMapData( var map: ArcGISMap, var graphicOverlays: List<GraphicsOverlay>, var locationDisplay: LocationDisplay )
Signed in members can post, follow updates, and more. New here? Register a free account.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.