Camera2+TextureView平板首次拍照崩溃:Surface无有效原生Surface问题求助
这个问题我之前适配平板Camera2的时候踩过坑,日志里的Surface had no valid native Surface其实是Legacy Camera模式下的典型问题——平板的Surface初始化节奏和手机不一样,首次拍照时TextureView的Surface还没完全准备好就被Camera2调用了。下面是几个亲测有效的解决办法:
1. 拍照前严格校验Surface有效性
平板的渲染线程通常比手机慢,onSurfaceTextureAvailable回调触发时,Surface可能还没完成底层native资源的初始化。所以在触发拍照前,一定要做双重校验:
// 在拍照按钮的点击事件里加判断 if (textureView.isAvailable() && textureView.getSurfaceTexture().isValid()) { // 确认Surface就绪,执行拍照 takePicture(); } else { // 延迟重试,给Surface留足初始化时间 new Handler(Looper.getMainLooper()).postDelayed(this::takePicture, 250); }
2. 避开Legacy Camera模式(硬件支持的话)
很多旧款平板会默认 fallback 到Legacy模式,这个模式对Surface的校验比Full/Limited模式严格得多。可以在初始化Camera前先检查硬件级别,优先选择支持高级别模式的相机:
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { for (String cameraId : cameraManager.getCameraIdList()) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); Integer hardwareLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); if (hardwareLevel != null && (hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL || hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)) { // 选定这个相机ID,跳过Legacy模式的相机 mTargetCameraId = cameraId; break; } } } catch (CameraAccessException e) { e.printStackTrace(); }
3. 捕获异常后重建Surface和Camera会话
如果还是出现崩溃,可以在拍照代码里捕获这个特定异常,然后重建Surface和Camera会话再重试:
try { mCaptureSession.capture(mCaptureRequest, mCaptureCallback, null); } catch (IllegalArgumentException e) { if (e.getMessage() != null && e.getMessage().contains("Surface had no valid native Surface")) { // 释放旧的SurfaceTexture textureView.getSurfaceTexture().release(); // 创建新的SurfaceTexture并绑定到TextureView textureView.setSurfaceTexture(new SurfaceTexture(0)); // 重新初始化Camera会话 recreateCameraCaptureSession(); // 延迟重试拍照 new Handler(Looper.getMainLooper()).postDelayed(this::takePicture, 300); } }
额外优化点
平板的布局测量耗时更长,建议在onWindowFocusChanged回调里再初始化Camera,确保TextureView已经完成布局和渲染:
private boolean isCameraInitialized = false; @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus && !isCameraInitialized) { // 此时View已经完全显示,Surface初始化更可靠 initCamera(); isCameraInitialized = true; } }
内容的提问来源于stack exchange,提问作者Ragini
相关产品推荐
相关产品推荐

