ARCore 中文文档 下载 App

ARCore Session 生命周期正确管理

Session 的生命周期模型

ARCore Session 是一个长生命周期对象——它的生命周期和 Activity/Fragment 对齐,但内部状态有自己的变化规律:

Session 创建
    ↓
configure() → 设置模式和 API
    ↓
resume() → 开始 SLAM 跟踪(Camera ON)
    ↓
每一帧 update() → 处理最新画面,获取 Frame 和 Trackable
    ↓
pause() → 停止跟踪(Camera OFF),Session 保留
    ↓
resume() → 恢复跟踪(Camera 重新 ON)
    ↓
destroy()(可选)→ 释放所有资源

一个 Session 对象可以 resume/pause 任意次——不需要每次都 new 新的。

Activity 各阶段的正确做法

onCreate:创建 Session(但不 resume)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // 1. 检查设备是否支持
    val availability = ArCoreApk.getInstance().checkAvailability(this)
    if (availability.isUnsupported) {
        finish()
        return
    }

    // 2. 请求安装 Google Play Services for AR(首次打开)
    if (availability == ArCoreApk.Availability.SUPPORTED_NOT_INSTALLED ||
        availability == ArCoreApk.Availability.SUPPORTED_APK_TOO_OLD) {
        ArCoreApk.getInstance().requestInstall(this, true)
        return  // 用户装完后 Activity 会自动重建,走到这里
    }

    // 3. 创建 Session(只创建一次)
    try {
        arSession = Session(this)
    } catch (e: UnavailableException) {
        // 设备完全不支持
        finish()
        return
    }

    // 4. 配置 Session(只需要配置一次,后续 resume 不需要重配)
    arSession?.configure(
        Session.Config(this).apply {
            // 在这里设置所有 API 模式
        }
    )
}

onResume:恢复 Session + 开启渲染循环

override fun onResume() {
    super.onResume()

    if (arSession == null) return

    // 1. 恢复 Session(打开摄像头,开始 SLAM)
    try {
        arSession?.resume()
    } catch (e: CameraException) {
        // 摄像头被其他应用占用
        showCameraBusyError()
        return
    }

    // 2. 开启 GLSurfaceView(恢复渲染)
    glSurfaceView?.onResume()

    // 3. 启动帧更新回调(每一帧调用 session.update())
    startFrameLoop()
}

onPause:暂停 Session + 停止渲染循环

override fun onPause() {
    super.onPause()

    // 1. 停止帧更新回调(先停渲染循环,防止渲染 Pause 后的 Session)
    stopFrameLoop()

    // 2. 暂停 Session(关闭摄像头,停止 SLAM)
    arSession?.pause()

    // 3. 暂停 GLSurfaceView
    glSurfaceView?.onPause()
}

onDestroy:可选的 destroy

override fun onDestroy() {
    super.onDestroy()

    // destroy 不是必须的,但如果你确定不再使用这个 Session,
    // 调用它可以释放 GL 资源和 native 内存
    arSession?.destroy()
    arSession = null
}

帧更新循环

Session.update() 是 ARCore 的核心——必须在每一帧调用,在 GL 渲染之前:

// GLSurfaceView.Renderer 中
override fun onDrawFrame(gl: GL10?) {
    // 1. Session.update() —— 必须在任何渲染之前调用
    val frame = try {
        arSession?.update()
    } catch (e: SessionException) {
        // Session 已经 pause,忽略这一帧
        return
    } ?: return

    // 2. 更新 Trackable(平面、特征点、Augmented Image 等)
    // 3. 用 frame.camera.pose 渲染摄像头画面
    // 4. 在适当位置叠加虚拟物体
}

帧循环频率

Session.update() 的调用频率决定了 ARCore 的更新频率:

注意:不要把 Session.update() 放在后台线程里——它必须在 GL 渲染线程中串行调用,否则会有线程安全问题。

常见的生命周期坑

坑一:onPause 时不关 Session

// 错误
override fun onPause() {
    super.onPause()
    // 忘记 pause Session!
    // 结果:摄像头一直开着、SLAM 一直跑、电池疯狂消耗
}

坑二:resume/pause 的顺序反了

// 错误顺序
override fun onPause() {
    glSurfaceView?.onPause()  // 先关渲染
    arSession?.pause()         // 再关 Session
    // 问题:关渲染后 Session 还在跑,浪费几毫秒
}

// 正确顺序
override fun onPause() {
    arSession?.pause()         // 先停 Session(Camera OFF)
    glSurfaceView?.onPause()  // 再关渲染
}

坑三:每次 onResume 都重新创建 Session

// 错误
override fun onResume() {
    arSession = Session(this)  // 每次都 new!
    // 结果:旧 Session 没被 destroy → 内存泄漏 + 摄像头资源没释放
}

// 正确
override fun onResume() {
    if (arSession == null) {
        arSession = Session(this)
    }
    arSession?.resume()
}

坑四:Activity 旋转屏幕

// 错误:Activity 配置变更会触发重建
// 如果 Activity 在 Manifest 中声明了 configChanges,onCreate 不会再被调用
// Session 可能处于不一致状态

// 正确:要么在 Manifest 中声明,要么处理生命周期
<activity
    android:configChanges="orientation|screenSize|keyboardHidden" />

坑五:Fragment 中的 Session

// Fragment 的生命周期和 Activity 不同
// Session 最好由 Activity 管理,Fragment 通过 ViewModel 共享
// 不要在 Fragment.onDestroyView() 里 destroy Session
// 因为 View 销毁了但 Activity 还活着

Unity 中的 Session 生命周期

Unity AR Foundation 自动处理 Session 生命周期:

需要手动干预时:

var sessionManager = GetComponent<ARSessionManager>();

// 手动暂停
sessionManager.enabled = false;

// 手动恢复
sessionManager.enabled = true;

后台恢复的注意事项

当用户把应用切到后台再切回来时:

组件状态恢复行为
SessionPausedResume 后 SLAM 从当前位置继续跟踪
摄像头关闭Resume 后重新打开
Trackable保留之前检测到的 Plane/Anchor 仍然存在
Cloud Anchors保留托管/解析状态不变

Session 会丢失的情况:

这些情况下 Session 需要重新创建,之前的本地 Anchor 全部丢失。Cloud Anchors 不受影响(在云端)。