1.为什么升级100.0
我之前在公司做地图一直用的是arcgis10.2,经过多年的开发,这个版本的工具类封装的非常方便,自己也没有时间去换100.0的版本。但是突然有一天工程反馈说他的9.0的安卓手机打开地图直接崩溃,在网上找了半天没有解决arcgis10在9.0手机上的兼容问题,所以只好去换最先的100.0了。但是100.0与10.0的api完全不同,在开发中踩了许多坑,所以了这篇文章希望能帮到之后遇到同样问题的同学。
下面代码如果有错误请大神指出,我会及时改正
2.集成ArcGIS Runtime SDK
集成方式在官方文档中有介绍
1.首先要在build.gradle文件中添加Esri的仓库
allprojects {
repositories {
google()
jcenter()
maven {
url 'https://esri.bintray.com/arcgis'
}
}
}
2.第二步添加依赖
dependencies {
implementation 'com.esri.arcgisruntime:arcgis-android:100.4.0'
}
3.根据官方文档要求在app模块build.gradle文件中添加如下代码设置java兼容版本
android {
[...]
module.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
4.最后一步添加权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
3.代码
首先直接上全部代码
public class MainPresenter extends BasePresenter implements MainContract.Presenter {
public static final String POLYLINE = "POLYLINE";//测量距离
public static final String POLYGON = "POLYGON";//测量面积
public static final String IDENTIFY = "IDENTIFY";//要素识别
public static final String NULL = "NULL";//什么都不做
private MapView mapView;
private ArcGISMap arcGISMap;
private GraphicsOverlay graphicsOverlay;
private String MapOperationType = NULL;
boolean isCanRotate = true;
private View contentview;
private TextView tv;
private ImageView iv;
private Callout callout;
private final MainContract.View iView;
private DecimalFormat df;
private SimpleDateFormat formatter;
Map<String,List<LayerFieldBean.FieldModels>> map=new HashMap<>();
public MainPresenter(BaseContract.View view) {
super(view);
iView = (MainContract.View) getmView();
}
//初始化地图
@SuppressLint("ClickableViewAccessibility")
@Override
public void initMap() {
mapView = iView.getMapView();
mapView.setAttributionTextVisible(false);
arcGISMap = new ArcGISMap();
//底图地址
String theURLString = common.Constance.BASE_MAP;
ArcGISTiledLayer mainArcGISVectorTiledLayer = new ArcGISTiledLayer(theURLString);
arcGISMap.setBasemap(new Basemap(mainArcGISVectorTiledLayer));
mapView.setMap(arcGISMap);
//新建并添加绘画图层
graphicsOverlay = new GraphicsOverlay();
mapView.getGraphicsOverlays().add(graphicsOverlay);
//添加地图的点击事件监听
mapView.setOnTouchListener(new DefaultMapViewOnTouchListener(iView.getContext(), mapView) {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
switch (MapOperationType) {
case NULL:
return super.onSingleTapConfirmed(e);
case POLYLINE:
//距离测量
Point clickPoint = mapView.screenToLocation(new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY())));
MeasuringDistance(clickPoint);
return true;
case POLYGON:
//测量面积
Point clickPoint2 = mapView.screenToLocation(new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY())));
MeasuringArea(clickPoint2);
return true;
case IDENTIFY:
//要素识别
android.graphics.Point screenPoint = new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY()));
if (arcGISMap.getOperationalLayers().size() > 0) {
// IdentifyFeatures(screenPoint);
IdentifyAllFeatures(screenPoint);
} else {
iView.showError(R.string.not_cxmap_error);
}
return true;
}
return super.onSingleTapConfirmed(e);
}
@Override
public boolean onRotate(MotionEvent event, double rotationAngle) {
//控制是否可以旋转地图
if (isCanRotate) {
return super.onRotate(event, rotationAngle);
} else {
return true;
}
}
});
//初始化范围
arcGISMap.setInitialViewpoint(new Viewpoint(new Point(542420.836330969, 2559890.377991153, SpatialReference.create(4547)), 60000));
//获取所有的图层的要显示字段
iView.showLoading();
String URL = common.Constance.LAYERFIELD;
HttpUtils.requstNet(URL, null, new IRequst() {
@Override
public void onSuccess(String string) {
iView.dismissLoading();
try {
ArrayList<LayerFieldBean> list = (ArrayList<LayerFieldBean>) GsonUtils.fromJsonForList(string, LayerFieldBean.class);
for (LayerFieldBean item : list) {
List<LayerFieldBean.FieldModels> li= map.get(item.getTableName());
if(li==null){
li=new ArrayList<>();
map.put(item.getTableName(),li);
}
List<LayerFieldBean.FieldModels> fieldModels = item.getFieldModels();
if(fieldModels!=null){
for(LayerFieldBean.FieldModels f:fieldModels)
li.add(f);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onError(int code) {
iView.dismissLoading();
}
});
}
//地图操作——测量距离
@Override
public void MapOperation_MeasuringDistance() {
MapOperationType = POLYLINE;
}
//地图操作——测量面积
@Override
public void MapOperation_MeasuringArea() {
MapOperationType = POLYGON;
}
//地图操作——要素查询
@Override
public void MapOperation_IdentifyFeatures() {
MapOperationType = IDENTIFY;
}
//地图操作——清除所有操作
@Override
public void MapOperation_NULL() {
MapOperationType = NULL;
MDlist.clear();
MAlist.clear();
graphicsOverlay.getGraphics().clear();
Callout callout = mapView.getCallout();
callout.dismiss();
}
//地图操作——地图放大
@Override
public void MapOperation_Amplification() {
double scale = mapView.getMapScale();
mapView.setViewpointScaleAsync(scale * 0.5);
}
//地图操作——地图缩小
@Override
public void MapOperation_Shrink() {
double scale1 = mapView.getMapScale();
mapView.setViewpointScaleAsync(scale1 * 2);
}
//图层操作——切换底图
@Override
public void MapViewAddBaseLayer(String url) {
ArcGISTiledLayer mainArcGISVectorTiledLayer = new ArcGISTiledLayer(url);
arcGISMap.setBasemap(new Basemap(mainArcGISVectorTiledLayer));
}
//图层操作——添加专题图层
@Override
public void MapViewAddLayor(String url) {
LayerList mainLayerList = arcGISMap.getOperationalLayers();
ArcGISMapImageLayer imageLayer = new ArcGISMapImageLayer(url);
imageLayer.setId(url);
mainLayerList.add(imageLayer);
//添加FeatureLayer为了要素查询
FeatureTable featureTable = new ServiceFeatureTable(url);
FeatureLayer mFeatureLayer = new FeatureLayer(featureTable);
mFeatureLayer.setOpacity(0.1f);
mFeatureLayer.setId(url + "selected");
arcGISMap.getOperationalLayers().add(mFeatureLayer);
}
//图层操作——删除专题图层(根据地图url删除对应的图层)
@Override
public void MapViewRemoveLayor(String url) {
LayerList mainLayerList = arcGISMap.getOperationalLayers();
for (Layer layer : mainLayerList) {
if (TextUtils.equals(url, layer.getId())) {
mainLayerList.remove(layer);
break;
}
}
for (Layer layer : mainLayerList) {
if (TextUtils.equals(url + "selected", layer.getId())) {
mainLayerList.remove(layer);
break;
}
}
}
//地图操作——设置是否可以旋转
@Override
public void setCanRotate(boolean tag) {
isCanRotate = tag;
}
//地图操作——设置旋转角度
@Override
public void setAngle(double angle) {
mapView.setViewpointRotationAsync(angle);
}
@Override
public void start() {
}
@Override
public void destroy() {
}
/**
* 测量长度
*/
ArrayList<Point> MDlist = new ArrayList<>();
private void MeasuringDistance(Point clickPoint) {
SimpleMarkerSymbol simpleMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, Color.RED, 10);
Graphic pointGraphic = new Graphic(clickPoint, simpleMarkerSymbol);
if (MDlist.size() == 0 || (MDlist.get(MDlist.size() - 1).getX() != clickPoint.getX() && MDlist.get(MDlist.size() - 1).getY() != clickPoint.getY()))
MDlist.add(clickPoint);
PointCollection borderCAtoNV = new PointCollection(mapView.getSpatialReference());
for (Point p : MDlist) {
borderCAtoNV.add(p);
}
Polyline polyline = new Polyline(borderCAtoNV);
SimpleLineSymbol fillSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.BLUE, 5);
Graphic lineGraphic = new Graphic(polyline, fillSymbol);
ListenableList listenableList = graphicsOverlay.getGraphics();
listenableList.clear();
listenableList.add(lineGraphic);
for (Point p : MDlist)
listenableList.add(new Graphic(p, simpleMarkerSymbol));
String longstr = calculateDistance(MDlist);
callout = mapView.getCallout();
if (contentview == null) {
contentview = LinearLayout.inflate(iView.getContext(), R.layout.mapview_content, null);
tv = contentview.findViewById(R.id.id_content_tv);
iv = contentview.findViewById(R.id.id_contentclose_iv);
}
tv.setText(longstr);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MDlist.remove(MDlist.size() - 1);
if (MDlist.size() >= 1) {
MeasuringDistance(MDlist.get(MDlist.size() - 1));
} else {
graphicsOverlay.getGraphics().clear();
callout.dismiss();
}
}
});
callout.show(contentview, MDlist.get(MDlist.size() - 1));
}
/**
* 计算长度
* @param list 点的集合
* @return
*/
private String calculateDistance(ArrayList<Point> list) {
if (df == null) {
df = new DecimalFormat("0.000");
}
double overallLength = 0;
if (list != null && list.size() > 1) {
for (int i = 1; i < list.size(); i++) {
Point p1 = list.get(i - 1);
Point p2 = list.get(i);
LinearUnit linearUnit = new LinearUnit(LinearUnitId.METERS);//距离单位
AngularUnit angularUnit = new AngularUnit(AngularUnitId.DEGREES);//角度单位
double distanceValue = GeometryEngine.distanceGeodetic(p1, p2, linearUnit, angularUnit, GeodeticCurveType.GEODESIC).getDistance();
overallLength += distanceValue;
}
}
if (overallLength >= 1000) {
overallLength /= 1000;
return df.format(overallLength) + "千米";
}
return df.format(overallLength) + "米";
}
/**
* 测量面积
*/
ArrayList<Point> MAlist = new ArrayList<>();
private void MeasuringArea(Point clickPoint) {
SimpleMarkerSymbol simpleMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, Color.RED, 10);
Graphic pointGraphic = new Graphic(clickPoint, simpleMarkerSymbol);
if (MAlist.size() == 0 || (MAlist.get(MAlist.size() - 1).getX() != clickPoint.getX() && MAlist.get(MAlist.size() - 1).getY() != clickPoint.getY()))
MAlist.add(clickPoint);
PointCollection borderCAtoNV = new PointCollection(mapView.getSpatialReference());
for (Point p : MAlist) {
borderCAtoNV.add(p);
}
Polygon polygon = new Polygon(borderCAtoNV);
SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.DIAGONAL_CROSS, Color.BLUE, null);
Graphic fillGraphic = new Graphic(polygon, fillSymbol);
ListenableList listenableList = graphicsOverlay.getGraphics();
listenableList.clear();
listenableList.add(fillGraphic);
for (Point p : MAlist)
listenableList.add(new Graphic(p, simpleMarkerSymbol));
String longstr = calculateArea(polygon);
callout = mapView.getCallout();
if (contentview == null) {
contentview = LinearLayout.inflate(iView.getContext(), R.layout.mapview_content, null);
tv = contentview.findViewById(R.id.id_content_tv);
iv = contentview.findViewById(R.id.id_contentclose_iv);
}
tv.setText(longstr);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MAlist.remove(MAlist.size() - 1);
if (MAlist.size() >= 1) {
MeasuringArea(MAlist.get(MAlist.size() - 1));
} else {
graphicsOverlay.getGraphics().clear();
callout.dismiss();
}
}
});
callout.show(contentview, MAlist.get(MAlist.size() - 1));
}
/**
* 计算面积
*
* @param polygon 面要素
* @return
*/
private String calculateArea(Polygon polygon) {
if (df == null) {
df = new DecimalFormat("0.000");
}
double overallArea = 0;
overallArea = GeometryEngine.area(polygon);
//注意!测量面积时如果点的顺序如果是逆时针的,面积有可能是负数,需要处理一下
if (overallArea < 0) {
polygon = (Polygon) GeometryEngine.simplify(polygon);
overallArea = GeometryEngine.area(polygon);
}
if (overallArea >= 1000000) {
overallArea /= 1000000;
return df.format(overallArea) + "平方千米";
}
return df.format(overallArea) + "平方米";
}
/**
* I查询所有可见图层
*
* @param screenPoint
*/
DecimalFormat decimalFormat;
private void IdentifyAllFeatures(android.graphics.Point screenPoint) {
iView.showLoading();
final ListenableFuture<List<IdentifyLayerResult>> listListenableFuture = mapView.identifyLayersAsync(
screenPoint, 12, false, 10);
listListenableFuture.addDoneListener(new Runnable() {
@Override
public void run() {
iView.dismissLoading();
try {
//IdentifyLayerResult:每个图层的返回结果
List<IdentifyLayerResult> identifyLayerResults = listListenableFuture.get();
if (identifyLayerResults != null && identifyLayerResults.size() > 0) {
int count = 0;
List<Map<String, Object>> attributes = new ArrayList<>();
List<String>names=new ArrayList<>();
List<Geometry> geometrys = new ArrayList<>();
for (IdentifyLayerResult identifyLayerResult : identifyLayerResults) {
String name = identifyLayerResult.getLayerContent().getName();
Log.e("xyh", "run: " + name);
List<GeoElement> elements = identifyLayerResult.getElements();
if (elements.size() > 0) {
count++;
GeoElement element = elements.get(0);
Map<String, Object> attribute = element.getAttributes();
attributes.add(attribute);
names.add(name);
Geometry geometry = element.getGeometry();
geometrys.add(geometry);
if (count >= 3) {
break;
}
}
}
if (geometrys.size() > 0 && attributes.size() > 0) {
FeaturesToMap(attributes, geometrys,names);
}
}
} catch (Exception e) {
iView.showError(R.string.not_element_error);
}
}
});
}
/**
* 要素识别
*
* @param screenPoint
*/
private void IdentifyFeatures(android.graphics.Point screenPoint) {
iView.showLoading();
LayerList list = arcGISMap.getOperationalLayers();
FeatureLayer mFeatureLayer = null;
for (int i = list.size() - 1; i > 0; i--) {
Layer layer = arcGISMap.getOperationalLayers().get(i);
if (layer instanceof FeatureLayer) {
mFeatureLayer = (FeatureLayer) layer;
break;
}
}
if (mFeatureLayer != null) {
//查询mFeatureLayer图层中点击范围内的所有地理要素
final ListenableFuture<IdentifyLayerResult> identifyLayerResultListenableFuture = mapView.identifyLayerAsync(
mFeatureLayer, screenPoint, 12, false, 10);
identifyLayerResultListenableFuture.addDoneListener(new Runnable() {
@Override
public void run() {
iView.dismissLoading();
try {
IdentifyLayerResult identifyLayerResult = identifyLayerResultListenableFuture.get();
String name = identifyLayerResult.getLayerContent().getName();
Log.e("xyh", "run: " + name);
List<GeoElement> elements = identifyLayerResult.getElements();
if (elements.size() > 0) {
GeoElement element = elements.get(0);
Map<String, Object> attributes = element.getAttributes();
Geometry geometry = element.getGeometry();
//查询结果显示
// FeaturesToMap(attributes,geometry);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
} else {
iView.dismissLoading();
}
}
//I查询结果显示到地图上
private void FeaturesToMap(List<Map<String, Object>> attributes, List<Geometry> geometrys) {
}
@Override
public void SearchToMap(QueryResultBean2.HitsItem qrb, boolean isaddtososoids) {
QueryResultBean2._source source = qrb.get_source();
double y = source.getNorth();
double x = source.getEast();
Point p = new Point(x, y);
BitmapDrawable image = (BitmapDrawable) iView.getContext().getResources().getDrawable(R.mipmap.d);
PictureMarkerSymbol symbol = new PictureMarkerSymbol(image);
Graphic graphic = new Graphic(p, symbol);
ListenableList listenableList = graphicsOverlay.getGraphics();
listenableList.clear();
listenableList.add(graphic);
zoomToScale(p, mapView.getMapScale());
callout = mapView.getCallout();
View view = LayoutInflater.from(iView.getContext()).inflate(R.layout.callout_layout, null);
TextView tv1 = (TextView) view.findViewById(R.id.callout_tv1);
TextView tv2 = (TextView) view.findViewById(R.id.callout_tv2);
ImageButton callout_clous = (ImageButton) view.findViewById(R.id.callout_clous);
tv1.setText(source.getName());
tv2.setText("地址:" + source.getAddname());
callout.setContent(view);
callout.setLocation(p);
// callout.setOffset(0, DisplayUtils.dp2px(MainActivity.this, 25));
Callout.Style calloutStyle = callout.getStyle();
//设置尖尖角的位置,尖尖显示在气泡的下放,
calloutStyle.setLeaderPosition(Callout.Style.LeaderPosition.LEFT_MIDDLE);
calloutStyle.setBorderColor(R.color.colorDominantTone);
calloutStyle.setCornerRadius(0);
// calloutStyle.setCornerCurveDp(0, mContext);
callout.setStyle(calloutStyle);
callout_clous.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
callout.dismiss();
// graphicsOverlay.getGraphics().
}
});
callout.show();
}
/**
* 以一点为中心放大或缩小
*
* @param point
* @param scale 比例尺
*/
private void zoomToScale(Point point, double scale) {
mapView.setViewpointCenterAsync(point, scale);
}
public Symbol getSymbol(String typeName) {
int color = Color.RED;
if (typeName.equalsIgnoreCase("point")) {
SimpleMarkerSymbol sms = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, color, 10);
return sms;
} else if (typeName.equalsIgnoreCase("polyline")) {
SimpleLineSymbol fillSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, color, 5);
return fillSymbol;
} else {
SimpleFillSymbol sfs = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.RED, null);
return sfs;
}
}
}
4.几个注意点
1.100.0之后没有设置初始化范围的方法(setExtent())了,想要初始化范围需要利用中心点和比例尺来确定范围。
arcGISMap.setInitialViewpoint()
2.测量面积时,如果点的方向是逆时针的话,会出现负数。所以我们要加个判断,如果是负数需要
GeometryEngine.simplify()方法处理一下。
overallArea = GeometryEngine.area(polygon);
if (overallArea < 0) {
polygon = (Polygon) GeometryEngine.simplify(polygon);
overallArea = GeometryEngine.area(polygon);
}