Mapbox Android Learning Notes Offline Map

Posted by peppino on Mon, 05 Aug 2019 05:02:29 +0200

Offline

Usually, you may find that your user base is not on the grid most of the time. Maps SDK allows you to download and store pre-selected areas for use when the device is offline. The result of downloading the map is to use style, tile and other resources in the download area to generate fully functional maps.

Offline Plugin
User devices do not always have strong enough Internet connections to download and view map blocks. You may want to build an offline model in an Android project to explain this situation. Android's Mapbox offline plug-in is a convenient way to send information to Maps SDK's offline manager class and download map blocks for offline use using the manager in the background service. Once the offline download area is defined and initialized, the plug-in handles all other things for you. Because plug-ins use services, downloads continue even if the application runs in the background.

limit

An application can download multiple areas for offline use, but the total amount of offline downloads in all download areas has a maximum tiling count upper limit. SDK sets tile ceiling to 6000 tiles. Use our Tile Count Estimator to calculate the number of Tiles required for offline use cases. In the range of M25 zoom level 0-15, 6,000 tiles cover an area roughly equivalent to Greater London, while in the range of zoom level 0-9, they cover the adjacent United States. The size of these blocks on the disk will vary according to the chosen pattern.

Maps SDK does not limit the number of offline areas that can be created. Your mapbox-enabled applications will reuse tile s and resources required for multiple areas, thereby saving network traffic and disk space.

SDK does not limit download speed in offline areas, nor does it limit disk space for offline resources. These limitations will depend on the storage capacity of mobile devices and the speed of the connected network.

Our terms of service do not allow you or end users to redistribute offline maps downloaded from Mapbox servers.

Tile Automatic Update

Maps SDK downloads tiles when any connection is available, including through conventional mobile data (2G, 3G, 4G, etc.). Because there is only a single highly optimized tile download, there is no risk that users will accidentally download 100 MB if they open the map in the downloaded area. Unless the user is browsing 100 MB tiles.

When SDK automatically updates the offline map patches, the offline area will not be re-downloaded. The offline update process of tiles is the same as that of conventional map tiles: map tiles are downloaded only when a new version of tiles is available.

Define an area

Before you can use an area offline, you must download the resources needed for that area. Based on the parameters specified when creating the region, the SDK calculates all resource requirements, such as fonts, styles, and vector blocks that cover the region. If multiple areas in the offline database contain fonts and styles, they will not be re-downloaded when downloading other areas.

First, you need to get an instance of offlineManager, define the area to download, and finally create a definition object. It's important to pay attention to a few things:

  • Offline map styles must match those used for mapView
  • This definition requires the screen density of the device, which you should derive from the activities resources
  • Download boundaries should not exceed 6000 tiling limits

Examples:

// Set up the OfflineManager
OfflineManager offlineManager = OfflineManager.getInstance(MainActivity.this);

// Create a bounding box for the offline region
LatLngBounds latLngBounds = new LatLngBounds.Builder()
  .include(new LatLng(37.7897, -119.5073)) // Northeast
  .include(new LatLng(37.6744, -119.6815)) // Southwest
  .build();

// Define the offline region
OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition(
  mapboxMap.getStyleUrl(),
  latLngBounds,
  10,
  20,
  MainActivity.this.getResources().getDisplayMetrics().density);

metadata

Encourage the use of at least one region name to provide metadata objects so that the regions downloaded by users can be distinguished. In addition to the region name, you can store any binary region information you want. These are opaque to SDK implementations and will not affect your offline area download. It only stores and retrieves an array of bytes. Examples are as follows:

// Implementation of Storing Yosemite National Park as Offline Area Name Using JSON
byte[] metadata;
try {
  JSONObject jsonObject = new JSONObject();
  jsonObject.put(JSON_FIELD_REGION_NAME, "Yosemite National Park");
  String json = jsonObject.toString();
  metadata = json.getBytes(JSON_CHARSET);
} catch (Exception exception) {
  Log.e(TAG, "Failed to encode metadata: " + exception.getMessage());
  metadata = null;
}

In addition to creating metadata, you can update stored information, such as allowing users to update area names. The offlineManager object provides a method called updateMetadata, which receives the updated metadata byte array and a callback function, which is notified when the update is complete or an error occurs.

Download an area

Now that you have created boundaries and defined objects, you can use offline Manager to create an asynchronous download that calls createOffline Region. You need to pass in the definitions and metadata objects created in the Definition Area and Metadata section. This will give you two methods, onCreate and onError. An onError occurs if an error occurs in the boot or download area. The onCreate method provides an offlineRegion object that you can use to check downloads and even display progress to users. If you need to pause the download, you can use offlineRegion.setDownloadState() to handle this problem.
Download an example:

// Asynchronous Creation Zone
offlineManager.createOfflineRegion(definition, metadata,
  new OfflineManager.CreateOfflineRegionCallback() {
    @Override
    public void onCreate(OfflineRegion offlineRegion) {
      offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE);

      // Using setObserver to monitor the download process
      offlineRegion.setObserver(new OfflineRegion.OfflineRegionObserver() {
        @Override
        public void onStatusChanged(OfflineRegionStatus status) {
          // Calculate download progress (percentage)
          double percentage = status.getRequiredResourceCount() >= 0
          ? (100.0 * status.getCompletedResourceCount() / status.getRequiredResourceCount()) :
          0.0;

          if (status.isComplete()) {
            // End of download
            Log.d(TAG, "Region downloaded successfully.");
          } else if (status.isRequiredResourceCountPrecise()) {
            Log.d(TAG, percentage);
          }
        }

        @Override
        public void onError(OfflineRegionError error) {
          // When an error occurs, print to logcat
          Log.e(TAG, "onError reason: " + error.getReason());
          Log.e(TAG, "onError message: " + error.getMessage());
        }

        @Override
        public void mapboxTileCountLimitExceeded(long limit) {
          // If the off-line area exceeds the maximum number of tiles, please notify
          Log.e(TAG, "Mapbox tile count limit exceeded: " + limit);
        }
      });
    }

  @Override
  public void onError(String error) {
    Log.e(TAG, "Error: " + error);
  }
});

Manage download areas

Once you or your user downloads an area, the Maps SDK provides options to process the collection list, locate the camera in the downloaded area, and delete the area.

Download List
Area lists are useful for displaying downloaded information to users or collecting information within code. Offfline Manager provides a listOffline Regions method, which provides both onList and onError methods. Use the Offline Region array to perform all operations in a particular area.

// Obtain area boundaries and zoom conditions, and move the camera.
LatLngBounds bounds = ((OfflineTilePyramidRegionDefinition)
  offlineRegions[regionSelected].getDefinition()).getBounds();
double regionZoom = ((OfflineTilePyramidRegionDefinition)
  offlineRegions[regionSelected].getDefinition()).getMinZoom();

// New camera location
CameraPosition cameraPosition = new CameraPosition.Builder()
  .target(bounds.getCenter())
  .zoom(regionZoom)
  .build();

// Mobile Camera
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))

Delete area

To delete an offline area from the database, you need to first receive a list of offline areas, as described in the previous section. The onList method will provide you with an array of the current offline regions that are downloaded from the device, which are offline Regions. Then, you will use this object to select the area to be deleted and call delete on it, which will provide you with a callback function to notify you when the area is successfully deleted or an error occurs.

Deleting a region also removes the least recently requested resources that other regions do not need until the database is reduced to a certain size.

Remove area callback function:

offlineRegions[0].delete(new OfflineRegion.OfflineRegionDeleteCallback() {
  @Override
  public void onDelete() {
    // Once this area is deleted, hide the progressBar and display toast
    progressBar.setVisibility(View.INVISIBLE);
    progressBar.setIndeterminate(false);
    Toast.makeText(MainActivity.this, "Region deleted", Toast.LENGTH_LONG).show();
  }

  @Override
  public void onError(String error) {
    progressBar.setVisibility(View.INVISIBLE);
    progressBar.setIndeterminate(false);
    Log.e(TAG, "Error: " + error);
  }
});

Offline sideloading

Side loading is a two-part process that provides an available mobile application for offline areas. The first step is to package the tile s and resources needed to create an offline zone outside the SDK, and the second step is to merge the created offline packages into the SDK offline database.

Generating offline packages
To generate an offline package containing tile s and resources for a specific area, you have two options. You can use either the command line tool or the macOS graphical interface. The CLI option applies to any operating system, while the macOS option applies only to the macOS environment.

Note that the offline functionality of your mobile application is limited to 6000 tiles. For more information about this tile ceiling, refer to the Restrictions section above.

The command line uses reference: https://docs.mapbox.com/android/maps/overview/offline/#generate-the-offline-package

Merge offline packages
Once a new offline package is created, copy the file to the device so that the offline merge API can merge its contents into the main Maps SDK database. You can use adb to copy the file locally or download it from the server. Maps SDK loads all tile s and resources from a primary database and provides an offline merge API to merge the contents of the new secondary database into the primary database.

Note: Before v6.6.0 of Android Maps SDK, when the offline merge API was unavailable, the side loading solution was to delete the main database file and add your own offline database. Although this method is still technically feasible, it is no longer recommended because it does not allow multiple databases to be merged and can easily crash.

Steps for merging auxiliary databases into the main Maps SDK database: https://docs.mapbox.com/android/maps/overview/offline/#merge-the-offline-package
For a complete example, see MergeOfflineRegionsActivity and Example database . For more details, see Merge Offline Regions document.

Database Location on Android
On Android, you can move the location of the SDK database of the main map from internal storage to external storage. To do this, make sure that the application has WRITE_EXTERNAL_STORAGE permissions and the following flags in Android Manifest.xml:

<application>
  <meta-data
    android:name="com.mapbox.SetStorageExternal"
    android:value="true" />
    ...
</application>

Topics: SDK Database Android Mobile