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

SurfaceView暂停恢复实现及应用最小化后无法恢复问题排查

一、如何实现SurfaceView的暂停与恢复?

核心实现逻辑

结合你提供的SDLSurface类,SurfaceView的暂停与恢复需同步处理Java层和Native层(SDL)的状态:

暂停流程

  • Java层操作:在handlePause()中注销传感器监听,避免后台不必要的资源消耗;同时通过surfaceDestroyed回调通知Native层停止渲染。
    public void handlePause() {
        enableSensor(Sensor.TYPE_ACCELEROMETER, false);
    }
    
    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        Log.v("SDL", "surfaceDestroyed()");
        // 标记Native层进入暂停状态
        SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
        SDLActivity.handleNativeState();
        mIsSurfaceReady = false;
        // 通知Native层销毁Surface相关资源
        SDLActivity.onNativeSurfaceDestroyed();
    }
    
  • Native层操作:在onNativeSurfaceDestroyed中释放OpenGL上下文、停止渲染线程,确保无残留的GPU操作。

恢复流程

  • Java层操作:在handleResume()中恢复传感器监听、重新获取视图焦点;通过surfaceCreated和surfaceChanged回调触发Native层重建渲染环境。
    public void handleResume() {
        setFocusable(true);
        setFocusableInTouchMode(true);
        requestFocus();
        enableSensor(Sensor.TYPE_ACCELEROMETER, true);
    }
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.v("SDL", "surfaceCreated()");
        // 通知Native层创建Surface
        SDLActivity.onNativeSurfaceCreated();
    }
    
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // ... 分辨率适配逻辑 ...
        if (!skip) {
            SDLActivity.onNativeSurfaceChanged();
            mIsSurfaceReady = true;
            // 标记Native层进入恢复状态
            SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED;
            SDLActivity.handleNativeState();
        }
    }
    
  • Native层操作:在onNativeSurfaceCreated中重建OpenGL上下文,onNativeSurfaceChanged恢复渲染线程,重新启动画面绘制。

二、应用最小化后无法恢复问题分析与解决

问题描述

应用启动页通过BillingManager发起购买操作,未启动购买流程时最小化可正常恢复;但启动购买页面后再最小化,应用无法恢复,日志报错:

2023-10-29 16:33:43.324 8592-25240/com.controlledbattles.bigbattlesimulator.app E/libEGL: call to OpenGL ES API with no current context (logged once per thread)

问题根源

  1. 启动购买页面时,系统将当前Activity压入后台,SurfaceView的Surface被销毁,但Native层的OpenGL渲染线程未完全暂停,仍尝试调用无上下文的OpenGL API,导致崩溃。
  2. 购买流程结束恢复应用时,Surface重建后Native层的OpenGL上下文未正确重建,状态切换不彻底。

具体修复方案

1. 强制暂停时的Native层同步

修改surfaceDestroyed方法,确保Native层完全暂停后再销毁Surface资源:

@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
    Log.v("SDL", "surfaceDestroyed()");

    SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
    SDLActivity.handleNativeState();
    // 增加等待逻辑,确保Native线程完成暂停
    synchronized (SDLActivity.getContext()) {
        try {
            SDLActivity.getContext().wait(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    mIsSurfaceReady = false;
    SDLActivity.onNativeSurfaceDestroyed();
}

2. 优化恢复时的上下文重建

在surfaceChanged中优先重建OpenGL上下文,再恢复Native渲染:

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    // ... 原有分辨率适配、skip判断逻辑 ...

    if (!skip) {
        // 先重建OpenGL上下文
        SDLActivity.onNativeSurfaceCreated();
        SDLActivity.onNativeSurfaceChanged();
        mIsSurfaceReady = true;

        SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED;
        SDLActivity.handleNativeState();
    }
}

3. 同步Billing流程与Surface生命周期

发起购买前手动暂停Surface,购买结束后恢复:

// 发起购买前调用
sdlSurface.handlePause();
// 启动购买流程
billingManager.launchBillingFlow(activity, billingFlowParams);

// 购买结果回调中恢复Surface
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    // ... 处理购买结果逻辑 ...
    sdlSurface.handleResume();
    // 强制触发Surface重建(如果未自动触发)
    if (!sdlSurface.mIsSurfaceReady) {
        sdlSurface.getHolder().setFixedSize(sdlSurface.getWidth(), sdlSurface.getHeight());
    }
}

4. 检查Native层上下文管理

确保Native层正确处理上下文的销毁与重建:

void onNativeSurfaceDestroyed() {
    if (eglContext != EGL_NO_CONTEXT) {
        eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        eglDestroyContext(eglDisplay, eglContext);
        eglContext = EGL_NO_CONTEXT;
    }
}

void onNativeSurfaceCreated() {
    // 重新创建EGL上下文并绑定
    eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
}

内容的提问来源于stack exchange,提问作者Eypro Corp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 15:19:50