Display a map

Maps specify how geographic data is organized and how it should be communicated to your app users. Each instance of a map (ArcGISMap) represents an individual map you can display for your users. To display a map you must assign it to a map view (MapView). In an MVC architecture, the map represents the model tier and the map view represents the view tier. The map and map view work together to visualize the geographic data on a screen.

Users can interact with the map and its layers using the map view's built-in navigation tools. You have many ways to enhance this experience by configuring the look and feel of the map and adding business logic to these user interactions.

Open a map

You can open a map by creating it from a web map or from a mobile map package.

Create the map object from a web map

Web maps can be accessed using either their URL or directly from a portal using their portal item ID. Both methods are described here along with the authentication process required to access the map if it or its data is not public.

Using a web map URL

You can construct the map object from one of the map’s URL strings as follows:

ArcGISMap map = new ArcGISMap("URL/to/webmap");

The map constructor supports these three URL formats:

  • The map viewer URL—For example, https://www.arcgis.com/home/webmap/viewer.html?webmap=69fdcd8e40734712aaec34194d4b988c. The URL is provided in the browser's address bar when a web map is created or viewed using the ArcGIS.com map viewer.
  • The item details URL—For example, https://www.arcgis.com/home/item.html?id=69fdcd8e40734712aaec34194d4b988c. This URL is found in the address bar when you're viewing the details page for an item presented in My Content in ArcGIS.com.
  • The item data URL—For example, https://www.arcgis.com/sharing/rest/content/items/69fdcd8e40734712aaec34194d4b988c/data?. This is the address of the JSON string that represents the information to display the map.

If the map is not public, the API’s authentication challenge handler automatically requests that the user provides his credentials.

Using a web map portal item

You can construct the map object using the map's portal item ID. You can find this 32 character ID within any of the three URLs described above. For example, here is a map that's identified by the item ID of 69fdcd8e40734712aaec34194d4b988c.

Web map details page

  1. Create the portal object by providing the URL string to the portal. In the example below, the public map is accessed from ArcGIS Online (www.arcgis.com).

    //construct the portal from the URL of the portal
    Portal portal = new Portal("http://www.arcgis.com");

  2. Construct the portal item object by providing the portal and the item ID string for the map.

    //construct a portal item from the portal and item ID string
    PortalItem mapPortalItem = new PortalItem(portal, "e229d715f7ca4fa980308549fb288165");

  3. Pass the portal item to the map constructor.

    //construct a map from the portal item
    ArcGISMap map = new ArcGISMap(mapPortalItem);

Upon completion of this code, neither the portal, portal item, nor the map are loaded. These objects will be loaded when you pass the map to the map view or if you load them explicitly. See the loadable pattern topic for more information. You can override any of the map's properties by setting their value before the map is loaded.

Authentication

If the map or its layers are not public, you need to provide credentials to access them. In these cases you can either rely on the API’s authentication challenge handler to prompt the user for their credentials or you can provide your own login facility and pass the credentials to the portal's setCredentials method as described in the Access the ArcGIS platform topic.

Create a map object from a mobile map package

A mobile map package is a file object (.mmpk) created in ArcGIS Pro. It is a transport mechanism for maps, their layers, data, networks, and locators. A mobile map package can be sideloaded onto a device by email, or by platform-specific transfer mechanism, or it can be downloaded from a portal to the device.

Note:

StreetMap Premium also provides ready-to-use and regularly updated mobile map packages that include a street map, locator, and network dataset for areas throughout the globe. For details, see Add StreetMap Premium data.

Each mobile map package can contain one or more maps that can be displayed in a map view. For more information, see creating mobile map packages.

  1. Obtain the file path to the mobile map package.

    // The mobile map package has been placed in the apps documents folder
    File mmpkFile = new File(Environment.getExternalStorageDirectory(), dataPath + "CaliforniaNevada.mmpk");
    String mmpkPath = mmpkFile.getAbsolutePath();

  2. Construct the mobile map package object using the file path.

    final MobileMapPackage mobileMapPackage = new MobileMapPackage("path/to/file/.mmpk");

  3. The mobile map package must be loaded into the app before the maps themselves can be accessed. Once the mobile map package is loaded, any of its maps can be assigned to the map view to be displayed.

    mobileMapPackage.addDoneLoadingListener(() -> {
      if (mobileMapPackage.getLoadStatus() == LoadStatus.LOADED) {
        System.out.println("Number of maps = " + mobileMapPackage.getMaps().size());
        // In this case the first map in the array is obtained
        ArcGISMap mobileMap = mobileMapPackage.getMaps().get(0);
      } else {
        // If loading failed, deal with failure depending on the cause...
      }
    });
    mobileMapPackage.loadAsync();

Upon completion of this code the map is not loaded. You can override any of the map's properties by setting their value before the map is loaded. See the loadable pattern topic for more information.

Display the map in a map view

To display a map, you assign it to a map view. Each map view can display a different visible area of the map, can be configured in different ways, and can be designed to respond differently to user gestures. Assign a map to a map view as follows:

mapView.setMap(map);

Assigning a map to a map view initiates the map’s load cycle. When that cycle completes, the map view initiates the load cycle on the map’s layers in order to draw them. For more information loading resources (load cycles), see Loadable pattern of asynchronous resources. You can monitor the loading of the individual layers using the map view's LayerViewStateChangedListener.

You can load the map into your app before assigning it to a map view. This is useful if you want to validate the content of the map or you want to access any content or properties in the map without displaying it. For example, this code loads the map explicitly and checks if the map contains bookmarks before it displays the map in the map view.

map.addDoneLoadingListener(new Runnable() {
  @Override
  public void run() {
    if (map.getLoadStatus() == LoadStatus.LOADED) {
      // Once map is loaded, can check its properties and content
      if (map.getBookmarks().size() > 0) {
        // For example, show UI and allow user to choose a map bookmark...
      }
    } else {
      // If loading failed, deal with failure depending on the cause...
      dealWithLoadFailure();
    }
  }
});
map.loadAsync();

Monitor layer loading

Assigning a map to a map view or explicitly loading a map triggers loading of the map's basemap and operational layers. Each time the state of a layer changes, the map view's LayerViewStateChangedListener is triggered. Examine the layer's view status to determine whether a layer is active, loading, not visible, out of scale, or whether an error has occurred with the layer's loading process.

mapView.addLayerViewStateChangedListener(new LayerViewStateChangedListener() {
  @Override
  public void layerViewStateChanged(LayerViewStateChangedEvent layerViewStateChangedEvent) {
    // Each layer may have more than one layer view state.
    StringBuilder layerStatuses = new StringBuilder();
    for (LayerViewStatus status : layerViewStateChangedEvent.getLayerViewStatus()) {
      if (layerStatuses.length() > 0) {
        layerStatuses.append(",");
      }
      layerStatuses.append(status.name());
    }

    showMessage(String.format("Layer '%s' status=%s", layerViewStateChangedEvent.getLayer().getName(),
        layerStatuses.toString()));
  }
});

Monitor map drawing

If your users pan or zoom the map or the business logic in your app changes the visible area of the map, then new map content will need to be drawn. There will be a short time delay before this map drawing phase is completed. Your app may need to know that the drawing is complete. For example, you may want your app to take a snapshot, or screenshot, of the map only when the drawing has finished.

Use the map view's DrawStatusChangedListener to detect whether the map drawing is in progress or has completed. For example, this code displays a progress bar if the drawing is still in progress.

For example, this code displays a progress bar while drawing is in progress.

mMapView.addDrawStatusChangedListener(new DrawStatusChangedListener() {
    @Override
    public void drawStatusChanged(DrawStatusChangedEvent drawStatusChangedEvent) {
        if(drawStatusChangedEvent.getDrawStatus() == DrawStatus.IN_PROGRESS){
            progressBar.setVisibility(View.VISIBLE);
            Log.d("drawStatusChanged", "spinner visible");
        }else if (drawStatusChangedEvent.getDrawStatus() == DrawStatus.COMPLETED){
            progressBar.setVisibility(View.INVISIBLE);
        }
    }
});

Navigate the map

When a map is first loaded into a map view, it's displayed at a geographical location defined by the map's initial view point. User's can then pan or zoom the map with a range of gestures that are built into the map view. You can access the visible area of the map as a polygon returned by the map view's getVisibleArea method. The visible area is returned as a polygon, and not an envelope, because the map may be rotated and each corner of the map may contain unique x-y coordinates.

Polygon polygon = mapView.getVisibleArea();

As a developer you can programmatically set the map's visible area in your app by calling one of the map view's many setViewpoint methods. Many options are available to choose from to allow you to:

  • Rotate the map to a specified angle.
  • Zoom the map to the specified scale.
  • Zoom or pan the map so that a given geometry fits the visible area of the map view.
  • Zoom or pan the map to a specified location.
  • Zoom or pan the map to a specific view point. You can define a view point using a:
    • Center and scale
    • Center, scale, and rotation
    • Latitude, longitude, and scale
    • Target extent
    • Target extent and rotation

For example, the code that follows sets the view point to a specific lat, long, and scale with an animation that lasts two seconds. Each method returns a boolean value so you can detect if the animation was interrupted by the user.

Viewpoint viewpoint = new Viewpoint(27.3805833, 33.6321389, 6E3);

final ListenableFuture<Boolean> viewpointSetFuture = mapView.setViewpointAsync(viewpoint, 2);
viewpointSetFuture.addDoneListener(new Runnable() {
  @Override
  public void run() {
    try {
      boolean completed = viewpointSetFuture.get();
      if (completed) showMessage("Animation completed successfully");
    } catch (InterruptedException e) {
      showMessage("Animation interrupted");
    } catch (ExecutionException e) {
      // Deal with exception during animation...
    }
  }
});

Configure the map view

You can enhance your user's map experience by showing the device's location, rotating the map display, or making the world map seamless.

Show the device's location (display the user's current location)

Many devices provide information about their location through Wi-Fi, cellular networks, or GPS. The device's operating system passes its location to the map view so you can display and track the device on a map. The map view always tries to get the most accurate location available but the reported location could be a best approximation based on signal strength, satellite positions, and other factors. By default, the map view displays the location with a blue, round symbol and a semi-transparent blue circle around this symbol to indicate the range of accuracy.

The display of the location on a map, the symbol used, the animation, and the autopan behavior are managed by an instance of LocationDisplay. Each MapView has its own instance of a location display.

Start displaying the device's location as follows:

LocationDisplay locationDisplay = mapView.getLocationDisplay();
locationDisplay.addDataSourceStatusChangedListener(new LocationDisplay.DataSourceStatusChangedListener() {
  @Override
  public void onStatusChanged(LocationDisplay.DataSourceStatusChangedEvent dataSourceStatusChangedEvent) {
    if (dataSourceStatusChangedEvent.getSource().getLocationDataSource().getError() == null) {
      showMessage("Location Display Started=" + dataSourceStatusChangedEvent.isStarted());
    } else {
      // Deal with problems starting the LocationDisplay...
    }
  }
});
locationDisplay.startAsync();

Note:

Apps using LocationDisplay must be granted location permissions as described in Google's documentation for requesting app permissions.

For details and additional options for displaying a user's location, such as displaying tracks or changing the symbol, see Show device location in this guide. Also see LocationDisplay in the API Reference.

Enable wrap around

Most flat representations of the earth extend up to 180 degrees east and west longitude and make it difficult to visualize areas that span across the 180th meridian. As we know the world is spherical and does not end at the 180th meridian. Enabling wrap around in the map view displays a 2D map extending seamlessly across the 180th meridian. For more information, see the wrap around maps topic.

// wraparound is enabled if layers within map support it
mapView.setWrapAroundMode(WrapAroundMode.ENABLE_WHEN_SUPPORTED);

Note:

If your map has wrap around enabled and you're working with map locations, map extents, or are editing or sketching geometries with a map, you must normalize the geometries.

Note:

Some maps do not support wrap around; maps that do support wrap around will automatically be displayed in wrap around

Rotate the map

You may not want your map to display in a North-South direction in your device. You can reorient your map in the map view by setting the viewpoint rotation. A positive rotation value rotates the map in an counterclockwise and a negative rotation value rotates the map in a clockwise direction.

final ListenableFuture<Boolean> viewpointSetFuture = mapView.setViewpointRotationAsync(90);
viewpointSetFuture.addDoneListener(new Runnable() {
  @Override
  public void run() {
    try {
      boolean completed = viewpointSetFuture.get();
      if (completed)
        showMessage("Rotation completed successfully");
    } catch (InterruptedException e) {
      showMessage("Rotation interrupted");
    } catch (ExecutionException e) {
      // Deal with exception during animation...
    }
  }
});

Enhance the user's map interaction

You can provide extra functionality as your users interact with the map by implementing your own map touch listener. Each method on your listener will receive the touch event information at the position that the user interacted with the screen. You just need to add code within the method to use these coordinates.

The easiest way to do this is to make use of the existing DefaultMapViewOnTouchListener.

  1. Create a class that extends the DefaultMapViewOnTouchListener.
    class MapSingleTapListener extends DefaultMapViewOnTouchListener {
  2. Override the methods corresponding to the gestures you want to change the behaviour of. In this example, the single-tap gesture is changed to display the tapped location in map coordinates by overriding onSingleTapConfirmed.
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
      Point mapPoint = mapView.screenToLocation(new android.graphics.Point((int)e.getX(), (int)e.getY()));
      showMessage(String.format("User tapped on the map at (%.3f,%.3f)", mapPoint.getX(), mapPoint.getY()));
      return true;
    }
  3. Set an instance of your new listener class onto the MapView.
    mapView.setOnTouchListener(new MapSingleTapListener(context, mapView));
Note:

Alternatively, you can directly implement the MapView.OnTouchListener interface, and handle all gestures yourself.

Take a snapshot of the map

Take a snapshot, or screen capture, of the visible area of a map using the map view's exportImageAsync method. Use the image within the app or store it in a file to be shared, printed, or included in other documents.

The code below demonstrates how to save the exported Bitmap, returned from the exportImageAsync method future, to a file in the Pictures directory of the devices local storage. Note that this code will require the WRITE_EXTERNAL_STORAGE Android permission.

final ListenableFuture<Bitmap> exportImageFuture = mapView.exportImageAsync();
exportImageFuture.addDoneListener(new Runnable() {
  @Override
  public void run() {
    try {
      // Get the resulting Bitmap from the future
      Bitmap bitmap = exportImageFuture.get();

      if (bitmap != null) {
        // Create a File to write the Bitmap into
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "map.png");
        FileOutputStream fileOutputStream;
        try {
          // Write the Bitmap into the file and close the file stream.
          fileOutputStream = new FileOutputStream(file);
          bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
          fileOutputStream.close();
        } catch (IOException e) {
          // Deal with exception writing file...
        }
      }

    } catch (InterruptedException | ExecutionException e) {
      // Deal with exception during export...
    }
  }
});

Note:

If you want to store this image as a thumbnail of a portal item, be aware that the size limit of a thumbnail is 1 MB. Check the image size before saving the image as a thumbnail and, if necessary resize it.