Since upgrading to 10.2.6 the onStatusChanged signal for layer objects doesn't seem to be firing. We have a basemap picker in our app and as the user selected basemaps we would use this event to make sure the basemap they picked was initialized before they could pick any other basemaps. Not doing that caused an app crash after a while.
I no longer see the onStatusChanged signal in the API documentation for the layer object now, so how can we accomplish this same thing in the new API? I do still see the same methodology I was using in the Tiled layer online example in the Samples App for 10.2.6, so I'm a little confused as to whether or not this signal is still around in the new version of the API. Here's some test code you can run to reproduce this issue. Click each of the buttons to replace the existing basemap and you will see no feedback from the onStatusChanged signal. This worked like a charm in 10.2.5.
import QtQuick 2.3
import QtQuick.Controls 1.2
import ArcGIS.Runtime 10.26
import ArcGIS.Extras 1.0
ApplicationWindow {
id: appWindow
width: 800
height: 600
title: "Test"
Map {
id: appMap
anchors.fill: parent
focus: true
ArcGISTiledMapServiceLayer {
url: "http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
}
}
Button {
anchors {
top: parent.top
right: parent.right
margins: 10
}
text: "Layer 1"
onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer")
}
Button {
anchors {
top: parent.top
left: parent.left
margins: 10
}
text: "Layer 2"
onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer")
}
Button {
anchors {
bottom: parent.bottom
right: parent.right
margins: 10
}
text: "Layer 3"
onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer")
}
Button {
anchors {
bottom: parent.bottom
left: parent.left
margins: 10
}
text: "Layer 4"
onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer")
}
function addLayer(url) {
try {
var baseLayerToInsert;
baseLayerToInsert = ArcGISRuntime.createObject("ArcGISTiledMapServiceLayer");
baseLayerToInsert.url = url;
bmLyrConnections.target = baseLayerToInsert;
appMap.insertLayer(baseLayerToInsert, 0);
appMap.removeLayerByIndex(1);
}
catch(err) {
console.log("BasemapPicker:setBaseLayer" + err.message);
}
}
Connections {
id: bmLyrConnections
onStatusChanged: {
console.log("BASEMAP STATUS: " + target.status);
if (target.status === Enums.LayerStatusInitialized) {
console.log("INITIALIZED");
}
else if (target.status === Enums.LayerStatusErrored) {
console.log(target.error);
}
}
}
}
Solved! Go to Solution.
Andy,
This looks like a bug. The statusChanged signal does exist, but for some reason it isn't in the doc and it is firing only when initializing, not once it is initialized. I'm also seeing that it works on ArcGISDynamicMapServiceLayer but not ArcGISTiledLayer, so I'm not sure if it is a bug with the layer base class or just with the tiled layer. I have filed a bug to get both the API and doc fixed up.
This is pretty hard to workaround as it is not notifying us when its status changed. The only thing I can think of is to write a short loop to check the status (the status property does work, it is the signal that is not notifying us). The below code seems to work, however, it is definitely not ideal, as you ideally wouldn't have to write a loop like this whenever you want to switch out a basemap. See line 110 below. You can tweak the number of attempts and wait time to your liking. Again, this isn't an ideal workaround, but you can use it as a base so you aren't completely stuck for the logic you are using.
// Copyright 2015 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the Sample code usage restrictions document for further information. // import QtQuick 2.3 import QtQuick.Controls 1.2 import ArcGIS.Runtime 10.26 import ArcGIS.Extras 1.0 ApplicationWindow { id: appWindow width: 800 height: 600 title: "Test" property ArcGISTiledMapServiceLayer baseLayerToInsert Map { id: appMap anchors.fill: parent focus: true ArcGISTiledMapServiceLayer { url: "http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" } } Button { anchors { top: parent.top right: parent.right margins: 10 } text: "Layer 1" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer") } Button { anchors { top: parent.top left: parent.left margins: 10 } text: "Layer 2" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer") } Button { anchors { bottom: parent.bottom right: parent.right margins: 10 } text: "Layer 3" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer") } Button { anchors { bottom: parent.bottom left: parent.left margins: 10 } text: "Layer 4" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer") } function addLayer(url) { baseLayerToInsert = ArcGISRuntime.createObject("ArcGISTiledMapServiceLayer"); baseLayerToInsert.url = url; appMap.insertLayer(baseLayerToInsert, 0); appMap.removeLayerByIndex(1); console.log(baseLayerToInsert.status) var attempts = 0; while (baseLayerToInsert.status !== Enums.LayerStatusInitialized && attempts < 10) { System.wait(500); ++attempts; } console.log(baseLayerToInsert.status, " === ", Enums.LayerStatusInitialized); } }
Andy,
This looks like a bug. The statusChanged signal does exist, but for some reason it isn't in the doc and it is firing only when initializing, not once it is initialized. I'm also seeing that it works on ArcGISDynamicMapServiceLayer but not ArcGISTiledLayer, so I'm not sure if it is a bug with the layer base class or just with the tiled layer. I have filed a bug to get both the API and doc fixed up.
This is pretty hard to workaround as it is not notifying us when its status changed. The only thing I can think of is to write a short loop to check the status (the status property does work, it is the signal that is not notifying us). The below code seems to work, however, it is definitely not ideal, as you ideally wouldn't have to write a loop like this whenever you want to switch out a basemap. See line 110 below. You can tweak the number of attempts and wait time to your liking. Again, this isn't an ideal workaround, but you can use it as a base so you aren't completely stuck for the logic you are using.
// Copyright 2015 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the Sample code usage restrictions document for further information. // import QtQuick 2.3 import QtQuick.Controls 1.2 import ArcGIS.Runtime 10.26 import ArcGIS.Extras 1.0 ApplicationWindow { id: appWindow width: 800 height: 600 title: "Test" property ArcGISTiledMapServiceLayer baseLayerToInsert Map { id: appMap anchors.fill: parent focus: true ArcGISTiledMapServiceLayer { url: "http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" } } Button { anchors { top: parent.top right: parent.right margins: 10 } text: "Layer 1" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer") } Button { anchors { top: parent.top left: parent.left margins: 10 } text: "Layer 2" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer") } Button { anchors { bottom: parent.bottom right: parent.right margins: 10 } text: "Layer 3" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer") } Button { anchors { bottom: parent.bottom left: parent.left margins: 10 } text: "Layer 4" onClicked: addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer") } function addLayer(url) { baseLayerToInsert = ArcGISRuntime.createObject("ArcGISTiledMapServiceLayer"); baseLayerToInsert.url = url; appMap.insertLayer(baseLayerToInsert, 0); appMap.removeLayerByIndex(1); console.log(baseLayerToInsert.status) var attempts = 0; while (baseLayerToInsert.status !== Enums.LayerStatusInitialized && attempts < 10) { System.wait(500); ++attempts; } console.log(baseLayerToInsert.status, " === ", Enums.LayerStatusInitialized); } }
Along with the below code, you could also add an extra check in the onClicked of the button to actually disable the button
onClicked: { enabled = false addLayer("http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer") if (appMap.layerByIndex(0).status) enabled = true }
Thanks Luke. That loop will get us past this issue …