文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-06-06 14:07

关注

效果:

实现功能: 后台定位 地图长按添加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);
        
        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;
    }
    
    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);
        
        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);
            }
        }
    };
    
    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 ,注意要选择全量定位。
在这里插入图片描述
百度地图官网关于后台定位的讲解
百度地图官网关于地理围栏的讲解


作者:小李也有春天


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯