Offline Map doesn't show all layers

553
0
01-07-2021 02:12 PM
Labels (2)
JohnMeah
New Contributor

Hi,

    I'm new to The Esri Community and Android SDK programming.  I'm having an issue where I need to offline a section of the map as outlined in this tutorial - https://developers.arcgis.com/android/latest/guide/take-map-offline-on-demand.htm but I'm using inherited code outlined below to do so and the output map doesn't show all of the layers of the maps and throws an exception:

I/System.out: Non Outage Completion cannot be taken offline
Error : com.esri.arcgisruntime.ArcGISRuntimeException: Illegal state: Unable to support duplicate feature layers already exists

I use this code to generate the map and the exception: 

 

 

    fun generateOfflineMap() {
        // create a progress dialog to show map download progress
        progressDialog!!.setTitle("Generate Offline Map")
        progressDialog!!.setMessage("Downloading map...")
        progressDialog!!.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL)
        progressDialog!!.isIndeterminate = false
        progressDialog!!.setCanceledOnTouchOutside(false)
        progressDialog!!.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel") { dialog, which ->
            downloadMsg!!.visibility = View.GONE
            mGraphicsOverlay!!.graphics.clear()
            mapdownloadJob!!.cancel()
            //set the flag to false to re-select the download area for consecutive downloads
            isMapDownloadAreaSelected = false
            isMapDownloadInProgress = false
            dialog.dismiss()
        }
        if (!isMapDownloadAreaSelected) {
            downloadMsg!!.visibility = View.VISIBLE
            // create a graphics overlay for the map view
            mGraphicsOverlay = GraphicsOverlay()
            mapView!!.graphicsOverlays.add(mGraphicsOverlay)

            // create a graphic to show a box around the extent we want to download
            mDownloadArea = Graphic()
            mGraphicsOverlay!!.graphics.add(mDownloadArea)
            val simpleLineSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 2F)
            mDownloadArea!!.symbol = simpleLineSymbol
            // upper left corner of the area to take offline
            minScreenPoint = Point(200, 200)
            // lower right corner of the downloaded area
            maxScreenPoint = Point(mapView!!.width - 200,
                    mapView!!.height - 200)
            // convert screen points to map points
            minPoint = mapView!!.screenToLocation(minScreenPoint)
            maxPoint = mapView!!.screenToLocation(maxScreenPoint)
            // use the points to define and return an envelope
            if (minPoint != null && maxPoint != null) {
                val envelope = Envelope(minPoint, maxPoint)
                mDownloadArea!!.geometry = envelope
            }

            //Debugging - use this to get errors with layers and tables

            var offlineMapTask = OfflineMapTask(map);
            var minScale = mapView!!.mapScale
            val maxScale = mapView!!.map.maxScale
            val generateOfflineMapParameters = GenerateOfflineMapParameters(mDownloadArea!!.geometry, minScale, maxScale)

            val offlineMapCapabilitiesFuture: ListenableFuture<OfflineMapCapabilities> = offlineMapTask.getOfflineMapCapabilitiesAsync(generateOfflineMapParameters)
            offlineMapCapabilitiesFuture.addDoneListener {
                    val offlineMapCapabilities: OfflineMapCapabilities = offlineMapCapabilitiesFuture.get()
                    if (offlineMapCapabilities.hasErrors()) {
                        // Handle possible errors with layers
                        for ((key, value) in offlineMapCapabilities.getLayerCapabilities()) {
                            if (!value.isSupportsOffline()) {
                                println(key.getName().toString() + " cannot be taken offline\n" +
                                        "Error: " + value.getError())
                            }
                        }

                        // Handle possible errors with tables
                        for ((key, value) in offlineMapCapabilities.getTableCapabilities()) {
                            if (!value.isSupportsOffline()) {
                                println(key.tableName.toString() + " cannot be taken offline\n" +
                                        "Error : " + value.getError())
                            }
                        }
                    } else {
                        // All layers and tables can be taken offline!
                        showMessage("All layers are good to go!")
                    }
            }

            //End Debugging

            // update the download area box whenever the viewpoint changes
            mapView!!.addViewpointChangedListener { viewpointChangedEvent: ViewpointChangedEvent? ->
                if (map!!.loadStatus == LoadStatus.LOADED) {
                    // upper left corner of the area to take offline
                    minScreenPoint = Point(200, 200)
                    // lower right corner of the downloaded area
                    maxScreenPoint = Point(mapView!!.width - 200,
                            mapView!!.height - 200)
                    // convert screen points to map points
                    minPoint = mapView!!.screenToLocation(minScreenPoint)
                    maxPoint = mapView!!.screenToLocation(maxScreenPoint)
                    // use the points to define and return an envelope
                    if (minPoint != null && maxPoint != null) {
                        val envelope = Envelope(minPoint, maxPoint)
                        mDownloadArea!!.geometry = envelope
                    }
                }
            }
            // map download area selected
            isMapDownloadAreaSelected = true
        } else {
            if (!isMapDownloadInProgress) {
                progressDialog!!.progress = 0
                progressDialog!!.show()

                // delete any offline map already in the cache
                deleteDirectory(File(offlineMapDirectoryPath))
                // specify the extent, min scale, and max scale as parameters
                var minScale = mapView!!.mapScale
                val maxScale = mapView!!.map.maxScale
                // minScale must always be larger than maxScale
                if (minScale <= maxScale) {
                    minScale = maxScale + 1
                }
                val generateOfflineMapParameters = GenerateOfflineMapParameters(mDownloadArea!!.geometry, minScale, maxScale)
                // create an offline map offlineMapTask with the map
                val offlineMapTask = OfflineMapTask(mapView!!.map)

                // create an offline map job with the download directory path and parameters and start the job
                mapdownloadJob = offlineMapTask.generateOfflineMap(generateOfflineMapParameters, offlineMapDirectoryPath)
                isMapDownloadInProgress = true
                // replace the current map with the result offline map when the job finishes
                mapdownloadJob.addJobDoneListener(Runnable {
                    if (mapdownloadJob.getStatus() == Job.Status.SUCCEEDED) {
                        val result = mapdownloadJob.getResult()
                        downloadMsg!!.visibility = View.GONE
                        mGraphicsOverlay!!.graphics.clear()
                        //set the flag to false to re-select the download area for consecutive downloads
                        isMapDownloadAreaSelected = false
                        isMapDownloadInProgress = false

                        //show the map
                        mapView!!.map = result.offlineMap

                        //hide save map, show cancel map
                        //save_map.visibility = View.GONE
                        //cancel_map.visibility = View.VISIBLE

                        //hide the legend - it must be online
                        legendHeader!!.visibility = View.GONE

                        if (mAttributes != null) {
                            sharedPreferencesPseg.setString("ESDNUMBERFORSAVEDMAP", mAttributes!!.cadjobno)
                        } else {
                            sharedPreferencesPseg.setString("ESDNUMBERFORSAVEDMAP", "MAINTAB")
                        }

                        Toast.makeText(requireContext(), "Map downloaded successfully", Toast.LENGTH_LONG).show()
                    } else if (mapdownloadJob.getStatus() == Job.Status.FAILED) {
                        Toast.makeText(requireContext(), "Error in generate offline map", Toast.LENGTH_LONG).show()
                    } else if (mapdownloadJob.getStatus() == Job.Status.PAUSED) {
                        Toast.makeText(requireContext(), "Map download cancelled", Toast.LENGTH_LONG).show()
                    }
                    progressDialog!!.dismiss()
                })
                mapdownloadJob.addProgressChangedListener(Runnable { progressDialog!!.progress = mapdownloadJob.getProgress() })
                mapdownloadJob.start()
            } else {
                mapdownloadJob!!.addProgressChangedListener { progressDialog!!.progress = mapdownloadJob!!.progress }
                progressDialog!!.show()
            }
        }
    }

 

 

    When the code to display the map is called the map is displayed but with minimal detail and it appears layer(s) are left out.  I'm not sure what is causing this.  I also use this function below to open the map and wanted to provide this to see if there are errors in this code as well:

 

 

 

    private fun openOfflineMap() {
        val offlineMapPackage = MobileMapPackage(offlineMapDirectoryPath)
        offlineMapPackage.loadAsync()
        offlineMapPackage.addDoneLoadingListener {
            if (offlineMapPackage.maps.size == 0) {
                mapNotDownloadedMsg!!.visibility = View.VISIBLE
                progressBar!!.visibility = View.GONE
            } else {
                mapView!!.map = offlineMapPackage.maps[0]
                callout = mapView!!.callout
                progressBar!!.visibility = View.GONE
                //                    downloadMapIcon.setVisibility(View.GONE);
                mapView!!.visibility = View.VISIBLE
                mapView!!.onTouchListener = object : DefaultMapViewOnTouchListener(context, mapView) {
                    override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
                        if (callout.isShowing()) {
                            callout.dismiss()
                        }
                        val screenPoint = Point(Math.round(e.x), Math.round(e.y))
                        // identifyResult(screenPoint);
                        identifyandDisplayResults(screenPoint)
                        return true
                    }
                }
            }
        }
    }

 

 

Any help you can provide is much appreciated!  If there is a need for additional detail please let me know and I will provide as best I can.

Thanks,

John Meah

0 Replies