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 )
Angemeldete Mitglieder können Beiträge verfassen, Updates folgen und mehr. Neu hier? Registriere ein kostenloses Konto.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.