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)
问题根源
- 启动购买页面时,系统将当前Activity压入后台,SurfaceView的Surface被销毁,但Native层的OpenGL渲染线程未完全暂停,仍尝试调用无上下文的OpenGL API,导致崩溃。
- 购买流程结束恢复应用时,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
相关产品推荐
相关产品推荐

