-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
Description
When integrating Camera X Preview into my project, a brief black screen appears when navigating to the page that contains the preview. I suspect this issue is caused by the camera not being fully initialized before the preview is displayed.
Steps to Reproduce
-
Integrate Camera X Preview according to the official documentation.
-
Navigate to the page where the Camera X Preview is hosted.
-
Observe the screen state immediately after entering the page.
Expected Behavior
The Camera X Preview should display the camera feed smoothly and immediately when entering the page, without any black screen interruption.
Actual Behavior
A black screen is shown for a short period (about 0.5-2 seconds) before the camera preview finally appears.
Possible Cause
The camera initialization process (such as opening the camera hardware, configuring preview parameters) is not completed before the preview view is rendered. As a result, the preview view cannot display valid camera data immediately and shows a black screen temporarily.
Environment
-
Camera X Version: 1.4.0
-
Android OS Version: Android 11
-
Device Model: Xperia 5II
Additional Information
I have followed the official Camera X integration guide to set up the preview use case. The initialization code is called in the onCreate or onViewCreated method of the fragment/activity. Is there a recommended way to ensure that the preview is only displayed after the camera is fully initialized to avoid this black screen issue?
package com.example.detect;
import android.Manifest;
import android.content.pm.PackageManager;
import android.hardware.camera2.CaptureRequest;
import android.os.Bundle;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.camera2.interop.Camera2Interop;
import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.Preview;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import androidx.camera.core.resolutionselector.ResolutionStrategy;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CameraXActivity extends AppCompatActivity {
private static final String TAG = "CameraXPreview";
private static final int REQUEST_CAMERA_PERMISSION = 1001;
// 预览控件
private PreviewView previewView;
// 相机执行器(处理相机操作)
private ExecutorService cameraExecutor;
// 相机提供者(管理相机生命周期)
private ProcessCameraProvider cameraProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_xactivity);
// 初始化控件和执行器
previewView = findViewById(R.id.previewView);
cameraExecutor = Executors.newSingleThreadExecutor();
// 检查相机权限
if (checkCameraPermission()) {
// 权限已授予,初始化相机
startCamera();
} else {
// 申请相机权限
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION
);
}
}
/**
* 检查相机权限
*/
private boolean checkCameraPermission() {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED;
}
/**
* 初始化并启动相机预览
*/
@OptIn(markerClass = ExperimentalCamera2Interop.class)
private void startCamera() {
// 获取相机提供者
ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
// 获取相机提供者实例
cameraProvider = cameraProviderFuture.get();
// preview设置
Preview.Builder previewBuilder = new Preview.Builder().setResolutionSelector(new ResolutionSelector.Builder().setResolutionStrategy(new ResolutionStrategy(new Size(640, 480),
ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER)).build());
new Camera2Interop.Extender<>(previewBuilder).setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(30, 30)
);
// 配置预览用例
Preview preview = previewBuilder.build();
// 选择相机(后置相机)
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build();
// 解绑所有已绑定的用例(防止重复绑定)
cameraProvider.unbindAll();
// 绑定预览用例到生命周期
Camera camera = cameraProvider.bindToLifecycle(
(LifecycleOwner) this,
cameraSelector,
preview
);
// 将预览输出设置到 PreviewView
preview.setSurfaceProvider(previewView.getSurfaceProvider());
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "初始化相机失败", e);
Toast.makeText(this, "相机初始化失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}, ContextCompat.getMainExecutor(this));
}
/**
* 权限申请结果回调
*/
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限授予成功,启动相机
startCamera();
} else {
// 权限被拒绝
Toast.makeText(this, "相机权限被拒绝,无法使用相机功能", Toast.LENGTH_SHORT).show();
finish(); // 可选:关闭页面
}
}
}
/**
* 页面销毁时释放资源
*/
@Override
protected void onDestroy() {
super.onDestroy();
// 关闭执行器,释放资源
cameraExecutor.shutdown();
// 解绑相机用例
if (cameraProvider != null) {
cameraProvider.unbindAll();
}
}
}