高德地图-地理围栏功能实现

Posted by lizubing1992 on 01-12,2019

最近需要实现一个地理围栏相关的功能。

项目是和骑行相关的,主要是当游客或者骑友定位地址进入到对应的景点的地理围栏里面,则播报景点相关的报道语音。

接到需求之后,我开始查看高德的相关API,由于围栏是多边形的,则需要后台提供对应的围栏的经纬度数据,

1.创建地理围栏客户端

fenceClient = new GeoFenceClient(mContext);
IntentFilter filter = new IntentFilter(
    ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(GEOFENCE_BROADCAST_ACTION);
//注册地理围栏广播
registerReceiver(mGeoFenceReceiver, filter);
fenceClient.createPendingIntent(GEOFENCE_BROADCAST_ACTION);
fenceClient.setActivateAction(GeoFenceClient.GEOFENCE_IN);

地理围栏广播可以接收到客户定位是否在围栏内部,主要是用来处理围栏相关的操作

2.根据围栏客户端创建地理围栏


list = new ArrayList<>();
String lnglatGaode = encloseEntity.getLnglatGaode();
ArrayList<LnglatGaodeEntity> gaodeList = new GsonImpl()
  .toList(lnglatGaode, LnglatGaodeEntity.class);
for (LnglatGaodeEntity entity : gaodeList) {
latLng = new DPoint(StringUtils.parseDouble(entity.getLat()),
    StringUtils.parseDouble(entity.getLng()));
list.add(latLng);
}
DPoint firstLng = new DPoint(StringUtils.parseDouble(gaodeList.get(0).getLat()),
  StringUtils.parseDouble(gaodeList.get(0).getLng()));
list.add(firstLng);
//后台提供的围栏list数据,围栏对应的id
fenceClient.addGeoFence(list, encloseEntity.getSrcurl());

围栏数据由于是不规则的,则需要根据一系列的经纬度集合直接画出来,这样一切相关的程序就准备好

3.围栏广播相关处理

  private BroadcastReceiver mGeoFenceReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      LogUtils.w("mGeoFenceReceiver---------------------");
      // 接收广播
      if (intent.getAction().equals(GEOFENCE_BROADCAST_ACTION)) {
        Bundle bundle = intent.getExtras();
        //获取对应的围栏的语音url地址
        String customId = bundle
            .getString(GeoFence.BUNDLE_KEY_CUSTOMID);
        String fenceId = bundle.getString(GeoFence.BUNDLE_KEY_FENCEID);
        GeoFence fence = bundle.getParcelable(GeoFence.BUNDLE_KEY_FENCE);
        //status标识的是当前的围栏状态,不是围栏行为
        int status = bundle.getInt(GeoFence.BUNDLE_KEY_FENCESTATUS);
        StringBuffer sb = new StringBuffer();
        switch (status) {
          case GeoFence.STATUS_LOCFAIL:
            sb.append("定位失败");
            break;
          case GeoFence.STATUS_IN:
            sb.append("进入围栏 ");
            openMediaPlay(customId);
            break;
          case GeoFence.STATUS_OUT:
            sb.append("离开围栏 ");
            mediaPlayer.pause();
            break;
          case GeoFence.STATUS_STAYED:
            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;
        mHandler.sendMessage(msg);
      }
    }
  };

这里使用message主要是为了让对应的状态status按照队列发送,不至于乱,获取对应的语音url就可以播放了

4.查看对应的handlerMessage

@Override
public void handleMessage(Message msg) {
    super.handleMessage(msg);
    switch (msg.what) {
      case 0:
        //绘制多边形
        drawFence2Map();
        break;
      case 1:
        //围栏添加失败
        int errorCode = msg.arg1;
        break;
      case 2:
        //其他status数据类型
        String statusStr = (String) msg.obj;
        break;
      default:
        break;
    }
}

//依次绘制多边形
private void drawFence2Map() {
    new Thread() {
      @Override
      public void run() {
        try {
          synchronized (lock) {
            if (null == fenceList || fenceList.isEmpty()) {
              return;
            }
            for (GeoFence fence : fenceList) {
              LogUtils.w("fence--id" + fence.getFenceId() + "---Custom--" + fence.getCustomId());
              if (fenceMap.containsKey(fence.getFenceId())) {
                continue;
              }
              drawPolygon(fence);
              fenceMap.put(fence.getFenceId(), fence);
            }
          }
        } catch (Throwable e) {

        }
      }
    }.start();
  }


private void drawPolygon(GeoFence fence) {
    final List<List<DPoint>> pointList = fence.getPointList();
    if (null == pointList || pointList.isEmpty()) {
      return;
    }
    for (List<DPoint> subList : pointList) {
      List<LatLng> lst = new ArrayList<LatLng>();
      PolygonOptions polygonOption = new PolygonOptions();
      for (DPoint point : subList) {
        lst.add(new LatLng(point.getLatitude(), point.getLongitude()));
        boundsBuilder.include(
            new LatLng(point.getLatitude(), point.getLongitude()));
      }
      polygonOption.addAll(lst);
      polygonOption.zIndex(2);
      polygonOption.strokeColor(Color.argb(255, 255, 20, 147))
          .fillColor(Color.argb(50, 255, 20, 147)).strokeWidth(2);
      aMap.addPolygon(polygonOption);
    }
}

这里加上绘制多边形的围栏方便测试围栏效果

5.播放和暂停对应的音乐

private void openMediaPlay(String mp3) {
    try {
      if (!srcMp3.equals(mp3)) {
        mediaPlayer.setDataSource(Net.HOST + Net.PREFIX + mp3);
      }
      srcMp3 = mp3;
      mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
      // 通过异步的方式装载媒体资源
      mediaPlayer.prepareAsync();
      mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
          // 装载完毕回调
          mediaPlayer.start();
        }
      });
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

使用的是系统自带的播放器

其实难点就在于围栏的绘制那块


0评论