Select to view content in your preferred language

Caching vector tile layer data not possible?

784
6
08-30-2022 07:01 AM
JulianBissekkou
Emerging Contributor

We are developing an android and iOS App and we would like to improve the performance of the map. In particular the loading speed of the vector tiles that we use.

 

Our setup is really easy. We have only one layer which is a `ArcGISVectorTiledLayer`. When the map is visible, the data is loaded and displayed. When the map is visible on another screen, the map loads all the data again and the user has to wait.

 

We would like to cache the vector tile data between maps that are displayed in our apps.

Is that possible?

What other options of caching are available?

0 Kudos
6 Replies
Shubham_Sharma
Esri Contributor

@JulianBissekkou You can export the tiles from an online vector tile service or a portal item using the ExportVectorTilesJob . 

public ExportVectorTilesJob exportVectorTiles​(
ExportVectorTilesParameters exportVectorTilesParameters,
String vectorTileCachePath
)
The job returns a new export vector tiles job that can be used to generate and download a vector tile package (.vtpk) containing the vector tiles specified by the parameters.
 

Check out the Android sample "Export vector tiles" here

 

0 Kudos
JulianBissekkou
Emerging Contributor

Thanks for reaching out.

I did a quick test and there are a few problems that I found.

When exporting the data I get an error:
"Portal item is missing for style resources. Cannot export an item resource cache."

It might be the case that there are no style ressources. That's a valid state, correct?

 

Second problem: 
I would like to create a vector layer with the cache and the url so that the vector layer can quickly show whats already cached, but if needed it can request new data based on the url.

I don't see a constructor of AGSVectorTiledLayer with url and cache.

0 Kudos
JulianBissekkou
Emerging Contributor

Not providing `itemResourceCacheDownloadDirectory` resolved the first issue 🙂 

`

Shubham_Sharma
Esri Contributor

Use the available constructor:  API ref

 

ArcGISVectorTiledLayer​(java.lang.String dataSourceUri)

 

It creates a new ArcGISVectorTiledLayer from either the ArcGIS Vector Tile Service, Vector Tile Style Sheet indicated by the given URI, or the path to a Local Vector tile package(VTPK).

0 Kudos
JulianBissekkou
Emerging Contributor

I know this constructor but in my case I want to create vector layer that fetches data from remote but also using the existing data it reads from a cache.

 

To be more specific I want to explain my use case:

In my App I have a few different places where a map is shown. It's mostly centered on the users location, but the user is able to move around the map, zoom in or zoom out.
I don't want the map to always load the tiles again when a new map is created. I would like to keep the data in cache and use it if possible, but if the user decides to move around i want to load new data.

 

This is currently not possible in a efficient way, or am I wrong? I can download a specific part of a map and create a layer from that data, but my user is not able to scroll somewhere else outside of the downloaded area. 
Edit: I know that I can create 2 layers. One with the url and one with the cache, but then we will still load redundant data. I would like to reuse the already fetched data from my vector tiled layer.

0 Kudos
Shubham_Sharma
Esri Contributor

Hey @JulianBissekkou, I would like to make sure I'm understanding your problem correctly. You would like to have a local vtpk cache to load a map until the user scrolls outside the cached area, which then map fetches the online URL layer data. 

Below is an approach that should help, you might need to tweak according for your app's needs:

  • Load the ArcGISVectorTiledLayer to the map using the local cached vtpk file
  • Add a MapView viewpoint changed listener, so check if the user has "panned" outside of the cached layer extent. (map grey area)
  • If the current viewpoint geometry overlaps the map's geometry, this means you will need to load in additional layer data. You can check for geometry relationships using GeometryEngine
  • Load the online URL layer now, since additional layer data is needed. 
// loads the vector tile layer cache.
val vectorTiledLayer = ArcGISVectorTiledLayer(getExternalFilesDir(null)?.path + "/myVectorTiles.vtpk")
vectorTiledLayer.loadAsync()
vectorTiledLayer.addDoneLoadingListener {
    // if vector tiles failed to load, show message
    if (vectorTiledLayer.loadStatus == LoadStatus.FAILED_TO_LOAD) {
        showError(vectorTiledLayer.loadError.message.toString())
    }
}
// add the cached tile layer to the map
mapView.map.basemap.baseLayers.add(vectorTiledLayer)
mapView.map.loadAsync()
mapView.addViewpointChangedListener {
    // if the map is loaded
    if (mapView.map.loadStatus == LoadStatus.LOADED) {
        // get the current viewpoint extent
        val currentViewpoint = mapView.getCurrentViewpoint(Viewpoint.Type.BOUNDING_GEOMETRY)
        // get the cache map's extent
        val mapExtent = vectorTiledLayer.fullExtent
        // check if the user's viewpoint overlaps the cache map's extent
        if (GeometryEngine.overlaps(currentViewpoint.targetGeometry, mapExtent)) {
            Log.e(TAG, "Out of bounds")
            // load online resource now, since user has panned to the map's bounding extent
            // switch to use online basemap, and set the viewpoint as current extent
            mapView.map = ArcGISMap(Basemap(BasemapStyle.ARCGIS_STREETS_NIGHT))
            mapView.setViewpoint(currentViewpoint)
        }
    }
}

 

0 Kudos