最近需要實現一個地理圍欄相關的功能。
項目是和騎行相關的,主要是當游客或者騎友定位地址進入到對應的景點的地理圍欄里面,則播報景點相關的報道語音。
接到需求之后,我開始查看高德的相關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 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> pointList = fence.getPointList();
if (null == pointList || pointList.isEmpty()) {
return;
}
for (List subList : pointList) {
List lst = new ArrayList();
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();
}
}
復制代碼
使用的是系統自帶的播放器
其實難點就在于圍欄的繪制那塊