You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

安卓开发:触发Geofence后如何获取其关联点位的详细信息

实现方案

核心逻辑是利用Geofence的requestId作为唯一关联标识,建立requestId和航点信息的映射关系,触发事件时通过ID查询对应航点的完整信息。

第一步:修正现有代码bug

你当前的GeoFenceHelper的getGeoFence方法存在两个问题:

  1. 传入的ID参数未被使用,自行生成了UUID作为requestId,导致无法和业务层的航点关联
  2. 静态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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 17:06:05