How to implement Map tile caching?

5480
6
Jump to solution
11-18-2014 05:12 PM
MarkHine
New Contributor

I am having trouble trying to implement caching of map tiles to be used if the user doesn't have a network connection.

I have read through this sample code and attempted to implement it:

Export Tile Cache | ArcGIS for Developers

But there are a couple of problems I have encountered:

  1. The map seems to be caching a large area of the map and I would like to only download a small area around the devices current location.
  2. Where would I get the correct tile URL. At the moment I am using the sample url http://sampleserver6.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer
  3. How would I retrieve the level of detail the map is currently at? So that I can add it to the ExportTileCacheParameters.

Ideally the functionality I am looking for is the arcgis map to maintain its own internal cache automatically. I could specify the maximum size of the cache and the arcgis map automatically caches map sections that have been downloaded, keeping sections in the cache that have been most recently viewed.

Does arcgis support this notion or do I need to manage a map cache manually such the sample code above? if so, how would you recommend going about this?

0 Kudos
1 Solution

Accepted Solutions
PuneetPrakash
Esri Contributor

you can put a status listener on the TileLayer and listen for layer Initialized event when it becomes available from online. And before adding it to the mapView you can get the values of Full Extent and Min/Max scales. Then set these values on the MapView. To set the Extent use setMaxExtent() method.

 tilelayer.setOnStatusChangedListener(new OnStatusChangedListener() {
          
          @Override
          public void onStatusChanged(Object source, STATUS status) {
            // TODO Auto-generated method stub
            if(source == tilelayer && status== STATUS.INITIALIZED){
              
              mTileLayerExtent = tilelayer.getFullExtent();
              mTileLayerMinScale = tilelayer.getMinScale();
              mTileLayerMaxScale = tilelayer.getMaxScale();
            }
          }
        });

            mMapView.setMaxExtent(mTileLayerExtent);
            mMapView.setMinScale(mTileLayerMinScale);
            mMapView.setMaxScale(mTileLayerMaxScale);

View solution in original post

0 Kudos
6 Replies
PuneetPrakash
Esri Contributor

Hi Mark,

Here are some answers to the problems that you have encountered,

1. The ExportTileCacheTask will the cache the area of the map specified by the Geometry areaOfInterest parameter in the ExportTileCacheParameters constructor.

ExportTileCacheParameters(boolean createAsTilePackage, int minLevelOfDetail, int maxLevelOfDetail, Geometry areaOfInterest, SpatialReference inSpatialRef)

The sample code is using the visible area of the map on screen as the extent to be downloaded. You can specify the envelope of the size you want around device's current location. Please make sure you are using our latest release 10.2.5 as we addressed a bug related areaOfInterest parameter.

2. For taking ArcGIS online basemaps offline please take a look at:

https://developers.arcgis.com/android/guide/create-an-offline-map.htm

In the "Include a Basemap" section it has a link to a group (http://links.esri.com/rtbasemaps) which list the services you need to use for taking a ArcGIS Online basemap offline.

These are hosted on http://tiledbasemaps.arcgis.com/ and password protected. You will need to be a part of an organization to be able to use them.

3. To get the current level of detail of the map, you can call getCurrentLevel() method on the ArcGISTiledMapServiceLayer instance,

 int currentLOD = tiledlayer.getCurrentLevel();

We do not support the maintenance of downloaded tile cache's out of the box. That functionality is up to you to implement. One of that ArcGIS apps Collector implements this Go offline—Collector for ArcGIS | ArcGIS . You can figure out the size of the tile cache to be downloaded by using ExportTileCacheTasks estimateTileCacheSize() method,estimateTileCacheSize

  public Future<Long> estimateTileCacheSize(final ExportTileCacheParameters params, final CallbackListener<Long> callback) {

and then proceed to download the tilecache. You can store the information such as the extent and LOD for the local tile cache on disk to figure out what areas you have covered locally in respect to the online map extent being viewed.

0 Kudos
MarkHine
New Contributor

Hi Puneet,

Thanks for you reply.

I have managed to download & display a cached map tile in the map view now. But I have another question:

When I have the cached map loaded in the map view (with only level 16 cached), the map view can only pan an area slightly larger than the cached map area. So when the user reconnects to the network and I call reinitializeLayer(...) on the ArcGISTiledMapServiceLayer, the online layer loads but the map view is unable to pan any further than the area of the cached map.

How can I go about solving this issue? Would I have to set the map view extent so that it is able to pan for example the whole world?

Thanks,
Mark

0 Kudos
PuneetPrakash
Esri Contributor

Since you are downloading a local tile cache and adding it as the first layer to the MapView, the MapView is getting limited by the min / max scale on the localTiledLayer. You can try using the workflow illustrated in the sample and add the Online tiled layer as the first layer in the Mapview, and when you add the localTiledLayer, set the visibility of the online tiled layer to false. That way by switching the visibilities you can easily toggle between the two.

mMapView.getLayers()[0].setVisible(false);

mMapView.getLayers()[1].setVisible(true);

0 Kudos
MarkHine
New Contributor

I do have the ArcGISTiledMapServiceLayer added first. Then the ArcGISLocalTiledLayer will be added if there is a network connection.
So the flow in the case of no network connection when the map activity is opened is:
The ArcGISTiledMapServiceLayer is created but fails to initialise due to no network connection
The ArcGISLocalTiledLayer is created with the last cached map tile
Then the user gains network connection and I call reinitializeLayer() on the ArcGISTiledMapServiceLayer

Is there a way to set the min / max scale that you mentioned to the whole world? Or is there a better way to do this?

0 Kudos
PuneetPrakash
Esri Contributor

you can put a status listener on the TileLayer and listen for layer Initialized event when it becomes available from online. And before adding it to the mapView you can get the values of Full Extent and Min/Max scales. Then set these values on the MapView. To set the Extent use setMaxExtent() method.

 tilelayer.setOnStatusChangedListener(new OnStatusChangedListener() {
          
          @Override
          public void onStatusChanged(Object source, STATUS status) {
            // TODO Auto-generated method stub
            if(source == tilelayer && status== STATUS.INITIALIZED){
              
              mTileLayerExtent = tilelayer.getFullExtent();
              mTileLayerMinScale = tilelayer.getMinScale();
              mTileLayerMaxScale = tilelayer.getMaxScale();
            }
          }
        });

            mMapView.setMaxExtent(mTileLayerExtent);
            mMapView.setMinScale(mTileLayerMinScale);
            mMapView.setMaxScale(mTileLayerMaxScale);
0 Kudos
MarkHine
New Contributor

Thank you very much for your help. I was able to implement the simple cache as described above

0 Kudos