根据公司业务需求的展开,需要接入地图,并且在地图上画轨迹曲线以及自定义画区域等等。地图api可以接入百度,高德,或者google。下面以项目接入的高德地图api为例;
高德开放平台文档:https://lbs.amap.com/api/webservice/guide/create-project/get-key;
按照项目具体需求下载相应的SDK,放入项目libs中;
(注意为了兼容不同手机配置的地图.so文件比较多,而.so文件比较大,为了控制包大小,可以放弃部分兼容,这涉及到包大小优化,在文章里面有讲到 https://blog.youkuaiyun.com/and_caicai/article/details/105508306)
1.配置 AndroidManifest.xml 文件
在AndroidManifest.xml的application标签中配置Key:(key需要在高德开放平台创建项目获得)
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="您的Key"/>
2.在AndroidManifest.xml中配置权限:
//地图包、搜索包需要的基础权限 <!--允许程序打开网络套接字--> <uses-permission android:name="android.permission.INTERNET" /> <!--允许程序设置内置sd卡的写权限--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!--允许程序获取网络状态--> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!--允许程序访问WiFi网络信息--> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!--允许程序读写手机状态和身份--> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!--允许程序访问CellID或WiFi热点来获取粗略的位置--> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
3.配置XML布局文件 在布局xml文件中添加地图控件;
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.amap.api.maps.MapView>
4..地图展示
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.basicmap_activity);//设置对应的XML布局文件
MapView mapView = (MapView) findViewById(R.id.map);
mapView.onCreate(savedInstanceState);// 此方法必须重写
AMap aMap = mapView.getMap();
}
5.地图显示时候的一些设置
mMapTracking.onCreate(savedInstanceState);// 此方法须覆写。
//地图
if (mAMap == null) {
mAMap = mMapTracking.getMap();
}
UiSettings mUiSettings = mAMap.getUiSettings();
mUiSettings.setZoomGesturesEnabled(true);//设置地图是否可以手势缩放大小
mUiSettings.setScrollGesturesEnabled(true);//设置地图是否可以手势滑动
mUiSettings.setMyLocationButtonEnabled(false);// 设置默认定位按钮是否显示
mUiSettings.setZoomControlsEnabled(false);//设置地图默认的缩放按钮是否显示
mUiSettings.setLogoBottomMargin(-100);//隐藏logo
mAMap.moveCamera(CameraUpdateFactory.zoomTo(8));
/*将GPS定位坐标类型转换为高德*/
CoordinateConverter converter = new CoordinateConverter(context);
// CoordType.GPS 待转换坐标类型
converter.from(CoordinateConverter.CoordType.GPS);
在这里需要提一句,
* WGS84: Google Earth采用,Google Map中国范围外使用
* GCJ02: 火星坐标系,中国国家测绘局制定的坐标系统,由WGS84机密后的坐标。Google Map中国和搜搜地图使用,高德
* BD09:百度坐标,GCJ02机密后的坐标系
* 搜狗坐标系,图吧坐标等,估计也是在GCJ02基础上加密而成的
百度地图 高德地图坐标系不同,通过接口获得数据点 如果是不同坐标系需要进行转换。
6.根据坐标获取具体位置
//异步查询坐标
private void getAddressByLatlng(LatLng latLng) {
//逆地理编码查询条件:逆地理编码查询的地理坐标点、查询范围、坐标类型。
LatLonPoint latLonPoint = new LatLonPoint(latLng.latitude, latLng.longitude);
RegeocodeQuery query = new RegeocodeQuery(latLonPoint, 500f, GeocodeSearch.AMAP);
//异步查询
geocodeSearch.getFromLocationAsyn(query);
}
//异步查询结果监听
geocodeSearch = new GeocodeSearch(context);
geocodeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
@Override
public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int i) {//得到逆地理编码异步查询结果
RegeocodeAddress regeocodeAddress = regeocodeResult.getRegeocodeAddress();
String formatAddress = regeocodeAddress.getFormatAddress();
simpleAddress = formatAddress.substring(9);
if(!Tools.isEmpty(simpleAddress)){
tv_out_address.setText(simpleAddress+"");
}else{
tv_out_address.setText("");
}
DLog.e("LocusFragment","查询经纬度对应详细地址:\n" + simpleAddress);
}
@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
}
});
7.根据获取的点在地图上画轨迹曲线(及自定义画线)
/*车辆行驶轨迹*/
private void setMapTracking(final List<GPSDataBean> gpsDataList, RealTimeTruckBean bean) {
List<Integer> colorList=new ArrayList<>();
List<LatLng> latList=new ArrayList<>();
mPolylineOptions = new PolylineOptions();
mPolylineOptions.width(10);
mPolylineOptions.zIndex(10f);
markerOption = new MarkerOptions();
if (NotNull.isNotNull(bean)) {
// addTruckOnTimeMarker(bean);
}
mAMap.setOnMarkerClickListener(new AMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
LatLng latLngMarker = new LatLng(marker.getPosition().latitude, marker.getPosition().longitude);
newbounds.include(latLngMarker);
CameraUpdate mCameraUpdate = CameraUpdateFactory.newLatLngBounds(newbounds.build(), 15);
//加上这句好像点击mark后不能显示在屏幕内
// mAMap.animateCamera(mCameraUpdate);
return false;
}
});
mAMap.setOnInfoWindowClickListener(new AMap.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {
marker.hideInfoWindow();
}
});
if (!NotNull.isNotNull(gpsDataList) || gpsDataList.size() <= 0) {
mHandler.post(new Runnable() {
@Override
public void run() {
showTips("无GPS数据");
closeProgressDialog();
}
});
if (bean != null) {
if (NotNull.isNotNull(bean.getY()) && NotNull.isNotNull(bean.getX())) {
LatLng mCenterLatLng = new LatLng(Double.parseDouble(bean.getY()), Double.parseDouble(bean.getX()));
CameraUpdate mCameraUpdate = CameraUpdateFactory.newCameraPosition(new CameraPosition(mCenterLatLng, 10, 0, 0));
mAMap.animateCamera(mCameraUpdate);
}
}
return;
}
double x=0;
double y=0;
for (int i = 0; i < gpsDataList.size(); i++) {
// sourceLatLng待转换坐标点 LatLng类型
if (NotNull.isNotNull(gpsDataList.get(i).getY())&& NotNull.isNotNull(gpsDataList.get(i).getX())){
LatLng sourceLatLng = new LatLng(Double.parseDouble(gpsDataList.get(i).getY()), Double.parseDouble(gpsDataList.get(i).getX()));
converter.coord(sourceLatLng);
// 执行转换操作
LatLng desLatLng = converter.convert();
latList.add(desLatLng);
colorList.add(getColorList(gpsDataList.get(i)));
x += sourceLatLng.latitude;
y += sourceLatLng.longitude;
if (i == 0) {
converter.coord(new LatLng(Double.parseDouble(gpsDataList.get(0).getY()), Double.parseDouble(gpsDataList.get(0).getX())));
// 执行转换操作
LatLng startLatLng = converter.convert();
markerOption.position(startLatLng);
if (NotNull.isNotNull(gpsDataList.get(0).getWeight())) {
double gpsDataWeight = Double.parseDouble(gpsDataList.get(0).getWeight());
gpsWeightStart = myformat.format(gpsDataWeight);
}
markerOption.title("设备ID:" + truckModel.getDeviceId() + "\n车牌号:" + truckModel.getCarNumber() + "\n车重:" + gpsWeightStart + "(吨)").snippet("日期:" + gpsDataList.get(0).getDate());
markerOption.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.start)));
} else if (i == gpsDataList.size() - 1) {
converter.coord(new LatLng(Double.parseDouble(gpsDataList.get(gpsDataList.size() - 1).getY()), Double.parseDouble(gpsDataList.get(gpsDataList.size() - 1).getX())));
// 执行转换操作
LatLng endtLatLng = converter.convert();
markerOption.position(endtLatLng);
if (NotNull.isNotNull(gpsDataList.get(gpsDataList.size() - 1).getWeight())) {
double gpsDataWeight = Double.parseDouble(gpsDataList.get(gpsDataList.size() - 1).getWeight());
gpsWeightEnd = myformat.format(gpsDataWeight);
}
markerOption.title("设备ID:" + truckModel.getDeviceId() + "\n车牌号:" + truckModel.getCarNumber() + "\n车重:" + gpsWeightEnd + "(吨)").snippet("日期:" + gpsDataList.get(i).getDate());
markerOption.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.end)));
}
markerOption.setFlat(true);
mAMap.addMarker(markerOption);
newbounds.include(desLatLng);//轨迹全部显示在屏幕内
}
}
CameraUpdate mCameraUpdate = CameraUpdateFactory.newLatLng(new LatLng((double) (x/gpsDataList.size()),(double)(y/gpsDataList.size())));
mAMap.animateCamera(mCameraUpdate);//第二个参数为四周留空宽度.
mAMap.setMinZoomLevel(6f);
mAMap.setMaxZoomLevel(13f);
mAMap.moveCamera(CameraUpdateFactory.zoomTo(8));
mPolylineOptions.addAll(latList);
mPolylineOptions.colorValues(colorList);
mAMap.addPolyline(mPolylineOptions);
}
如果有类似如上图的轨迹曲线,曲线点没有依附在道路上,可以尝试用 高德的轨迹纠偏
https://lbs.amap.com/api/android-sdk/guide/draw-on-map/track-sdk
8.在地图上显示实时位置,并用图标标记
//添加实时位置
private void addAddr(MarkerOptions opt, OnLineTruckBean bean, String speed) {
if (NotNull.isNotNull(bean.getY()) && NotNull.isNotNull(bean.getX())) {
if (addMarker != null) {
addMarker.remove();
}
float zoom= mAMap.getCameraPosition().zoom;
if(zoom <4){
zoom=10f;
}
Bitmap bitmap = doAddBit(bean,speed);//图标
LatLng gpsLatLng = new LatLng(Double.parseDouble(bean.getY()), Double.parseDouble(bean.getX()));//当前坐标(x,y)
converter.coord(gpsLatLng);
// 执行转换操作
LatLng gdlatLng = converter.convert();
opt.position(gdlatLng);
opt.icon(BitmapDescriptorFactory.fromBitmap(bitmap));
addMarker = mAMap.addMarker(opt);
newbounds.include(gdlatLng);//轨迹全部显示在屏幕内
CameraUpdate mCameraUpdate = CameraUpdateFactory.changeLatLng(gdlatLng);//改变位置
mAMap.moveCamera(mCameraUpdate);//第二个参数为四周留空宽度.
mAMap.moveCamera(CameraUpdateFactory.zoomTo(zoom));
}
}
9.在地图自定义区域 圆或者多边形
//画圆,圆心坐标(lat1,lon) 半径r3
Double lat1 = Double.parseDouble(lat);
Double lon2 = Double.parseDouble(lon);
Double r3 = Double.parseDouble(r);
LatLng latLng = new LatLng(lat1,lon2);
Circle myCircle=mAMap.addCircle(new CircleOptions().
center(latLng).
radius(r3).
fillColor(Color.argb(170, 238, 89, 83)).
strokeColor(Color.argb(170, 13, 130, 235)).
strokeWidth(3f));
//画多边形
List<WeiLan> wllis =jsonToBeanList(data,WeiLan.class); //点list
List<LatLng> list3=new ArrayList<>();
for (int i = 0; i < wllis.size(); i++) {
WeiLan point = wllis.get(i);
Double lat1 = Double.parseDouble(point.getLat());
Double lat2 = Double.parseDouble(point.getLng());
LatLng lat = new LatLng(lat1, lat2);
list3.add(lat);
llis.add(lat);
}
// 声明 多边形参数对象
PolygonOptions polygonOptions = new PolygonOptions();
// 添加 多边形的每个顶点(顺序添加)
for (int t = 0; t < list3.size(); t++) {
LatLng latp = list3.get(t);
polygonOptions.add(latp);
}
polygonOptions.strokeWidth(4) // 多边形的边框 深绿色:#98ED84
.strokeColor(Color.argb(100, 13, 130, 235)) // 边框颜色
.fillColor(Color.argb(100, 238, 89, 83)); // 多边形的填充色
mAMap.addPolygon(polygonOptions);
效果图如下:
以上代码涉及的项目可以再github上查看:https://github.com/ctgu1988/hd_wnq-yufeng