android调用百度地图实现地理围栏

Rabia ·
更新时间:2024-09-20
· 899 次阅读

效果:

实现功能: 后台定位 地图长按添加marker得到当前位置经纬度坐标 创建地理围栏(以marker所在位置为中心,半径默认设置为100米) 通过BroadcastReceiver监听当前位置与围栏的位置关系 实现过程:

1. 后台定位
为了最大程度的增加定位进程的存活率,百度Android定位SDK提供后台持续定位的能力,可在应用退后台的状态下,持续记录位置信息。

首先初始化定位信息,主要是设置坐标类型等一些基本属性

// 定位初始化 private void initLocationSDK() { mClient = new LocationClient(this); LocationClientOption mOption = new LocationClientOption(); mOption.setScanSpan(5000); mOption.setCoorType("bd09ll");//设置坐标类型 mOption.setIsNeedAddress(true);//设置是否需要地址信息,默认为无地址。 mOption.setOpenGps(true); mClient.setLocOption(mOption); mClient.registerLocationListener(myLocationListener); }

初始化完成后开启后台定位功能,此时将会以5秒/次进行后台定位,及时你的应用处于后台,只要没有被清理依旧会执行定位过程,这样就可实现当应用处于后台仍然会执行的功能,比如在导航过程中进行当前坐标实时实施上传。

private void startBackgroundLocation() { if (isEnableLocInForeground) { //关闭后台定位(true:通知栏消失;false:通知栏可手动划除) mClient.disableLocInForeground(true); isEnableLocInForeground = false; mForegroundBtn.setText("前台定位"); mClient.stop(); } else { //开启后台定位 mClient.enableLocInForeground(1, notification); isEnableLocInForeground = true; mForegroundBtn.setText("后台定位"); mClient.start(); } } 为地图设置长按监听事件,在地图上长按选点并将该点设置成为地理围栏的中心点 public void longClickAddMaker() { mBaiduMap.clear(); //清除地图上的marker标志 mBaiduMap.setOnMapLongClickListener(new BaiduMap.OnMapLongClickListener() { @Override public void onMapLongClick(LatLng latLng) { if (latLng != null) { if (isOnLongClickEnable) { latitude = latLng.latitude; longitude = latLng.longitude; //Dest_BD09LL_End = new LatLng(latLng.latitude, latLng.longitude); Toast.makeText(DeleveryInfo.this, "" + latitude + " fff " + longitude, Toast.LENGTH_SHORT).show(); mBitmap = BitmapDescriptorFactory.fromResource(R.drawable.icon_openmap_mark); //用来构造InfoWindow //响应点击的OnInfoWindowClickListener----为marker添加点击事件 InfoWindow.OnInfoWindowClickListener listener = new InfoWindow.OnInfoWindowClickListener() { @Override public void onInfoWindowClick() { // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // popuInfoFlag = 1; // dhPopupView(); // } Toast.makeText(DeleveryInfo.this, "点击了添加的marker图标", Toast.LENGTH_LONG).show(); } }; //构造InfoWindow //point 描述的位置点 -100 InfoWindow相对于point在y轴的偏移量 InfoWindow mInfoWindow = new InfoWindow(mBitmap, new LatLng(latitude, longitude), -100, listener); mBaiduMap.showInfoWindow(mInfoWindow);//使InfoWindow生效 isOnLongClickEnable = false; //禁止添加marker } } } }); } 创建地理围栏 (默认半径为100米) private void initGeoFenceClient() { fenceClient = new GeoFenceClient(getApplicationContext());// 1 创建地理围栏客户端 IntentFilter filter = new IntentFilter(); //注册 filter.addAction(GEOFENCE_BROADCAST_ACTION); registerReceiver(mGeoFenceReceiver, filter); /** * 创建pendingIntent */ fenceClient.createPendingIntent(GEOFENCE_BROADCAST_ACTION); fenceClient.isHighAccuracyLoc(true); // 在即将触发侦听行为时允许开启高精度定位模式(开启gps定位,gps定位结果优先) fenceClient.setGeoFenceListener(DeleveryInfo.this); /** * 设置地理围栏的触发行为,默认为进入 */ fenceClient.setActivateAction(GeoFenceClient.GEOFENCE_IN); } private void addRoundFence() { // String customId = etCustomId.getText().toString(); // String radiusStr = etRadius.getText().toString(); if (null == new LatLng(latitude, longitude) || TextUtils.isEmpty("100")||latitude ==0.0) { Toast.makeText(getApplicationContext(), "参数不全", Toast.LENGTH_SHORT) .show(); return; } DPoint centerPoint = new DPoint(latitude, longitude); //fenceRadius = Float.parseFloat(radiusStr); fenceClient.addGeoFence(centerPoint, GeoFenceClient.BD09LL, 100, "1");//fenceRadius, "1"); } 创建BroadcastReceiver来监听当前坐标与围栏的关系 private BroadcastReceiver mGeoFenceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 接收广播 if (intent.getAction().equals(GEOFENCE_BROADCAST_ACTION)) { Bundle bundle = intent.getExtras(); String customId = bundle .getString(GeoFence.BUNDLE_KEY_CUSTOMID); String fenceId = bundle.getString(GeoFence.BUNDLE_KEY_FENCEID); GeoFence geoFence = bundle.getParcelable(GeoFence.BUNDLE_KEY_FENCE); int status = bundle.getInt(GeoFence.BUNDLE_KEY_FENCESTATUS); int locType = bundle.getInt(GeoFence.BUNDLE_KEY_LOCERRORCODE); StringBuffer sb = new StringBuffer(); switch (status) { case GeoFence.INIT_STATUS_IN: sb.append("围栏初始状态:在围栏内"); Toast.makeText(DeleveryInfo.this, "在里面", Toast.LENGTH_SHORT).show(); break; case GeoFence.INIT_STATUS_OUT: sb.append("围栏初始状态:在围栏外"); Toast.makeText(DeleveryInfo.this, "在围栏外", Toast.LENGTH_SHORT).show(); break; case GeoFence.STATUS_LOCFAIL: sb.append("定位失败,无法判定目标当前位置和围栏之间的状态"); Toast.makeText(DeleveryInfo.this, "无法判定目标当前位置和围栏之间的状态", Toast.LENGTH_SHORT).show(); break; case GeoFence.STATUS_IN: sb.append("进入围栏 "); break; case GeoFence.STATUS_OUT: sb.append("离开围栏 "); break; default: break; } if (status != GeoFence.STATUS_LOCFAIL) { if (!TextUtils.isEmpty(customId)) { sb.append(" customId: " + customId); } sb.append(" fenceId: " + fenceId); } String str = sb.toString(); Message msg = Message.obtain(); msg.obj = str; msg.what = 2; handler2.sendMessage(msg); } } };

xml文件中只有一个button按钮,就不展示了。

完整代码: public class DeleveryInfo extends AppCompatActivity implements View.OnClickListener, BaiduMap.OnMapClickListener, GeoFenceListener { double latitude; //长按的精度 double longitude;// 长按的纬度 // 地理围栏的广播action private static final String GEOFENCE_BROADCAST_ACTION = "liyue.edu.ncst.cn.mymap.DeleveryInfo"; private GeoFenceClient fenceClient; //创建地理围栏 private float fenceRadius; //要创建的围栏的半径 private HashMap fenceMap = new HashMap(); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SDKInitializer.initialize(getApplicationContext()); SDKInitializer.setCoordType(CoordType.BD09LL); setContentView(R.layout.activity_delevery_info); initViews(); initLocationSDK(); //初始化定位 // settingLocInForeground();//设置后台定位 startBackgroundLocation(); //开始后台定位 initGeoFenceClient(); } // 定位初始化 private void initLocationSDK() { mClient = new LocationClient(this); LocationClientOption mOption = new LocationClientOption(); mOption.setScanSpan(5000); mOption.setCoorType("bd09ll");//设置坐标类型 mOption.setIsNeedAddress(true);//设置是否需要地址信息,默认为无地址。 mOption.setOpenGps(true); mClient.setLocOption(mOption); mClient.registerLocationListener(myLocationListener); } private void startBackgroundLocation() { if (isEnableLocInForeground) { //关闭后台定位(true:通知栏消失;false:通知栏可手动划除) mClient.disableLocInForeground(true); isEnableLocInForeground = false; mForegroundBtn.setText("前台定位"); mClient.stop(); } else { //开启后台定位 mClient.enableLocInForeground(1, notification); isEnableLocInForeground = true; mForegroundBtn.setText("后台定位"); mClient.start(); } } class MyLocationListener extends BDAbstractLocationListener { @Override public void onReceiveLocation(BDLocation bdLocation) { if (bdLocation == null || mMapView == null) { return; } if (isFirstLoc) { //如果是第一次定位 LatLng ll = null; ll = getMostAccuracyLocation(bdLocation); if (ll == null) { return; } isFirstLoc = false; points.add(ll);//加入集合 last = ll; if (ll.latitude != 4.9E-324) //定位失败时不显示 locateAndZoom(bdLocation, ll); } LatLng point = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude()); if (DistanceUtil.getDistance(last, point) > 1) {//比较两次定位点间的距离 if (bdLocation.getLatitude() != 4.9E-324) { //判断当前定位点是否正确 points.add(point);//如果要运动完成后画整个轨迹,位置点都在这个集合中 last = point; locateAndZoom(bdLocation, point); //当非第一次定位时也要执行定位图标显示 OverlayOptions dotOption = new DotOptions().center(point).color(0xAAA9A9A9); mBaiduMap.addOverlay(dotOption); Dest_BD09LL_Start = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());//设置导航的起点点坐标 myLocation = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude()); } } } } private LatLng getMostAccuracyLocation(BDLocation location) { if (location.getRadius() > 45) {//gps位置精度大于40米的点直接弃用 return null; } LatLng ll = new LatLng(location.getLatitude(), location.getLongitude()); if (DistanceUtil.getDistance(last, ll) > 5) { last = ll; points.clear();//有任意连续两点位置大于10,重新取点 return null; } points.add(ll); last = ll; //有5个连续的点之间的距离小于10,认为gps已稳定,以最新的点为起始点 if (points.size() >= 2) { points.clear(); return ll; } return null; } /** * @Description: 构建mapstatus参数显示定位图标 * @CreateDate: 2020/4/17 23:59 */ private void locateAndZoom(final BDLocation location, LatLng ll) { locData = new MyLocationData.Builder().accuracy(0) // 此处设置开发者获取到的方向信息,顺时针0-360 .direction(location.getDirection()).latitude(location.getLatitude()) .longitude(location.getLongitude()).build(); mBaiduMap.setMyLocationData(locData); MapStatus.Builder builder = new MapStatus.Builder(); mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build())); } private void initGeoFenceClient() { fenceClient = new GeoFenceClient(getApplicationContext());// 1 创建地理围栏客户端 IntentFilter filter = new IntentFilter(); //注册 filter.addAction(GEOFENCE_BROADCAST_ACTION); registerReceiver(mGeoFenceReceiver, filter); /** * 创建pendingIntent */ fenceClient.createPendingIntent(GEOFENCE_BROADCAST_ACTION); fenceClient.isHighAccuracyLoc(true); // 在即将触发侦听行为时允许开启高精度定位模式(开启gps定位,gps定位结果优先) fenceClient.setGeoFenceListener(DeleveryInfo.this); /** * 设置地理围栏的触发行为,默认为进入 */ fenceClient.setActivateAction(GeoFenceClient.GEOFENCE_IN); } Object lock = new Object(); void drawFence2Map() { new Thread() { @Override public void run() { try { synchronized (lock) { if (null == fenceList || fenceList.isEmpty()) { return; } for (GeoFence fence : fenceList) { if (fenceMap.containsKey(fence.getFenceId())) { continue; } drawFence(fence); fenceMap.put(fence.getFenceId(), fence); } } } catch (Throwable e) { } } }.start(); } private void drawFence(GeoFence fence) { switch (fence.getType()) { case GeoFence.TYPE_ROUND: drawCircle(fence, false); break; } } private void drawCircle(GeoFence fence, boolean isPoi) { LatLng center; int radius; if (isPoi) { BDLocation bdLocation = new BDLocation(); bdLocation.setLatitude(fence.getCenter().getLatitude()); bdLocation.setLongitude(fence.getCenter().getLongitude()); BDLocation tempLocation = LocationClient .getBDLocationInCoorType(bdLocation, BDLocation.BDLOCATION_GCJ02_TO_BD09LL); center = new LatLng(tempLocation.getLatitude(), tempLocation.getLongitude()); } else { center = new LatLng(latitude, longitude); } radius = (int) fence.getRadius(); // 绘制一个圆形 if (center == null) { return; } mBaiduMap.addOverlay(new CircleOptions().center(center) .radius(radius) .fillColor(0xAA0000FF) // 填充颜色 .stroke(new Stroke(5, 0xAA00ff00))); } @SuppressLint("HandlerLeak") Handler handler2 = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: StringBuffer sb = new StringBuffer(); sb.append("添加围栏成功"); String customId = (String) msg.obj; if (!TextUtils.isEmpty(customId)) { sb.append("customId: ").append(customId); } Toast.makeText(getApplicationContext(), sb.toString(), Toast.LENGTH_SHORT).show(); drawFence2Map(); break; case 1: int errorCode = msg.arg1; Toast.makeText(getApplicationContext(), "添加围栏失败,errorcode = " + errorCode, Toast.LENGTH_SHORT).show(); break; case 2: break; default: break; } } }; /** * 接收触发围栏后的广播,当添加围栏成功之后,会立即对所有围栏状态进行一次侦测,只会发送一次围栏和位置之间的初始状态; * 当触发围栏之后也会收到广播,对于同一触发行为只会发送一次广播不会重复发送,除非位置和围栏的关系再次发生了改变。 */ private BroadcastReceiver mGeoFenceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 接收广播 if (intent.getAction().equals(GEOFENCE_BROADCAST_ACTION)) { Bundle bundle = intent.getExtras(); String customId = bundle .getString(GeoFence.BUNDLE_KEY_CUSTOMID); String fenceId = bundle.getString(GeoFence.BUNDLE_KEY_FENCEID); GeoFence geoFence = bundle.getParcelable(GeoFence.BUNDLE_KEY_FENCE); int status = bundle.getInt(GeoFence.BUNDLE_KEY_FENCESTATUS); int locType = bundle.getInt(GeoFence.BUNDLE_KEY_LOCERRORCODE); StringBuffer sb = new StringBuffer(); switch (status) { case GeoFence.INIT_STATUS_IN: sb.append("围栏初始状态:在围栏内"); Toast.makeText(DeleveryInfo.this, "在里面", Toast.LENGTH_SHORT).show(); break; case GeoFence.INIT_STATUS_OUT: sb.append("围栏初始状态:在围栏外"); Toast.makeText(DeleveryInfo.this, "在围栏外", Toast.LENGTH_SHORT).show(); break; case GeoFence.STATUS_LOCFAIL: sb.append("定位失败,无法判定目标当前位置和围栏之间的状态"); Toast.makeText(DeleveryInfo.this, "无法判定目标当前位置和围栏之间的状态", Toast.LENGTH_SHORT).show(); break; case GeoFence.STATUS_IN: sb.append("进入围栏 "); break; case GeoFence.STATUS_OUT: sb.append("离开围栏 "); break; case GeoFence.STATUS_STAYED: sb.append("在围栏内停留超过10分钟 "); break; default: break; } if (status != GeoFence.STATUS_LOCFAIL) { if (!TextUtils.isEmpty(customId)) { sb.append(" customId: " + customId); } sb.append(" fenceId: " + fenceId); } String str = sb.toString(); Message msg = Message.obtain(); msg.obj = str; msg.what = 2; handler2.sendMessage(msg); } } }; /** * @Description: geoFenceList - - 本次创建的围栏列表(创建成功才有,不成功为空) * errorCode - - 错误码 * customId - - 本次操作对应的自定义业务ID(如果有,如果添加的时候没有设置customId,回调中也不会有) * @Author: LiYue * @CreateDate: 2020/4/24 19:31 */ List fenceList = new ArrayList(); @Override public void onGeoFenceCreateFinished(final List geoFenceList, int errorCode, String customId) { Message msg = Message.obtain(); if (errorCode == GeoFence.ADDGEOFENCE_SUCCESS) { fenceList.addAll(geoFenceList); msg.obj = customId; msg.what = 0; } else { msg.arg1 = errorCode; msg.what = 1; } handler2.sendMessage(msg); } /** * 添加圆形围栏 */ private void addRoundFence() { // String customId = etCustomId.getText().toString(); // String radiusStr = etRadius.getText().toString(); if (null == new LatLng(latitude, longitude) || TextUtils.isEmpty("100")||latitude ==0.0) { Toast.makeText(getApplicationContext(), "参数不全", Toast.LENGTH_SHORT) .show(); return; } DPoint centerPoint = new DPoint(latitude, longitude); //fenceRadius = Float.parseFloat(radiusStr); fenceClient.addGeoFence(centerPoint, GeoFenceClient.BD09LL, 100, "1");//fenceRadius, "1"); } @Override protected void onDestroy() { super.onDestroy(); mMapView.getMap().clear(); mMapView.onDestroy(); mMapView = null; mClient.disableLocInForeground(true); // 关闭前台定位服务 mClient.unRegisterLocationListener(myLocationListener); // 取消之前注册的 BDAbstractLocationListener 定位监听函数 mBaiduMap.setMyLocationEnabled(false); mClient.stop();// 停止定位sdk try { unregisterReceiver(mGeoFenceReceiver); //注销广播 } catch (Throwable e) { } if (null != fenceClient) { fenceClient.removeGeoFence(); // 地理围栏客户端 } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mMapView.onSaveInstanceState(outState); }

最后,如果要想实现地理围栏的话要到百度地图官网下载相应的Android 定位 SDK ,注意要选择全量定位。
在这里插入图片描述
百度地图官网关于后台定位的讲解
百度地图官网关于地理围栏的讲解


作者:小李也有春天



百度地图 地图 地理 Android

需要 登录 后方可回复, 如果你还没有账号请 注册新账号