Learn how to download and display an offline map for a user-defined geographical area of a web map.
Offline maps allow users to continue working when network connectivity is poor or lost. If a web map is enabled for offline use, a user can request that ArcGIS generates an offline map for a specified geographic area of interest.
In this tutorial, you will download an offline map for an area of interest from the web map of the
stormwater network within Naperville, IL, USA
. You can then use this offline map without a network connection.Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Confirm that your system meets the system requirements.
-
An IDE for Android development in Kotlin.
Steps
Open an Android Studio project
-
To start this tutorial, complete the Display a web map tutorial. Or download and unzip the Display a web map solution in a new folder.
-
Modify the old project for use in this new tutorial. Expand More info for instructions.
-
On your file system, delete the .idea folder, if present, at the top level of your project.
-
In the Android tool window, open app > res > values > strings.xml.
In the
<string name="app
element, change the text content to Display an offline map (on-demand)._name" > strings.xmlUse dark colors for code blocks <resources> <string name="app_name">Display an offline map (on-demand)</string> </resources>
-
In the Android tool window, open Gradle Scripts > settings.gradle.
Change the value of
root
to "Display an offline map (on-demand)".Project.name settings.gradleUse dark colors for code blocks rootProject.name = "Display an offline map (on-demand)" include ':app'
-
Click File > Sync Project with Gradle files. Android Studio will recognize your changes and create a new .idea folder.
-
-
If you downloaded the solution, get an access token and set the API key.
-
Go to the Create an API key tutorial to obtain a new API key access token using your ArcGIS Location Platform or ArcGIS Online account. Ensure that the following privilege is enabled: Location services > Basemaps > Basemap styles service. Copy the access token as it will be used in the next step.
-
In Android Studio: in the Android tool window, open app > java > com.example.app > MainActivity.
-
In the
set
method, find theApi Key For App() ArcGIS
call and paste your access token inside the double quotes, replacing YOUR_ACCESS_TOKEN.Runtime Environment.set Api Key(" YOUR _ACCESS _TOKE N") MainActivity.ktUse dark colors for code blocks private fun setApiKeyForApp(){ ArcGISRuntimeEnvironment.setApiKey("YOUR_ACCESS_TOKEN") }
-
Add import statements and packagingOptions
-
Replace app-specific import statements with the imports needed for this tutorial.
MainActivity.ktUse dark colors for code blocks 17 18 19 20 21 44 45 46 47Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line package com.example.app import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import android.graphics.Color import android.view.View import android.widget.ProgressBar import android.widget.Toast import java.util.* import com.esri.arcgisruntime.ArcGISRuntimeEnvironment import com.esri.arcgisruntime.concurrent.Job import com.esri.arcgisruntime.geometry.Envelope import com.esri.arcgisruntime.geometry.SpatialReferences import com.esri.arcgisruntime.mapping.ArcGISMap import com.esri.arcgisruntime.mapping.view.Graphic import com.esri.arcgisruntime.mapping.view.GraphicsOverlay import com.esri.arcgisruntime.mapping.view.MapView import com.esri.arcgisruntime.portal.Portal import com.esri.arcgisruntime.portal.PortalItem import com.esri.arcgisruntime.symbology.SimpleFillSymbol import com.esri.arcgisruntime.symbology.SimpleLineSymbol import com.esri.arcgisruntime.tasks.offlinemap.GenerateOfflineMapParameters import com.esri.arcgisruntime.tasks.offlinemap.GenerateOfflineMapUpdateMode import com.esri.arcgisruntime.tasks.offlinemap.OfflineMapTask import com.example.app.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() {
-
In Android Studio, in the Android tool window, open Gradle Scripts > build.gradle (Module:Display_a_map_from_a_mobile_map_package.app). Make sure your file matches the one below. In particular, verify that you have the
build
andFeatures packaging
blocks shown.Options build.gradle (Module:Display_a_map_from_a_mobile_map_package.app)Use dark colors for code blocks Copy 29 30 31 32 39 40kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() } buildFeatures { viewBinding true } packagingOptions { exclude 'META-INF/DEPENDENCIES' } }
Get the web map item ID
You can use ArcGIS tools to create and view web maps. Use the Map Viewer to identify the web map item ID. This item ID will be used later in the tutorial.
- Go to the Naperville water network
in the Map Viewer in ArcGIS Online. This web map displays
stormwater network within Naperville, IL, USA
. - Make a note of the item ID at the end of the browser's URL. The item ID should be
acc027394bc84c2fb04d1ed317aac674
.
Define a Progress Bar
and create read-only properties
-
In the Project tool window, open app > res > layout > activity_main.xml. Add a
<Progress
element to define a progress bar.Bar > MainActivity.ktUse dark colors for code blocks <ProgressBar android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="50dp" android:layout_marginEnd="50dp" android:padding="20dp" android:indeterminate="false" android:visibility="gone" android:scaleY="3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
-
In the Project tool window, open app > java > com.example.app > MainActivity.kt. At the top of the
Main
class, keep the read-only, lazy propertiesActivity activity
andMain Binding map
that were defined in Display a web map tutorial. Add read-only, lazy propertiesView progress
andBar area
.Overlay MainActivity.ktUse dark colors for code blocks class MainActivity : AppCompatActivity() { private val activityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) } private val mapView: MapView by lazy { activityMainBinding.mapView } private val progressBar: ProgressBar by lazy { activityMainBinding.progressBar } private val areaOverlay: GraphicsOverlay by lazy { GraphicsOverlay() }
Display the web map
You can display a web map using the web map's item ID. Create a map from the web map portal item, and display it in your app.
-
In the Visual Studio > Solution Explorer, double-click MapViewModel.cs to open the file.
-
In MainActivity.kt, delete the code inside
setup
.Map() Create a
Portal
pointing to ArcGIS Online. Then create aPortalItem
for the Naperville water network, using the portal and the web map's item ID. Finally, set theMap
property to a newView.map ArcGISMap
created using thePortalItem
.MainActivity.ktUse dark colors for code blocks // set up your map here. You will call this method from onCreate() private fun setupMap() { // create a portal pointing to ArcGIS Online val portal = Portal("https://www.arcgis.com", false) // create a portal item for a specific web map id val webMapId = "acc027394bc84c2fb04d1ed317aac674" val mapItem = PortalItem(portal, webMapId) // create the map from the item val map = ArcGISMap(mapItem) // set the map to the map view mapView.map = map }
-
Add the
area
to the map view's list of graphics overlays.Overlay The GraphicsOverlay referenced by
area
has no graphics in it at the moment. You will add an area-of-interest graphic in the next section. To see where you defined theOverlay area
property, expandOverlay Show more lines
in the code block below. The property is highlighted in blue.For more information about the list of graphics overlays in a map view, see
Geo
.View.get Graphics Overlays() MainActivity.ktUse dark colors for code blocks // set up your map here. You will call this method from onCreate() private fun setupMap() { // create a portal pointing to ArcGIS Online val portal = Portal("https://www.arcgis.com", false) // create a portal item for a specific web map id val webMapId = "acc027394bc84c2fb04d1ed317aac674" val mapItem = PortalItem(portal, webMapId) // create the map from the item val map = ArcGISMap(mapItem) // set the map to the map view mapView.map = map // add a graphics overlay to the map view mapView.graphicsOverlays.add(areaOverlay) }
-
Click Run > Run > app to run the app.
You should see a map of the
stormwater network within Naperville, IL, USA
. Use the mouse to drag, scroll, and double-click the map view to explore the map.Specify an area of the web map to take offline
You can specify an area of the web map to take offline using an
Envelope
. You can use a graphic to display the area on the map.
-
Define a new function
create
. Create anAreaof Interest Graphic() Envelope
to define the area of interest to take offline.MainActivity.ktUse dark colors for code blocks private fun createAreaOfInterestGraphic(): Envelope { // define area of interest (envelope) to take offline. val offlineArea = Envelope(-88.1526, 41.7694, -88.1490, 41.7714, SpatialReferences.getWgs84()) }
-
Display a graphic of the area to take offline.
Use a
SimpleLineSymbol
and aSimpleFillSymbol
to create a newGraphic
of the offline area with a red outline. Add the graphic to theGraphicsOverlay
referenced byarea
.Overlay MainActivity.ktUse dark colors for code blocks private fun createAreaOfInterestGraphic(): Envelope { // define area of interest (envelope) to take offline. val offlineArea = Envelope(-88.1526, 41.7694, -88.1490, 41.7714, SpatialReferences.getWgs84()) // create a graphic to display the area to take offline val lineSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 2f) val fillSymbol = SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.TRANSPARENT, lineSymbol) val offlineAreaGraphic = Graphic(offlineArea, fillSymbol) // create a graphics overlay and add the graphic areaOverlay.graphics.add(offlineAreaGraphic) }
-
Return the offline area itself. It will be used later when you create parameters for the job that generates and downloads an offline map.
MainActivity.ktUse dark colors for code blocks private fun createAreaOfInterestGraphic(): Envelope { // define area of interest (envelope) to take offline. val offlineArea = Envelope(-88.1526, 41.7694, -88.1490, 41.7714, SpatialReferences.getWgs84()) // create a graphic to display the area to take offline val lineSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 2f) val fillSymbol = SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.TRANSPARENT, lineSymbol) val offlineAreaGraphic = Graphic(offlineArea, fillSymbol) // create a graphics overlay and add the graphic areaOverlay.graphics.add(offlineAreaGraphic) return offlineArea }
-
Click Run > Run > app to run the app.
You should see a red outline on the
stormwater network within Naperville, IL, USA
. This indicates the area of the web map that you are going to take offline.Download and display the offline map
You can generate and download an offline map for a specified area of interest using an asynchronous task. When complete, it will provide the offline map for display in your map view.
-
Define a new function
create
. Create anOffline Map Task And Parameters() OfflineMapTask
that references the online map.MainActivity.ktUse dark colors for code blocks private fun createOfflineMapTaskAndParameters(map: ArcGISMap, offlineArea : Envelope) { // create an offline map task using the current map val offlineMapTask = OfflineMapTask(map) }
-
Get default parameters to generate and download the offline map. Since the return value of
create
is a listenable future, add a done listener, where you modify the default parameters to download a read-only offline map.Default Generate Offline Map Parameters Async() This tutorial does not involve editing and updating the contents of the offline map. When an offline map is editable, metadata is stored in ArcGIS to track and synchronize edits. Setting the
Generate
toOffline Map Update Mode NO
avoids the overhead of maintaining this metadata in ArcGIS._UPDATES MainActivity.ktUse dark colors for code blocks private fun createOfflineMapTaskAndParameters(map: ArcGISMap, offlineArea : Envelope) { // create an offline map task using the current map val offlineMapTask = OfflineMapTask(map) // create a default set of parameters for generating the offline map from the area of interest val parametersFuture = offlineMapTask.createDefaultGenerateOfflineMapParametersAsync(offlineArea) parametersFuture.addDoneListener { val parameters = parametersFuture.get().apply { updateMode = GenerateOfflineMapUpdateMode.NO_UPDATES } downloadOfflineMap(offlineMapTask, parameters) } }
-
Define a new function
download
. Set a download location for the offline map.Offline Map() MainActivity.ktUse dark colors for code blocks private fun downloadOfflineMap(offlineMapTask: OfflineMapTask, parameters: GenerateOfflineMapParameters) { // Build a folder path named with today's date/time in the "My Documents" folder. val downloadLocation = getExternalFilesDir(null)?.path + "OfflineMap_" + Calendar.getInstance().time }
This tutorial code creates a new unique folder in your app's data folder, using the current date and time.
-
Create a new
GenerateOfflineMapJob
using theparameters
passed into the function and thedownload
.Location MainActivity.ktUse dark colors for code blocks private fun downloadOfflineMap(offlineMapTask: OfflineMapTask, parameters: GenerateOfflineMapParameters) { // Build a folder path named with today's date/time in the "My Documents" folder. val downloadLocation = getExternalFilesDir(null)?.path + "OfflineMap_" + Calendar.getInstance().time val generateJob = offlineMapTask.generateOfflineMap(parameters, downloadLocation).apply { } }
-
Add a progress changed listener for the generate offline map job.
MainActivity.ktUse dark colors for code blocks private fun downloadOfflineMap(offlineMapTask: OfflineMapTask, parameters: GenerateOfflineMapParameters) { // Build a folder path named with today's date/time in the "My Documents" folder. val downloadLocation = getExternalFilesDir(null)?.path + "OfflineMap_" + Calendar.getInstance().time val generateJob = offlineMapTask.generateOfflineMap(parameters, downloadLocation).apply { addProgressChangedListener { progressBar.progress = progress } } }
-
Add a job done listener for the generate offline map job.
MainActivity.ktUse dark colors for code blocks private fun downloadOfflineMap(offlineMapTask: OfflineMapTask, parameters: GenerateOfflineMapParameters) { // Build a folder path named with today's date/time in the "My Documents" folder. val downloadLocation = getExternalFilesDir(null)?.path + "OfflineMap_" + Calendar.getInstance().time val generateJob = offlineMapTask.generateOfflineMap(parameters, downloadLocation).apply { addProgressChangedListener { progressBar.progress = progress } addJobDoneListener { // replace the current map with the result offline map when the job finishes if (status == Job.Status.SUCCEEDED) { progressBar.visibility = View.GONE Toast.makeText( this@MainActivity, "Showing offline map.", Toast.LENGTH_LONG ).show() val result = result mapView.map = result.offlineMap areaOverlay.graphics.clear() } } } }
-
Start the generate offline map job, display a progress bar, and display a Toast saying that the job is starting.
MainActivity.ktUse dark colors for code blocks } generateJob.start() progressBar.visibility = View.VISIBLE Toast.makeText(this@MainActivity, "Starting generate offline map job.", Toast.LENGTH_LONG).show() }
-
In
setup
, call the functions you defined to create the area of interest graphic and then create the offline map task. First, callMap() create
and then pass the result when you callAreaof Interest Graphic() create
.Offline Map Task And Parameters() MainActivity.ktUse dark colors for code blocks // set the map to the map view mapView.map = map // add a graphics overlay to the map view mapView.graphicsOverlays.add(areaOverlay) // create a graphic showing the area of interest val offlineArea = createAreaOfInterestGraphic() createOfflineMapTaskAndParameters(map, offlineArea) }
-
Click Run > Run > app to run the app.
You should see an offline map for the specified area of the
stormwater network within Naperville, IL, USA
. Remove your network connection and you will still be able to use the mouse to drag, scroll, and double-click the map view to explore this offline map.What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: