最近需要實現一個地理圍欄相關的功能。
專案是和騎行相關的,主要是當遊客或者騎友定位地址進入到對應的景點的地理圍欄裡面,則播報景點相關的報導語音。
接到需求之後,我開始檢視高德的相關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();
}
}
複製程式碼
使用的是系統自帶的播放器
其實難點就在於圍欄的繪製那塊