《ArcGIS Runtime SDK for Android学习笔记》-10、自定义扩展图层加载天地图并缓存

Author Avatar
wshunli 3月 02, 2017
  • 在其它设备中阅读本文章

本文主要介绍自定义扩展图层加载天地图并缓存(支持 ArcGIS for Android 100 版本)

概述

国家地理信息公共服务平台 “ 天地图 ”(以下简称 “天地图” )是国家测绘地理信息局主导建设的网络化地理信息共享与服务门户,集成了来自国家、省、市(县)各级测绘地理信息部门,以及相关政府部门、企事业单位 、社会团体、公众的地理信息公共服务资源,向各类用户提供权威、标准、统一的在线地理信息综合服务。

“天地图”属于基础性、公益性服务平台,针对不同用途设计了多种数据版本和服务模式,用户可根据自身需求进行使用。

基本情况如下:

1、基于 OGC 的 WMTS 1.0.0 版本;
2、提供矢量地图、影像地图和地形图;
3、提供两种坐标系:国家2000大地坐标系和 Web Mercator 投影坐标系;
4、地图和标注数据分开,矢量地图和影像地图提供中英文标注,地形图仅提供中文标注。

天地图的坐标比较标准,是国家 2000 坐标,没有偏移,但是切片分辨率并不是标准的 WMTS 服务。

针对 ArcGIS for Android SDK 在 100 版本及以后发生了较大的变化,本文分为两部分介绍。

vectorimageterrain
矢量图影像图地形图

本文源码:https://github.com/wshunli/arcgis-android-tianditu

ArcGIS for Android 10.2.9 及以前

1、搭建 ArcGIS for Android 环境

这部分内容在前面有详细的介绍 https://www.wshunli.com/posts/29ec97b7.html

2、添加 arcgis-android-tianditu 依赖

arcgis-android-tianditu 已经发布至 jcenter ,确定项目已配置 jcenter 仓库即可。

repositories {
    jcenter()
}
    // 添加 arcgis-android-tianditu 依赖
dependencies {
    implementation 'com.wshunli.map:arcgis-android-tianditu:1.1.0'
}

3、快速入门

MapView mMapView = (MapView) findViewById(R.id.map);
TianDiTuLayer vec_c = new TianDiTuLayer(TianDiTuLayerTypes.TIANDITU_VECTOR_MERCATOR);
mMapView.addLayer(vec_c);

这里支持对切片的缓存,指定缓存位置即可。

MapView mMapView = (MapView) findViewById(R.id.map);
String cachePath = Environment.getExternalStorageDirectory().getAbsoluteFile() + "/TianDiTuCache";
TianDiTuLayer vec_c = new TianDiTuLayer(TianDiTuLayerTypes.TIANDITU_VECTOR_MERCATOR, cachePath);
mMapView.addLayer(vec_c);

4、支持的图层类型

本文支持现有天地图所有图层,指定 TianDiTuLayerTypes 即可。

1、矢量、影像和地形切片图

图层类型国家 2000 坐标墨卡托投影
矢量图TIANDITU_VECTOR_2000TIANDITU_VECTOR_MERCATOR
影像图TIANDITU_IMAGE_2000TIANDITU_IMAGE_MERCATOR
地形图TIANDITU_TERRAIN_2000TIANDITU_TERRAIN_MERCATOR

2.1、墨卡托投影及相关标注

图层类型墨卡托投影
矢量图TIANDITU_VECTOR_MERCATOR
矢量中文标注TIANDITU_VECTOR_ANNOTATION_CHINESE_MERCATOR
矢量英文标注TIANDITU_VECTOR_ANNOTATION_ENGLISH_MERCATOR
影像图TIANDITU_IMAGE_MERCATOR
影像中文标注TIANDITU_IMAGE_ANNOTATION_CHINESE_MERCATOR
影像英文标注TIANDITU_IMAGE_ANNOTATION_ENGLISH_MERCATOR
地形图TIANDITU_TERRAIN_MERCATOR
地形中文标注TIANDITU_TERRAIN_ANNOTATION_CHINESE_MERCATOR

2.2、国家 2000 坐标及相关标注

图层类型国家 2000 坐标
矢量图TIANDITU_VECTOR_2000
矢量中文标注TIANDITU_VECTOR_ANNOTATION_CHINESE_2000
矢量英文标注TIANDITU_VECTOR_ANNOTATION_ENGLISH_2000
影像图TIANDITU_IMAGE_2000
影像中文标注TIANDITU_IMAGE_ANNOTATION_CHINESE_2000
影像英文标注TIANDITU_IMAGE_ANNOTATION_ENGLISH_2000
地形图TIANDITU_TERRAIN_2000
地形中文标注TIANDITU_TERRAIN_ANNOTATION_CHINESE_2000

完整使用示例

package com.wshunli.map.tianditu.sample;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.esri.android.map.MapView;
import com.esri.android.map.event.OnZoomListener;
import com.wshunli.map.tianditu.TianDiTuLayer;
import com.wshunli.map.tianditu.TianDiTuLayerTypes;

public class MainActivity extends AppCompatActivity {
    public static String TDT_PATH = android.os.Environment.getExternalStorageDirectory() + "/TDTCacheDemo";
    MapView mMapView;
    //矢量地图
    public TianDiTuLayer vec_c;
    //矢量标注
    public TianDiTuLayer cva_c;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMapView = (MapView) findViewById(R.id.map);
        vec_c = new TianDiTuLayer(TianDiTuLayerTypes.TIANDITU_VECTOR_2000, TDT_PATH);
        mMapView.addLayer(vec_c);
        cva_c = new TianDiTuLayer(TianDiTuLayerTypes.TIANDITU_VECTOR_ANNOTATION_CHINESE_2000, TDT_PATH);
        mMapView.addLayer(cva_c);
        /**
         * 解决天地图标注覆盖问题
         */
        mMapView.setOnZoomListener(new OnZoomListener() {
            @Override
            public void preAction(float v, float v1, double v2) {
            }
            @Override
            public void postAction(float v, float v1, double v2) {
                cva_c.clearTiles();
            }
        });
    }
}

5、源码分析,核心代码如下

protected byte[] getTile(int level, int col, int row) throws Exception {
        if (level > layerInfo.getMaxZoomLevel()
                || level < layerInfo.getMinZoomLevel())
            return new byte[0];
        byte[] bytes = null;
        if (cachePath != null)
            bytes = getOfflineCacheFile(cachePath, level, col, row);
        if (bytes == null) {
            String url = layerInfo.getUrl()
                    + "?service=wmts&request=gettile&version=1.0.0&layer="
                    + layerInfo.getLayerName() + "&format=tiles&tilematrixset="
                    + layerInfo.getTileMatrixSet() + "&tilecol=" + col
                    + "&tilerow=" + row + "&tilematrix=" + (level + 1);
            Map<String, String> map = null;
            bytes = com.esri.core.internal.io.handler.a.a(url, map);
            if (cachePath != null)
                AddOfflineCacheFile(cachePath, level, col, row, bytes);
        }
        return bytes;
    }

更多内容参考:README_zh_CN.10.X

ArcGIS for Android 100.0.0 及以后

1、搭建 ArcGIS for Android 环境

这部分内容在前面有详细的介绍 https://www.wshunli.com/posts/29ec97b7.html

2、添加 arcgis-android-tianditu 依赖

注意版本不同,arcgis-android-tianditu 2.0.0 以后对应 ArcGIS for Android 100 版本及以后。

// 添加 arcgis-android-tianditu 依赖
dependencies {
    implementation 'com.wshunli.map:arcgis-android-tianditu:2.0.0'
}

3、简单示例

MapView mMapView = findViewById(R.id.mapView);
ArcGISMap map = new ArcGISMap();
TianDiTuLayer vec_c = new TianDiTuLayerBuilder()
    .setLayerType(TianDiTuLayerTypes.TIANDITU_VECTOR_MERCATOR)
    .build();
map.getBasemap().getBaseLayers().add(vec_c);
mMapView.setMap(map);

缓存切片,指定缓存位置即可缓存切片。

MapView mMapView = findViewById(R.id.mapView);
ArcGISMap map = new ArcGISMap();
String cachePath = Environment.getExternalStorageDirectory().getAbsoluteFile() + "/TianDiTu100Cache";
TianDiTuLayer vec_c = new TianDiTuLayerBuilder()
    .setLayerType(TianDiTuLayerTypes.TIANDITU_VECTOR_MERCATOR)
    .setCachePath(cachePath)
    .build();
map.getBasemap().getBaseLayers().add(vec_c);
mMapView.setMap(map);

注意使用接口及调用方式不太一样。

4、支持的图层类型没有变参考前面内容。

5、源码分析

@Override
protected byte[] getTile(TileKey tileKey) {

    int level = tileKey.getLevel();
    int col = tileKey.getColumn();
    int row = tileKey.getRow();
    if (level > layerInfo.getMaxZoomLevel()
            || level < layerInfo.getMinZoomLevel())
        return new byte[0];
    byte[] bytes = null;
    if (cachePath != null)
        bytes = getOfflineCacheFile(cachePath, level, col, row);
    if (bytes == null) {
        String url = layerInfo.getUrl()
                + "?service=wmts&request=gettile&version=1.0.0&layer="
                + layerInfo.getLayerName() + "&format=tiles&tilematrixset="
                + layerInfo.getTileMatrixSet() + "&tilecol=" + col
                + "&tilerow=" + row + "&tilematrix=" + (level);

        try {
            HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
            httpConnection.setRequestMethod("GET");
            httpConnection.setConnectTimeout(5000);
            InputStream in = httpConnection.getInputStream();
            bytes = getBytes(in);
            httpConnection.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (cachePath != null) {
            AddOfflineCacheFile(cachePath, level, col, row, bytes);
        }

    }
    return bytes;
}

更多内容参考:README_zh_CN

最后欢迎 star 或者提交 PR 到本仓库。

https://github.com/wshunli/arcgis-android-tianditu

参考资料
1、ArcGIS读取天地图2.0 - ArcGIS产品与技术专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/arcgis_all/article/details/8848120
2、arcgis api for android 叠加天地图 - 阿华博台 - 博客频道 - CSDN.NET
http://blog.csdn.net/yu624774720hua/article/details/8755398
3、入门Android开发—ArcGis读取天地图,并实现一些简单功能。 - 从入门到忘记 - 博客频道 - CSDN.NET
http://blog.csdn.net/u013867301/article/details/51036200
4、arcgis for android 本地缓存 | 大光的博客
http://daguang.me/2013/08/01/arcgis-for-android-本地缓存/
5、Android开发,arcgis自定义layer-历史影像和地图缓存的实现 - 博客频道 - CSDN.NET
http://blog.csdn.net/Stanny_Bing/article/details/53736659

如果本文对您有所帮助,且您手头还很宽裕,欢迎打赏赞助我,以支付网站服务器和域名费用。 https://paypal.me/wshunli 您的鼓励与支持是我更新的最大动力,我会铭记于心,倾于博客。
本文链接:https://www.wshunli.com/posts/eeb67a5.html