安卓开发:触发Geofence后如何获取其关联点位的详细信息
实现方案
核心逻辑是利用Geofence的requestId作为唯一关联标识,建立requestId和航点信息的映射关系,触发事件时通过ID查询对应航点的完整信息。
第一步:修正现有代码bug
你当前的GeoFenceHelper的getGeoFence方法存在两个问题:
- 传入的ID参数未被使用,自行生成了UUID作为
requestId,导致无法和业务层的航点关联 - 静态UUID变量被赋值为null,调用
UUID.randomUUID()时会触发空指针异常
第二步:创建航点实体类
用于存储航点的所有业务信息,实现Parcelable接口方便跨组件传递:
public class WayPoint implements Parcelable { private String id; private double latitude; private double longitude; private String description; // 可自行扩展其他字段,比如航点名称、类型等 public WayPoint(String id, double latitude, double longitude, String description) { this.id = id; this.latitude = latitude; this.longitude = longitude; this.description = description; } // Parcelable实现代码 protected WayPoint(Parcel in) { id = in.readString(); latitude = in.readDouble(); longitude = in.readDouble(); description = in.readString(); } public static final Creator<WayPoint> CREATOR = new Creator<WayPoint>() { @Override public WayPoint createFromParcel(Parcel in) { return new WayPoint(in); } @Override public WayPoint[] newArray(int size) { return new WayPoint[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(id); dest.writeDouble(latitude); dest.writeDouble(longitude); dest.writeString(description); } // Getter方法 public String getId() { return id; } public double getLatitude() { return latitude; } public double getLongitude() { return longitude; } public String getDescription() { return description; } }
第三步:建立ID-航点映射存储
如果仅需运行时使用,用单例HashMap存储即可;如果需要APP重启后仍能关联,可将映射关系持久化到SharedPreferences或Room数据库。
public class WayPointStore { private static WayPointStore instance; private final Map<String, WayPoint> wayPointMap = new HashMap<>(); private WayPointStore() {} public static synchronized WayPointStore getInstance() { if (instance == null) { instance = new WayPointStore(); } return instance; } // 新增航点映射 public void addWayPoint(WayPoint wayPoint) { wayPointMap.put(wayPoint.getId(), wayPoint); } // 根据ID查询航点 public WayPoint getWayPointById(String requestId) { return wayPointMap.get(requestId); } // 需要持久化可自行添加存储到本地、从本地加载的方法 }
第四步:改造地理围栏创建逻辑
修正GeoFenceHelper的getGeoFence方法
public class GeoFenceHelper extends ContextWrapper { // 删掉原来的错误UUID静态变量 PendingIntent pendingIntent; // ... 其他原有方法不变 public List <Geofence> getGeoFence (String ID, LatLng latLng, float radius, int transitionTypes) { List<Geofence> returnGeoFenceList = new ArrayList<>(); // 直接使用传入的航点ID作为Geofence的requestId returnGeoFenceList.add( new Geofence.Builder() .setCircularRegion(latLng.latitude, latLng.longitude, radius) .setRequestId(ID) .setTransitionTypes(transitionTypes) .setLoiteringDelay(2000) .setExpirationDuration(Geofence.NEVER_EXPIRE) .build()); return returnGeoFenceList; } }
改造添加围栏的业务方法
// 调用时传入实际的航点对象,而非仅传经纬度 private void addGeoFence(WayPoint wayPoint, float radius) { // 先将航点存入映射表 WayPointStore.getInstance().addWayPoint(wayPoint); List<Geofence> geofence = geoFenceHelper.getGeoFence(wayPoint.getId(), new LatLng(wayPoint.getLatitude(), wayPoint.getLongitude()), radius, Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT); GeofencingRequest geofencingRequest = geoFenceHelper.getGeoFencingRequest(geofence); PendingIntent pendingIntent = geoFenceHelper.getPendingIntent(); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } geofencingClient.addGeofences(geofencingRequest, pendingIntent) .addOnSuccessListener(unused -> { // 自定义成功逻辑 }) .addOnFailureListener(e -> { // 自定义失败逻辑 }); }
第五步:在广播接收器中获取航点信息
@Override public void onReceive(Context context, Intent intent) { notifactionHelper = new NotifactionHelper(context); GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); if (geofencingEvent.hasError()) { Log.d("geoferror", "onReceive: Geofence even has error.."); return; } List<Geofence> triggeredGeofenceList = geofencingEvent.getTriggeringGeofences(); Location triggerLocation = geofencingEvent.getTriggeringLocation(); double lat = triggerLocation.getLatitude(); double lon = triggerLocation.getLongitude(); int transitionType = geofencingEvent.getGeofenceTransition(); for (Geofence geofence : triggeredGeofenceList) { String requestId = geofence.getRequestId(); // 查询对应的航点信息 WayPoint triggeredWayPoint = WayPointStore.getInstance().getWayPointById(requestId); if (triggeredWayPoint != null) { // 拿到航点信息后自定义后续逻辑 switch (transitionType) { case Geofence.GEOFENCE_TRANSITION_ENTER: Toast.makeText(context, "进入航点:" + triggeredWayPoint.getDescription(), Toast.LENGTH_SHORT).show(); // 通知可直接展示航点信息 notifactionHelper.sendNotification("附近有航点:" + triggeredWayPoint.getDescription(), "打开应用查看详情", RouteActivity.class); break; case Geofence.GEOFENCE_TRANSITION_DWELL: Toast.makeText(context, "在航点范围内:" + triggeredWayPoint.getDescription(), Toast.LENGTH_SHORT).show(); break; case Geofence.GEOFENCE_TRANSITION_EXIT: Toast.makeText(context, "离开航点:" + triggeredWayPoint.getDescription(), Toast.LENGTH_SHORT).show(); break; } // 将航点信息发送到其他Activity Intent broadcastIntent = new Intent("TESTER"); broadcastIntent.putExtra("wayPoint", triggeredWayPoint); broadcastIntent.putExtra("lat", lat); broadcastIntent.putExtra("lon", lon); context.sendBroadcast(broadcastIntent); } } }
内容的提问来源于stack exchange,提问作者user16878083
相关产品推荐
相关产品推荐

