ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Android 地理围栏开发实战:用 Geofencing API 创建、监视与移除围栏

Android 地理围栏开发实战:用 Geofencing API 创建、监视与移除围栏 文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载地理围栏Geofencing将用户当前位置感知与附件地点特征感知相结合开发者指定一个位置的经纬度与半径即可在兴趣点周围划出一个圆形围栏再交由 Location Services 持续监听设备的进入、驻留与离开事件。本篇基于 Android 官方培训课程中文版的「创建和监视地理围栏」一课完整讲解从权限声明、Geofence 对象构建、GeofencingRequest 触发策略、PendingIntent 封装到 IntentService 事件处理与围栏移除的端到端实现并结合仓库中 位置信息课程 的其他课时补充连接 Google Play Services、模拟位置测试等实战细节让读者能够直接落地一套可运行的地理围栏监测方案。地理围栏的核心概念与模型在动手编码之前先理解地理围栏的三个基础要素经纬度Latitude / Longitude标示兴趣位置的坐标是围栏圆心。半径Radius调整位置邻近度决定围栏的覆盖范围。转移事件Transition设备相对围栏发生的状态迁移。Location Services 支持进入GEOFENCE_TRANSITION_ENTER、离开GEOFENCE_TRANSITION_EXIT以及驻留GEOFENCE_TRANSITION_DWELL三种事件。经纬度与半径共同定义一个圆形区域或围栏。系统允许应用同时拥有多个活动的地理围栏官方文档给出的限制是每个设备用户最多 100 个。对于每个围栏Location Services 既可以发出进入和离开事件也可以要求在设备于围栏区域内停留达到指定时长后再触发事件即驻留判定。此外通过指定以毫秒为单位的截止时间expiration duration可以限制任何单个围栏的持续时间——一旦围栏过期Location Services 会自动将其删除无需开发者手动清理。如上图所示半透明圆形区域即围栏边界GEOFENCE PERIMETER蓝绿色路径代表设备从外部穿过边界的ENTER事件围栏内部的深蓝色路径代表进入后在区域内移动并达到停留时长的DWELL事件红色路径代表设备从内部穿出边界的EXIT事件。设置地理围栏监视的前置条件声明位置权限请求地理围栏监视的第一步是设置必要权限。使用地理围栏必须声明ACCESS_FINE_LOCATION精确位置权限。在应用的AndroidManifest.xml中添加如下子节点uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION/说明ACCESS_FINE_LOCATION通常也隐含了粗略位置能力若你只需要街区级精度可参考 获取最后可知位置 中仅声明ACCESS_COARSE_LOCATION的做法但地理围栏的进入/离开判定依赖较高精度的边界判定故本课程要求声明精确位置权限。在 manifest 中注册 IntentService如果希望用IntentService监听地理位置变化并处理转移事件还需要在application节点内添加一个service子节点声明服务名字application android:allowBackuptrue ... service android:name.GeofenceTransitionsIntentService/ /application创建 Google Play Services API Client所有位置 API包括地理围栏都集成在 Google Play services 中因此访问前必须创建并连接GoogleApiClient。该 client 通过GoogleApiClient.Builder构建并添加LocationServices.API具体步骤见 获取最后可知位置 一课中的buildGoogleApiClient()方法protected synchronized void buildGoogleApiClient() { mGoogleApiClient new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); }连接完成后方可调用后续的GeofencingApi.addGeofences()与removeGeofences()。GoogleApiClient连接是否就绪可以通过onConnected()回调判断这也是 获取位置更新 一课中启动周期更新的惯用时机。创建和添加地理围栏添加围栏的标准流程是用位置 API 的 Builder 类创建围栏对象用GeofencingRequest封装触发策略定义处理事件的PendingIntent最后通过 convenience 类GeofencingApi把围栏与 PendingIntent 一并提交给 Location Services。创建地理围栏对象Geofence.Builder使用Geofence.Builder创建围栏并设置想要的半径、持续时间和转移类型。例如填充一个名为mGeofenceList的列表mGeofenceList.add(new Geofence.Builder() // Set the request ID of the geofence. This is a string to identify this // geofence. .setRequestId(entry.getKey()) .setCircularRegion( entry.getValue().latitude, entry.getValue().longitude, Constants.GEOFENCE_RADIUS_IN_METERS ) .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS) .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT) .build());各构建参数的作用与取值要点方法作用备注setRequestId(String)为围栏设置请求 ID字符串类型用于唯一标识该围栏后续按 ID 删除时也依赖它setCircularRegion(lat, lng, radius)定义圆形区域经纬度 半径米为兼顾典型 WiFi 网络的位置精度并降低功耗建议最小半径设为 100 米setExpirationDuration(long)设置围栏过期时间单位毫秒过期后 Location Services 自动删除该围栏setTransitionTypes(int)声明关注的转移类型可组合GEOFENCE_TRANSITION_ENTER、GEOFENCE_TRANSITION_EXIT以及驻留DWELLbuild()生成围栏对象链式构建的收尾方法示例从固定数据源中读取位置信息填充围栏在实际应用中你完全可以依据用户当前位置动态创建围栏例如在用户签到某地后自动在该地周边划出围栏。指定围栏与初始化触发器GeofencingRequestGeofencingRequest类嵌套了GeofencingRequest.Builder用于封装需要监视的围栏列表并设置如何触发地理围栏事件private GeofencingRequest getGeofencingRequest() { GeofencingRequest.Builder builder new GeofencingRequest.Builder(); builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); builder.addGeofences(mGeofenceList); return builder.build(); }这里涉及两个转移触发器GEOFENCE_TRANSITION_ENTER设备进入围栏时触发。GEOFENCE_TRANSITION_EXIT设备离开围栏时触发。setInitialTrigger()决定应用刚注册围栏时若设备已经位于围栏内是否立即补发事件INITIAL_TRIGGER_ENTER若设备已在地理围栏内通知 Location Services 立即触发一次GEOFENCE_TRANSITION_ENTER让应用立刻感知已在范围内。INITIAL_TRIGGER_DWELL在很多场景下是更优选择——只有当设备进入围栏并停留达到预定的驻留时长后才触发事件。这能显著减少设备在围栏边缘短暂进出所产生的大量重复通知也就是垃圾警告信息。实战策略小结想让围栏事件更有价值、更省电推荐两件事——优先使用INITIAL_TRIGGER_DWELL过滤路过用户同时把围栏最小半径设为 100 米左右以贴合典型 WiFi 网络的位置精确度并降低设备功耗。为地理围栏转移定义 PendingIntentLocation Services 发出的 Intent 可以触发应用内的各种动作但不能用它直接打开 Activity 或 Fragment——应用内的组件只能在响应用户动作时才可见。大多数情况下处理这类 Intent 的最佳载体是IntentService它可以在后台推送通知、执行长时间后台作业、把 Intent 转发给其他 Service或发送广播 Intent。下面的代码展示如何定义一个PendingIntent来启动GeofenceTransitionsIntentServicepublic class MainActivity extends FragmentActivity { ... private PendingIntent getGeofencePendingIntent() { // Reuse the PendingIntent if we already have it. if (mGeofencePendingIntent ! null) { return mGeofencePendingIntent; } Intent intent new Intent(this, GeofenceTransitionsIntentService.class); // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when // calling addGeofences() and removeGeofences(). return PendingIntent.getService(this, 0, intent, PendingIntent. FLAG_UPDATE_CURRENT); }注意两点一是缓存复用——如果已经持有 PendingIntent 就直接返回避免重复创建二是必须使用FLAG_UPDATE_CURRENT标志这样在调用addGeofences()与removeGeofences()时会拿到同一个 PendingIntent 实例保证以同一身份添加、以同一身份移除的语义一致性。添加地理围栏GeofencingApi.addGeofences()使用LocationServices.GeofencingApi.addGeofences()方法添加围栏向其提供 Google API client、GeofencingRequest对象和PendingIntent。下面的代码在onResult()中处理结果假设主 Activity 实现了ResultCallbackpublic class MainActivity extends FragmentActivity { ... LocationServices.GeofencingApi.addGeofences( mGoogleApiClient, getGeofencingRequest(), getGeofencePendingIntent() ).setResultCallback(this);建议在GoogleApiClient成功连接的onConnected()回调之后再发起addGeofences()调用确保 API client 已就绪结果的成败会通过ResultCallback.onResult()异步返回开发者可据此更新 UI 或记录日志。处理地理围栏转移GeofencingEvent 与 IntentService当 Location Services 探测到用户进入或离开某个围栏它会发送一个包含在PendingIntent中的 Intent——这个 PendingIntent 正是添加围栏时随请求提交的那个。Intent 被GeofenceTransitionsIntentService这类 Service 接收后从中取出地理围栏事件判断转移类型与命中的围栏最后发出通知。下面的代码展示了如何定义一个IntentService在地理围栏转移出现时推送通知用户点击通知后应用的主 Activity 会回到前台public class GeofenceTransitionsIntentService extends IntentService { ... protected void onHandleIntent(Intent intent) { GeofencingEvent geofencingEvent GeofencingEvent.fromIntent(intent); if (geofencingEvent.hasError()) { String errorMessage GeofenceErrorMessages.getErrorString(this, geofencingEvent.getErrorCode()); Log.e(TAG, errorMessage); return; } // Get the transition type. int geofenceTransition geofencingEvent.getGeofenceTransition(); // Test that the reported transition was of interest. if (geofenceTransition Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition Geofence.GEOFENCE_TRANSITION_EXIT) { // Get the geofences that were triggered. A single event can trigger // multiple geofences. List triggeringGeofences geofencingEvent.getTriggeringGeofences(); // Get the transition details as a String. String geofenceTransitionDetails getGeofenceTransitionDetails( this, geofenceTransition, triggeringGeofences ); // Send notification and log the transition details. sendNotification(geofenceTransitionDetails); Log.i(TAG, geofenceTransitionDetails); } else { // Log the error. Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition)); } }处理逻辑的关键步骤可拆解为解析事件GeofencingEvent.fromIntent(intent)从 Intent 中还原地理围栏事件对象。检查错误geofencingEvent.hasError()判断本次事件是否携带错误码若有错误可通过getErrorCode()获取错误码并用GeofenceErrorMessages.getErrorString()转换为可读的错误信息。读取转移类型geofencingEvent.getGeofenceTransition()返回本次转移的类型与应用设定的转移类型ENTER / EXIT比对只处理关心的类型。获取命中的围栏geofencingEvent.getTriggeringGeofences()返回触发本次事件的围栏列表——单次事件可能同时触发多个围栏例如设备同时位于多个重叠围栏的边界附近。消费事件拼接转移详情、发送通知并记录日志对无效的转移类型记录错误日志如geofence_transition_invalid_type。在通过 PendingIntent 检测到转移事件之后这个 IntentService 获取转移类型、测试是否为应用用来触发通知的事件GEOFENCE_TRANSITION_ENTER或GEOFENCE_TRANSITION_EXIT然后发出通知并记录转移的详细信息。由于IntentService的onHandleIntent()在工作线程中执行即使在此处执行通知构建、网络上报等轻量级任务也不会阻塞 UI 主线程。停止地理围栏监视removeGeofences()当不再需要监视地理围栏或者想要节省设备的电池电量和 CPU 周期时应停止地理围栏监视。可以在用于添加和删除围栏的主 Activity 里发起停止操作删除围栏会导致它立即停止。API 提供两种删除方式按请求 ID 删除通过removeGeofences(GoogleApiClient, ListString geofenceRequestIds)精确删除指定围栏。按 PendingIntent 删除删除与指定 PendingIntent 相关的所有地理围栏。下面的代码通过 PendingIntent 删除地理围栏——当设备进入或离开之前已添加的围栏时停止所有相关通知LocationServices.GeofencingApi.removeGeofences( mGoogleApiClient, // This is the same pending intent that was used in addGeofences(). getGeofencePendingIntent() ).setResultCallback(this); // Result processed in onResult().注意注释中强调的关键点这里传入的 PendingIntent必须与addGeofences()时使用的是同一个实例这正是前面在getGeofencePendingIntent()中缓存复用 PendingIntent 并用FLAG_UPDATE_CURRENT保证身份一致的原因。删除结果同样通过ResultCallback异步返回。进阶用模拟位置测试地理围栏地理围栏的判定高度依赖位置数据逐台真机、逐个地点手工验证成本很高。仓库中的 使用模拟位置进行测试 一课提供了更高效的方案将 Location Services 设置为模拟模式后向它发送模拟位置对象Location Services 即可用这些模拟位置触发地理围栏事件。要点包括开启模拟模式应用需声明ACCESS_MOCK_LOCATION权限并在测试设备上开启模拟位置选项然后调用LocationClient.setMockMode(true)关闭模拟模式则调用setMockMode(false)断开 client 连接也会自动恢复内部位置提供器。发送模拟位置构造Location对象provider 需设为flp再调用LocationClient.setMockLocation(location)发送。Location Services 会将该模拟位置设为当前位置并在下一次位置更新时送出如果新位置进入某个围栏就会触发对应的围栏事件。测试数据设计对步行、骑行、驾驶、火车等不同运动模式分别构造不同的位置变化幅度——慢速运动用较小的位置步长快速运动用较大的位置步长。测试数据可以按运动模式组织为 XML、从服务器下载或用工具应用录制真实移动轨迹后回放。发送周期选择模拟位置的发送频率应参考真实位置提供器的能力例如 GPS 最快约每秒一次、WiFi 最快约每 5 秒一次室内依赖 WiFi 的场景建议将发送周期设为 5 秒。此外识别用户的当下活动 一课演示了如何用GooglePlayServicesUtil.isGooglePlayServicesAvailable()在连接位置服务前检查 Google Play services 是否可用并用getErrorDialog()引导用户修复——这套检查流程同样适用于地理围栏功能上线前的环境校验。地理围栏也可以与 周期性的位置更新 等其他位置感知特性组合使用构建更完整的位置情境应用。小结本课围绕创建和监视地理围栏给出了一条完整可落地的技术链路先声明ACCESS_FINE_LOCATION权限并在 manifest 中注册GeofenceTransitionsIntentService连接GoogleApiClient后用Geofence.Builder定义圆形围栏经纬度 半径 过期时间 转移类型用GeofencingRequest设置初始触发器推荐INITIAL_TRIGGER_DWELL减少垃圾通知半径建议不小于 100 米通过可复用的PendingIntentFLAG_UPDATE_CURRENT调用GeofencingApi.addGeofences()注册转移事件在IntentService.onHandleIntent()中经GeofencingEvent解析、校验与分发最后用removeGeofences()按 ID 或按 PendingIntent 停止监视。配合模拟位置测试与 Google Play services 可用性检查即可高效交付可靠的地理围栏功能。本课完整原文见 location/geofencing.md所属课程目录见 Android 位置信息。相关课时获取最后可知位置、获取位置更新、使用模拟位置进行测试、识别用户的当下活动。赞分享文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载相关推荐IoT-For-Beginners 地理围栏实战使用 Azure Functions 的 Twilio/SendGrid 绑定发送进入围栏通知IoT For Beginners 地理围栏实战使用 Azure Functions 的 Twilio/SendGrid 绑定发送进入围栏通知 在地理围栏G教程文档教育物联网嵌入式React Native Maps地理围栏实现区域监控和地理触发React Native Maps地理围栏实现区域监控和地理触发 React Native Maps是一个强大的跨平台地图组件为iOS和Android提供原移动开发UI组件前端QGroundControl 计划视图地理围栏GeoFence完全指南创建、编辑与上传QGroundControl 计划视图地理围栏GeoFence完全指南创建、编辑与上传 地理围栏GeoFence是 QGroundControl 计划无人机智能硬件上一篇GeoJSON.io 免费在线地理数据编辑工具完全指南下一篇如何快速集成bugsnag-android到你的Android应用5分钟上手教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表