ARCore Cloud Anchor托管状态监听优化方案咨询
优化ARCore Cloud Anchor状态监听的方案
问题描述
我正在开发一款共享增强现实(AR)体验应用,想了解是否存在更优方案,可获知ARCore服务器完成Cloud Anchor托管的时机。目前我采用的实现方式是在MainActivity的onCreate函数中调用:
customArFragment.arSceneView.scene.addOnUpdateListener(arHandler::onUpdateFrame)
具体处理类代码如下:
class ArHandler( val fragment: ArFragment, val activity: Activity, val snackbarHelper: SnackbarHelper ) { fun onUpdateFrame(frameTime: FrameTime) { checkUpdatedAnchor() } @Synchronized private fun checkUpdatedAnchor() { if (appAnchorState != AppAnchorState.HOSTING && appAnchorState != AppAnchorState.RESOLVING) { return } val cloudState = cloudAnchor?.cloudAnchorState Log.i("CheckUpdatedAnchor", cloudState.toString()) if (appAnchorState === AppAnchorState.HOSTING) { if (cloudState != null) { if (cloudState.isError) { snackbarHelper.showMessage( activity, activity.getString(R.string.hosting_error) + cloudState ) appAnchorState = AppAnchorState.NONE } else if (cloudState == Anchor.CloudAnchorState.SUCCESS) { appAnchorState = AppAnchorState.HOSTED if (anchorTask == AnchorTask.CREATE) { storeManager.nextShortCode(object : StoreManager.ShortCodeListener { override fun onShortCodeAvailable(shortCode: Int?) { myShortCode = shortCode if (shortCode == null) { snackbarHelper.showMessage( activity, "Could not get shortCode" ) return } cloudAnchor?.let { storeManager.storeUsingShortCode(shortCode, it.cloudAnchorId) } snackbarHelper.showMessage( activity, "Anchor hosted! Cloud Short Code: " + shortCode ) } }) } else if (anchorTask == AnchorTask.UPDATE) { myShortCode?.let { sc -> cloudAnchor?.let { ca -> storeManager.updateCloudAnchorID( sc, ca.cloudAnchorId ) snackbarHelper.showMessage( activity, "Anchor Updated!: " + myShortCode ) } } } } } } else if (appAnchorState == AppAnchorState.RESOLVING) { if (cloudState != null) { if (cloudState.isError) { snackbarHelper.showMessage( activity, "Error resolving anchor.. " + cloudState ) appAnchorState = AppAnchorState.NONE } else if (cloudState == Anchor.CloudAnchorState.SUCCESS) { snackbarHelper.showMessage( activity, "Anchor resolved successfully" ) appAnchorState = AppAnchorState.RESOLVED } } } } fun createCloudAnchor(customArFragment: CustomArFragment, anchor: Anchor) { this.cloudAnchor = customArFragment.arSceneView.session.hostCloudAnchor(anchor) this.anchorTask = AnchorTask.CREATE this.appAnchorState = ArHandler.AppAnchorState.HOSTING snackbarHelper.showMessage(activity, activity.getString(R.string.hosting_anchor)) this.cloudAnchor?.let { this.placeObject(it, Uri.parse("ArcticFox_Posed.sfb")) } } }
我认为这种通过SceneForm每帧回调检查锚点状态的“监听”方式不够合理,想请教是否有更好的实现思路?
优化方案
Great question! 每帧轮询云锚点状态确实不是最高效的做法——ARCore其实提供了专门的addOnCloudAnchorStateListener接口,能让你直接响应状态变化,不用在每帧做无意义的检查。下面是具体的重构思路和代码示例:
核心思路
不用给场景绑定OnUpdateListener,而是在创建或解析云锚点时,直接给ARCore的Session注册状态监听器。这个监听器只会在云锚点状态发生变化时触发,既节省资源,也更符合ARCore的设计逻辑。
重构后的代码示例
首先修改createCloudAnchor方法,在托管云锚点时添加监听器:
fun createCloudAnchor(customArFragment: CustomArFragment, anchor: Anchor) { val session = customArFragment.arSceneView.session this.cloudAnchor = session.hostCloudAnchor(anchor) this.anchorTask = AnchorTask.CREATE this.appAnchorState = AppAnchorState.HOSTING snackbarHelper.showMessage(activity, activity.getString(R.string.hosting_anchor)) this.cloudAnchor?.let { this.placeObject(it, Uri.parse("ArcticFox_Posed.sfb")) } // 注册云锚点状态监听器 session.addOnCloudAnchorStateListener { cloudAnchor, cloudAnchorState -> // 只处理当前目标云锚点的状态变化 if (cloudAnchor != this.cloudAnchor) return@addOnCloudAnchorStateListener handleCloudAnchorStateChange(cloudAnchorState) } } // 单独提取状态变化处理逻辑,提升代码可读性 @Synchronized private fun handleCloudAnchorStateChange(cloudState: Anchor.CloudAnchorState) { Log.i("CloudAnchorState", cloudState.toString()) when(appAnchorState) { AppAnchorState.HOSTING -> { if (cloudState.isError) { snackbarHelper.showMessage( activity, activity.getString(R.string.hosting_error) + cloudState ) appAnchorState = AppAnchorState.NONE } else if (cloudState == Anchor.CloudAnchorState.SUCCESS) { appAnchorState = AppAnchorState.HOSTED handleHostSuccess() } } AppAnchorState.RESOLVING -> { if (cloudState.isError) { snackbarHelper.showMessage( activity, "Error resolving anchor.. " + cloudState ) appAnchorState = AppAnchorState.NONE } else if (cloudState == Anchor.CloudAnchorState.SUCCESS) { snackbarHelper.showMessage( activity, "Anchor resolved successfully" ) appAnchorState = AppAnchorState.RESOLVED } } else -> return // 忽略无关状态 } } // 提取托管成功后的处理逻辑 private fun handleHostSuccess() { if (anchorTask == AnchorTask.CREATE) { storeManager.nextShortCode(object : StoreManager.ShortCodeListener { override fun onShortCodeAvailable(shortCode: Int?) { myShortCode = shortCode if (shortCode == null) { snackbarHelper.showMessage( activity, "Could not get shortCode" ) return } cloudAnchor?.let { storeManager.storeUsingShortCode(shortCode, it.cloudAnchorId) } snackbarHelper.showMessage( activity, "Anchor hosted! Cloud Short Code: " + shortCode ) } }) } else if (anchorTask == AnchorTask.UPDATE) { myShortCode?.let { sc -> cloudAnchor?.let { ca -> storeManager.updateCloudAnchorID( sc, ca.cloudAnchorId ) snackbarHelper.showMessage( activity, "Anchor Updated!: " + myShortCode ) } } } }
额外优化建议
- 清理监听器:当不再需要云锚点时(比如活动销毁、锚点被移除),记得调用
session.removeOnCloudAnchorStateListener()避免内存泄漏。 - 分离关注点:把状态处理、成功逻辑拆成独立方法,让代码更易维护和调试。
- 避免冗余检查:因为监听器只在状态变化时触发,所以不用额外判断状态是否更新,直接处理新状态即可。
内容的提问来源于stack exchange,提问作者Ivan Carrasco Alonso
相关产品推荐
相关产品推荐

