使用 ArcGIS 创建离线地图(.mmpk 地图)
Create an offline map using ArcGIS (.mmpk map)
我的目标是创建一个 Android 应用程序,当连接到 Internet 时,从 ArcGIS 门户下载地图,然后离线使用它们。我想使用服务模式,以便以后应用程序可以具有同步功能。我遵循了 ArcGIS here 的教程。
我目前卡在下载地图部分。我希望下载的地图在 移动地图包 (.mmpk) 中,但我的下载目录却有 一个 package.info 文件,以及一个地理数据库文件夹和.mmap 文件 为 image shown here。根据我的理解,我应该有一个 .mmpk 文件来离线使用它们。
按照教程步骤,我能够(1) 创建离线地图任务,(2) 指定参数, (3) 检查离线功能。然而在步骤(4)生成并下载离线地图,我预计下载的地图将在移动地图包(.mmpk)中,但它不是;正如我上面提到的图片所示。在步骤(5)打开并使用离线地图,我可以在使用我手动传输到设备中的移动地图包(.mmpk)文件时查看离线地图。我也尝试打开并使用我下载的 (.mmap) 文件,但没有显示地图。
我的完整代码如下所示:
(1)创建离线地图任务
// Load map from a portal item
final Portal portal = new Portal("http://www.arcgis.com");
final PortalItem webmapItem = new PortalItem(portal, "acc027394bc84c2fb04d1ed317aac674");
// Create map and add it to the view
myMap = new ArcGISMap(webmapItem);
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.setMap(myMap);
// Create task and set parameters
final OfflineMapTask offlineMapTask = new OfflineMapTask(myMap);
(2)指定参数
// Create default parameters
final ListenableFuture<GenerateOfflineMapParameters> parametersFuture = offlineMapTask.createDefaultGenerateOfflineMapParametersAsync(areaOfInterest);
parametersFuture.addDoneListener(new Runnable() {
@Override
public void run() {
try {
final GenerateOfflineMapParameters parameters = parametersFuture.get();
// Update the parameters if needed
// Limit maximum scale to 5000 but take all the scales above (use 0 as a MinScale)
parameters.setMaxScale(5000);
parameters.setIncludeBasemap(false);
// Set attachment options
parameters.setAttachmentSyncDirection(GenerateGeodatabaseParameters.AttachmentSyncDirection.UPLOAD);
parameters.setReturnLayerAttachmentOption(GenerateOfflineMapParameters.ReturnLayerAttachmentOption.EDITABLE_LAYERS);
// Request the table schema only (existing features won't be included)
parameters.setReturnSchemaOnlyForEditableLayers(true);
// Update the title to contain the region
parameters.getItemInfo().setTitle(parameters.getItemInfo().getTitle() + " (Central)");
// Create new item info
final OfflineMapItemInfo itemInfo = new OfflineMapItemInfo();
// Override thumbnail with the new image based on the extent
final ListenableFuture<Bitmap> exportImageFuture = mMapView.exportImageAsync();
exportImageFuture.addDoneListener(new Runnable() {
@Override
public void run() {
try {
Bitmap mapImage = exportImageFuture.get();
// Scale to thumbnail size
Bitmap thumbnailImage = Bitmap.createScaledBitmap(mapImage, 200, 133, false);
// Convert to byte[]
ByteArrayOutputStream stream = new ByteArrayOutputStream();
thumbnailImage.compress(Bitmap.CompressFormat.JPEG, 50, stream);
byte[] thumbnailBytes = stream.toByteArray();
stream.close();
// Set values to the itemInfo
itemInfo.setThumbnailData(thumbnailBytes);
itemInfo.setTitle("Water network (Central)");
itemInfo.setSnippet(webmapItem.getSnippet()); // Copy from the source map
itemInfo.setDescription(webmapItem.getDescription()); // Copy from the source map
itemInfo.setAccessInformation(webmapItem.getAccessInformation()); // Copy from the source map
itemInfo.getTags().add("Water network");
itemInfo.getTags().add("Data validation");
// Set metadata to parameters
parameters.setItemInfo(itemInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
});
(3) 检查离线能力
final ListenableFuture<OfflineMapCapabilities> offlineMapCapabilitiesFuture =
offlineMapTask.getOfflineMapCapabilitiesAsync(parameters);
offlineMapCapabilitiesFuture.addDoneListener(new Runnable() {
@Override
public void run() {
try {
OfflineMapCapabilities offlineMapCapabilities = offlineMapCapabilitiesFuture.get();
if (offlineMapCapabilities.hasErrors()) {
// Handle possible errors with layers
for (java.util.Map.Entry<Layer, OfflineCapability> layerCapability :
offlineMapCapabilities.getLayerCapabilities().entrySet()) {
if (!layerCapability.getValue().isSupportsOffline()) {
showMessage(layerCapability.getKey().getName() + " cannot be taken offline.");
showMessage("Error : " + layerCapability.getValue().getError().getMessage());
}
}
// Handle possible errors with tables
for (java.util.Map.Entry<FeatureTable, OfflineCapability> tableCapability :
offlineMapCapabilities.getTableCapabilities().entrySet()) {
if (!tableCapability.getValue().isSupportsOffline()) {
showMessage(tableCapability.getKey().getTableName() + " cannot be taken offline.");
showMessage("Error : " + tableCapability.getValue().getError().getMessage());
}
}
} else {
// All layers and tables can be taken offline!
showMessage("All layers are good to go!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
(4)生成并下载离线地图
String mExportPath = String.valueOf(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)) + File.separator + "New";
showMessage(mExportPath);
// Create and start a job to generate the offline map
final GenerateOfflineMapJob generateOfflineJob =
offlineMapTask.generateOfflineMap(parameters, mExportPath);
// Show that job started
final ProgressBar progressBarOffline = (ProgressBar) findViewById(R.id.progressBarOffline);
progressBarOffline.setVisibility(View.VISIBLE);
generateOfflineJob.start();
generateOfflineJob.addJobDoneListener(new Runnable() {
@Override
public void run() {
// Generate the offline map and download it
GenerateOfflineMapResult result = generateOfflineJob.getResult();
if (!result.hasErrors()) {
showMessage("no error");
mobileMapPackage = result.getMobileMapPackage();
// Job is finished and all content was generated
showMessage("Map " + mobileMapPackage.getItem().getTitle() +
" saved to " + mobileMapPackage.getPath());
// Show offline map in a MapView
mMapView.setMap(result.getOfflineMap());
// Show that job completed
progressBarOffline.setVisibility(View.INVISIBLE);
} else {
showMessage("error");
// Job is finished but some of the layers/tables had errors
if (result.getLayerErrors().size() > 0) {
for (java.util.Map.Entry<Layer, ArcGISRuntimeException> layerError : result.getLayerErrors().entrySet()) {
showMessage("Error occurred when taking " + layerError.getKey().getName() + " offline.");
showMessage("Error : " + layerError.getValue().getMessage());
}
}
if (result.getTableErrors().size() > 0) {
for (java.util.Map.Entry<FeatureTable, ArcGISRuntimeException> tableError : result.getTableErrors().entrySet()) {
showMessage("Error occurred when taking " + tableError.getKey().getTableName() + " offline.");
showMessage("Error : " + tableError.getValue().getMessage());
}
}
// Show that job completed
progressBarOffline.setVisibility(View.INVISIBLE);
}
}
});
(5) 打开并使用离线地图
// Create the mobile map package
final MobileMapPackage mapPackage = new MobileMapPackage(mobileMapPackage.getPath());
// Load the mobile map package asynchronously
mapPackage.loadAsync();
// Add done listener which will invoke when mobile map package has loaded
mapPackage.addDoneLoadingListener(new Runnable() {
@Override
public void run() {
// Check load status and that the mobile map package has maps
if(mapPackage.getLoadStatus() == LoadStatus.LOADED && mapPackage.getMaps().size() > 0){
// Cdd the map from the mobile map package to the MapView
mMapView.setMap(mapPackage.getMaps().get(0));
}else{
// Log an issue if the mobile map package fails to load
showMessage(mapPackage.getLoadError().getMessage());
}
}
});
我的代码中的 showMessage() 正在显示 Toast。
public void showMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
我担心如果我的.mmpk 预期是错误的,或者我的步骤哪里出错了,因为我还没有完全理解整个过程。这是我在 Android 中第一次使用 ArcGIS 地图。我找不到太多示例代码来进行实验,非常感谢能提供帮助的人。
谢谢!
该任务创建了一个分解的移动地图包,其工作方式与 .mmpk 文件相同。像这样打开它:
final MobileMapPackage mapPackage =
new MobileMapPackage("/data/com.geoinfo.asmasyakirah.arcgis/files/Documents/New");
(如果您无法在那里访问它,您可能希望在 Environment.getExternalStorageDirectory()
而不是 Environment.DIRECTORY_DOCUMENTS
中生成移动地图包。)
根据the documentation for the MobileMapPackage constructor:
Creates a new MobileMapPackage from the .mmpk file or exploded mobile map package at the given path.
如果您真的必须将它作为 .mmpk 文件,只需使用 Android API 压缩它来制作 zip 文件并将其命名为 .mmpk 而不是 .zip。
这个话题有点晚了,但我花了几天时间研究这个,发现了一些可能对你们中的一些人有所帮助的东西:
我通过这个 class 创建了我的 mapData : https://github.com/Esri/arcgis-runtime-samples-java/blob/master/src/main/java/com/esri/samples/map/generate_offline_map/GenerateOfflineMapSample.java
如您所见,它创建了一个包含 package.info + p13 的文件夹(您可以在其中找到地理数据库文件 + mmap 文件)
当我尝试离线加载此数据时,没有出现任何错误,但该图层是空的,我只能看到播放。
事实上,经过多次尝试后,我不得不检查除了地理数据库和 mmap 文件之外,我还能找到一个 .tpk 文件 (TilePackaged)
这个从来没有可用过(不知何故由于在线下载期间的网络问题)并且没有任何提醒我。
现在有了这个 tpk 文件,所有项目都清楚地显示了 'water network'
TL;DR; :在线准备时检查是否下载了tpk文件。
我的目标是创建一个 Android 应用程序,当连接到 Internet 时,从 ArcGIS 门户下载地图,然后离线使用它们。我想使用服务模式,以便以后应用程序可以具有同步功能。我遵循了 ArcGIS here 的教程。
我目前卡在下载地图部分。我希望下载的地图在 移动地图包 (.mmpk) 中,但我的下载目录却有 一个 package.info 文件,以及一个地理数据库文件夹和.mmap 文件 为 image shown here。根据我的理解,我应该有一个 .mmpk 文件来离线使用它们。
按照教程步骤,我能够(1) 创建离线地图任务,(2) 指定参数, (3) 检查离线功能。然而在步骤(4)生成并下载离线地图,我预计下载的地图将在移动地图包(.mmpk)中,但它不是;正如我上面提到的图片所示。在步骤(5)打开并使用离线地图,我可以在使用我手动传输到设备中的移动地图包(.mmpk)文件时查看离线地图。我也尝试打开并使用我下载的 (.mmap) 文件,但没有显示地图。
我的完整代码如下所示:
(1)创建离线地图任务
// Load map from a portal item
final Portal portal = new Portal("http://www.arcgis.com");
final PortalItem webmapItem = new PortalItem(portal, "acc027394bc84c2fb04d1ed317aac674");
// Create map and add it to the view
myMap = new ArcGISMap(webmapItem);
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.setMap(myMap);
// Create task and set parameters
final OfflineMapTask offlineMapTask = new OfflineMapTask(myMap);
(2)指定参数
// Create default parameters
final ListenableFuture<GenerateOfflineMapParameters> parametersFuture = offlineMapTask.createDefaultGenerateOfflineMapParametersAsync(areaOfInterest);
parametersFuture.addDoneListener(new Runnable() {
@Override
public void run() {
try {
final GenerateOfflineMapParameters parameters = parametersFuture.get();
// Update the parameters if needed
// Limit maximum scale to 5000 but take all the scales above (use 0 as a MinScale)
parameters.setMaxScale(5000);
parameters.setIncludeBasemap(false);
// Set attachment options
parameters.setAttachmentSyncDirection(GenerateGeodatabaseParameters.AttachmentSyncDirection.UPLOAD);
parameters.setReturnLayerAttachmentOption(GenerateOfflineMapParameters.ReturnLayerAttachmentOption.EDITABLE_LAYERS);
// Request the table schema only (existing features won't be included)
parameters.setReturnSchemaOnlyForEditableLayers(true);
// Update the title to contain the region
parameters.getItemInfo().setTitle(parameters.getItemInfo().getTitle() + " (Central)");
// Create new item info
final OfflineMapItemInfo itemInfo = new OfflineMapItemInfo();
// Override thumbnail with the new image based on the extent
final ListenableFuture<Bitmap> exportImageFuture = mMapView.exportImageAsync();
exportImageFuture.addDoneListener(new Runnable() {
@Override
public void run() {
try {
Bitmap mapImage = exportImageFuture.get();
// Scale to thumbnail size
Bitmap thumbnailImage = Bitmap.createScaledBitmap(mapImage, 200, 133, false);
// Convert to byte[]
ByteArrayOutputStream stream = new ByteArrayOutputStream();
thumbnailImage.compress(Bitmap.CompressFormat.JPEG, 50, stream);
byte[] thumbnailBytes = stream.toByteArray();
stream.close();
// Set values to the itemInfo
itemInfo.setThumbnailData(thumbnailBytes);
itemInfo.setTitle("Water network (Central)");
itemInfo.setSnippet(webmapItem.getSnippet()); // Copy from the source map
itemInfo.setDescription(webmapItem.getDescription()); // Copy from the source map
itemInfo.setAccessInformation(webmapItem.getAccessInformation()); // Copy from the source map
itemInfo.getTags().add("Water network");
itemInfo.getTags().add("Data validation");
// Set metadata to parameters
parameters.setItemInfo(itemInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
});
(3) 检查离线能力
final ListenableFuture<OfflineMapCapabilities> offlineMapCapabilitiesFuture =
offlineMapTask.getOfflineMapCapabilitiesAsync(parameters);
offlineMapCapabilitiesFuture.addDoneListener(new Runnable() {
@Override
public void run() {
try {
OfflineMapCapabilities offlineMapCapabilities = offlineMapCapabilitiesFuture.get();
if (offlineMapCapabilities.hasErrors()) {
// Handle possible errors with layers
for (java.util.Map.Entry<Layer, OfflineCapability> layerCapability :
offlineMapCapabilities.getLayerCapabilities().entrySet()) {
if (!layerCapability.getValue().isSupportsOffline()) {
showMessage(layerCapability.getKey().getName() + " cannot be taken offline.");
showMessage("Error : " + layerCapability.getValue().getError().getMessage());
}
}
// Handle possible errors with tables
for (java.util.Map.Entry<FeatureTable, OfflineCapability> tableCapability :
offlineMapCapabilities.getTableCapabilities().entrySet()) {
if (!tableCapability.getValue().isSupportsOffline()) {
showMessage(tableCapability.getKey().getTableName() + " cannot be taken offline.");
showMessage("Error : " + tableCapability.getValue().getError().getMessage());
}
}
} else {
// All layers and tables can be taken offline!
showMessage("All layers are good to go!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
(4)生成并下载离线地图
String mExportPath = String.valueOf(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)) + File.separator + "New";
showMessage(mExportPath);
// Create and start a job to generate the offline map
final GenerateOfflineMapJob generateOfflineJob =
offlineMapTask.generateOfflineMap(parameters, mExportPath);
// Show that job started
final ProgressBar progressBarOffline = (ProgressBar) findViewById(R.id.progressBarOffline);
progressBarOffline.setVisibility(View.VISIBLE);
generateOfflineJob.start();
generateOfflineJob.addJobDoneListener(new Runnable() {
@Override
public void run() {
// Generate the offline map and download it
GenerateOfflineMapResult result = generateOfflineJob.getResult();
if (!result.hasErrors()) {
showMessage("no error");
mobileMapPackage = result.getMobileMapPackage();
// Job is finished and all content was generated
showMessage("Map " + mobileMapPackage.getItem().getTitle() +
" saved to " + mobileMapPackage.getPath());
// Show offline map in a MapView
mMapView.setMap(result.getOfflineMap());
// Show that job completed
progressBarOffline.setVisibility(View.INVISIBLE);
} else {
showMessage("error");
// Job is finished but some of the layers/tables had errors
if (result.getLayerErrors().size() > 0) {
for (java.util.Map.Entry<Layer, ArcGISRuntimeException> layerError : result.getLayerErrors().entrySet()) {
showMessage("Error occurred when taking " + layerError.getKey().getName() + " offline.");
showMessage("Error : " + layerError.getValue().getMessage());
}
}
if (result.getTableErrors().size() > 0) {
for (java.util.Map.Entry<FeatureTable, ArcGISRuntimeException> tableError : result.getTableErrors().entrySet()) {
showMessage("Error occurred when taking " + tableError.getKey().getTableName() + " offline.");
showMessage("Error : " + tableError.getValue().getMessage());
}
}
// Show that job completed
progressBarOffline.setVisibility(View.INVISIBLE);
}
}
});
(5) 打开并使用离线地图
// Create the mobile map package
final MobileMapPackage mapPackage = new MobileMapPackage(mobileMapPackage.getPath());
// Load the mobile map package asynchronously
mapPackage.loadAsync();
// Add done listener which will invoke when mobile map package has loaded
mapPackage.addDoneLoadingListener(new Runnable() {
@Override
public void run() {
// Check load status and that the mobile map package has maps
if(mapPackage.getLoadStatus() == LoadStatus.LOADED && mapPackage.getMaps().size() > 0){
// Cdd the map from the mobile map package to the MapView
mMapView.setMap(mapPackage.getMaps().get(0));
}else{
// Log an issue if the mobile map package fails to load
showMessage(mapPackage.getLoadError().getMessage());
}
}
});
我的代码中的 showMessage() 正在显示 Toast。
public void showMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
我担心如果我的.mmpk 预期是错误的,或者我的步骤哪里出错了,因为我还没有完全理解整个过程。这是我在 Android 中第一次使用 ArcGIS 地图。我找不到太多示例代码来进行实验,非常感谢能提供帮助的人。
谢谢!
该任务创建了一个分解的移动地图包,其工作方式与 .mmpk 文件相同。像这样打开它:
final MobileMapPackage mapPackage =
new MobileMapPackage("/data/com.geoinfo.asmasyakirah.arcgis/files/Documents/New");
(如果您无法在那里访问它,您可能希望在 Environment.getExternalStorageDirectory()
而不是 Environment.DIRECTORY_DOCUMENTS
中生成移动地图包。)
根据the documentation for the MobileMapPackage constructor:
Creates a new MobileMapPackage from the .mmpk file or exploded mobile map package at the given path.
如果您真的必须将它作为 .mmpk 文件,只需使用 Android API 压缩它来制作 zip 文件并将其命名为 .mmpk 而不是 .zip。
这个话题有点晚了,但我花了几天时间研究这个,发现了一些可能对你们中的一些人有所帮助的东西:
我通过这个 class 创建了我的 mapData : https://github.com/Esri/arcgis-runtime-samples-java/blob/master/src/main/java/com/esri/samples/map/generate_offline_map/GenerateOfflineMapSample.java
如您所见,它创建了一个包含 package.info + p13 的文件夹(您可以在其中找到地理数据库文件 + mmap 文件)
当我尝试离线加载此数据时,没有出现任何错误,但该图层是空的,我只能看到播放。
事实上,经过多次尝试后,我不得不检查除了地理数据库和 mmap 文件之外,我还能找到一个 .tpk 文件 (TilePackaged)
这个从来没有可用过(不知何故由于在线下载期间的网络问题)并且没有任何提醒我。
现在有了这个 tpk 文件,所有项目都清楚地显示了 'water network'
TL;DR; :在线准备时检查是否下载了tpk文件。