移动地图程序的基础,在于“一张图”,外业调绘、导航类、成果展示、统计应用等都需要一张基本的底图来支撑。往往底图的好坏决定了整个移动地图的根基。
在线基础底图包括传统GIS(ArcGIS Server)和WebGIS(Online & Portal)。使用方式上确实不同,传统GIS是通过Layer直接对接地图服务(ArcGIS Server发布的)。WebGIS是同过ArcGISMap来对接WebMap。
1.传统GIS
对于一直使用ArcGIS Server发布地图服务的,可以直接使用地图服务(Layer)来加载在线的地图服务(ArcGIS Server)。
String url = "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer";
ArcGISTiledLayer arcGISTiledLayer = new ArcGISTiledLayer(url);
Basemap basemap = new Basemap(arcGISTiledLayer);
ArcGISMap arcGISMap = new ArcGISMap(basemap);
mMapView.setMap(arcGISMap);
2.WebGIS(Online & Portal)
通过Online或者Portal可以便捷快速的制作出更简洁智能的地图资源,用以表达我们的目的,对于移动端而言这些Web Map可以直接应用。
String url = "http://www.arcgis.com/home/webmap/viewer.html?webmap=55c1665bcd064552944a9e8296271ec3";
ArcGISMap arcGISMap = new ArcGISMap(url);
mMapView.setMap(arcGISMap);
Basemap basemap = arcGISMap.getBasemap(); //获取底图
LayerList operationalLayers = arcGISMap.getOperationalLayers(); //获取业务图层
3.在线矢量切片:ArcGISVectorTiledLayer
String url = "https://www.arcgis.com/home/item.html?id=e19e9330bf08490ca8353d76b5e2e658";
ArcGISVectorTiledLayer arcGISVectorTiledLayer = new ArcGISVectorTiledLayer(url);
Basemap basemap = new Basemap(arcGISVectorTiledLayer);
ArcGISMap arcGISMap = new ArcGISMap(basemap);
mMapView.setMap(arcGISMap);
Viewpoint vp = new Viewpoint(47.606726, -122.335564, 72223.819286);
arcGISMap.setInitialViewpoint(vp);
离线基础底图最传统的方式是直接拷贝ArcGIS Server服务的切片成果,存在的问题是无论使用松散型还是紧凑型都包含太多碎小文件,部署不便。
TPK文件便是为了解决多碎小文件问题。但是依然存在文件太大的问题,动辄十G甚至几十G。而矢量切片(VTPK)在于解决文件太大的问题。
1.TPK
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/yxt.tpk";
TileCache titleCache = new TileCache(path);
ArcGISTiledLayer arcGISTiledLayer = new ArcGISTiledLayer(titleCache);
Basemap basemap = new Basemap(arcGISTiledLayer);
ArcGISMap arcGISMap = new ArcGISMap(basemap);
mMapView.setMap(arcGISMap);
2.矢量切片:VTPK
String path = "/sdcard/Hymn/basemap/dzzhdjfb.vtpk";
ArcGISVectorTiledLayer mainArcGISVectorTiledLayer = new ArcGISVectorTiledLayer(path);
Basemap mainBasemap = new Basemap(mainArcGISVectorTiledLayer);
ArcGISMap mainArcGISMap = new ArcGISMap(mainBasemap);
mMapView.setMap(mainArcGISMap);
3.MMPK(Basemap)
通过ArcGIS Pro可以制作包含基础底图(Basemap)的MMPK,MMPK文件解析后,基础底图(Basemap)中的图层会解析为MobileBasemapLayer,只提供浏览功能。当然,亚洲字符的支持情况在安卓端不是特别好。
String path = "/sdcard/Hymn/basemap/MobileBasemapLayer.mmpk";
final MobileMapPackage mobileMapPackage = new MobileMapPackage(path);
mobileMapPackage.loadAsync();
mobileMapPackage.addDoneLoadingListener(new Runnable() {
@Override
public void run() {
LoadStatus loadStatus = mobileMapPackage.getLoadStatus();
if (loadStatus == LoadStatus.LOADED) {
List maps = mobileMapPackage.getMaps();
ArcGISMap arcGISMap = maps.get(0);
Basemap basemap = arcGISMap.getBasemap();
LayerList operationalLayers = arcGISMap.getOperationalLayers();
mMapView.setMap(arcGISMap);
}
}
});
在Runtime100里,MapView是通过ArcGISMap类来完成图层的管理。
ArcGISMap类是将底图和业务图层分开的,对于底图,ArcGISMap里用了Baemap类来进行管理。
上面已经介绍了加载底图,现在就讲讲底图的切换。
如果我们要切换底图时候,仅需要给ArcGISMap类重新赋值一个底图即可。
Basemap basemap = new Basemap(layer);
arcGISMap.setBasemap(basemap);
布局:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fl_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.esri.arcgisruntime.mapping.view.MapView
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent">com.esri.arcgisruntime.mapping.view.MapView>
FrameLayout>
<ListView
android:id="@+id/listview"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@android:color/background_light"
android:choiceMode="singleChoice"
android:divider="#BDBDBD"
android:dividerHeight="1dp" />
android.support.v4.widget.DrawerLayout>
Activity:
public class ChangeBasemapActivity extends AppCompatActivity {
@BindView(R.id.mapview)
MapView mMapview;
@BindView(R.id.fl_content)
FrameLayout mFlContent;
@BindView(R.id.listview)
ListView mListview;
@BindView(R.id.drawer_layout)
DrawerLayout mDrawerLayout;
private ArcGISMap mArcGISMap;
private String[] mNavigationDrawerItemTitles;
private ActionBarDrawerToggle mDrawerToggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_change_basemap);
ButterKnife.bind(this);
//侧滑页面数据
mNavigationDrawerItemTitles = getResources().getStringArray(R.array.basemap_types);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setTitle("底图切换");
}
mArcGISMap = new ArcGISMap(Basemap.Type.TOPOGRAPHIC, 47.6047381, -122.3334255, 12);
mMapview.setMap(mArcGISMap);
addDrawerItems();
setupDrawer();
}
private void addDrawerItems() {
ArrayAdapter mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
mNavigationDrawerItemTitles);
mListview.setAdapter(mAdapter);
mListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> adapterView, View view, int position, long id) {
selectBasemap(position);
}
});
}
/**
* Set up the navigation drawer
*/
private void setupDrawer() {
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
//getSupportActionBar().setTitle(mActivityTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.addDrawerListener(mDrawerToggle);
}
/**
* Select the Basemap item based on position in the navigation drawer
*
* @param position order int in navigation drawer
*/
private void selectBasemap(int position) {
// update selected item and title, then close the drawer
mListview.setItemChecked(position, true);
mDrawerLayout.closeDrawer(mListview);
// if-else is used because this sample is used elsewhere as a Library module
if (position == 0) {
// position 0 = Streets
mArcGISMap.setBasemap(Basemap.createStreets());
getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);
} else if (position == 1) {
// position 1 = Navigation Vector
mArcGISMap.setBasemap(Basemap.createNavigationVector());
getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);
} else if (position == 2) {
// position 2 = Topographic
mArcGISMap.setBasemap(Basemap.createTopographic());
getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);
} else if (position == 3) {
// position 3 = Topographic Vector
mArcGISMap.setBasemap(Basemap.createTopographicVector());
getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);
} else if (position == 4) {
// position 3 = Gray Canvas
mArcGISMap.setBasemap(Basemap.createLightGrayCanvas());
getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);
} else if (position == 5) {
// position 3 = Gray Canvas Vector
mArcGISMap.setBasemap(Basemap.createLightGrayCanvasVector());
getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Activate the navigation drawer toggle
return (mDrawerToggle.onOptionsItemSelected(item)) || super.onOptionsItemSelected(item);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
protected void onResume() {
super.onResume();
mMapview.resume();
}
@Override
protected void onPause() {
super.onPause();
mMapview.pause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapview.dispose();
}
}