关于在 Android Studio 中实现 CameraX 预览的问题
Issues about implementing a preview for CameraX in Android Studio
我尝试为 CameraX 实现预览,但我的代码中有两个错误,我无法解决:
CameraSelector 不在 androidx.camera.core.CameraSelector 中 public。无法从外部包访问。
无法解析符号'previewView'
编辑:我解决了问题,但仍然无法预览。我之前没有提到,但我在 Android 清单中插入了权限。
这是我的代码:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PreviewView previewView = (PreviewView) findViewById(R.id.previewView);
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
preview.setSurfaceProvider(previewView.createSurfaceProvider());
cameraProvider.unbindAll();
cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(this));
}
}
Build.gradle(模块:app),在依赖项部分
def camerax_version = "1.0.0-beta07"
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:1.0.0-alpha14"
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
我知道自 Camera-View 版本 1.0.0-alpha16 以来 createSurfaceProvider() 已重命名为 getSurfaceProvider(),但是当我尝试调用最后一个方法时 Android Studio 没有解决它。
这是日志(错误)
2020-11-22 20:59:01.944 10830-10830/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2020-11-22 20:59:01.945 10830-10830/? E/Zygote: accessInfo : 1
2020-11-22 20:59:03.214 10830-10885/com.android.unipi.camerademo E/Camera_APM :: [APM]APM's Thread is started
2020-11-22 20:59:03.216 10830-10885/com.android.unipi.camerademo E/Camera_APM :: [APM] This app is forground app
2020-11-22 20:59:03.223 10830-10872/com.android.unipi.camerademo E/SequentialExecutor: Exception while executing runnable androidx.camera.camera2.internal.-$$Lambda$Camera2CameraImpl$_NFNV64YCFFY0Tn3VRiyE3Ss3S0@5d0b8a
java.lang.SecurityException: validateClientPermissionsLocked:1145: Caller "com.android.unipi.camerademo" (PID 10188, UID 10830) cannot open camera "0" without camera permission
at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:855)
at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:499)
at android.hardware.camera2.CameraManager.openCameraForUid(CameraManager.java:670)
at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:638)
at androidx.camera.camera2.internal.compat.CameraManagerCompatApi28Impl.openCamera(CameraManagerCompatApi28Impl.java:70)
at androidx.camera.camera2.internal.compat.CameraManagerCompat.openCamera(CameraManagerCompat.java:185)
at androidx.camera.camera2.internal.Camera2CameraImpl.openCameraDevice(Camera2CameraImpl.java:871)
at androidx.camera.camera2.internal.Camera2CameraImpl.openInternal(Camera2CameraImpl.java:236)
at androidx.camera.camera2.internal.Camera2CameraImpl.tryAttachUseCases(Camera2CameraImpl.java:691)
at androidx.camera.camera2.internal.Camera2CameraImpl.lambda$attachUseCases$Camera2CameraImpl(Camera2CameraImpl.java:649)
at androidx.camera.camera2.internal.-$$Lambda$Camera2CameraImpl$_NFNV64YCFFY0Tn3VRiyE3Ss3S0.run(Unknown Source:4)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.workOnQueue(SequentialExecutor.java:230)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.run(SequentialExecutor.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: android.os.ServiceSpecificException: validateClientPermissionsLocked:1145: Caller "com.android.unipi.camerademo" (PID 10188, UID 10830) cannot open camera "0" without camera permission (code 1)
at android.os.Parcel.createException(Parcel.java:1980)
at android.os.Parcel.readException(Parcel.java:1934)
at android.os.Parcel.readException(Parcel.java:1884)
at android.hardware.ICameraService$Stub$Proxy.connectDevice(ICameraService.java:359)
at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:463)
at android.hardware.camera2.CameraManager.openCameraForUid(CameraManager.java:670)
at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:638)
at androidx.camera.camera2.internal.compat.CameraManagerCompatApi28Impl.openCamera(CameraManagerCompatApi28Impl.java:70)
at androidx.camera.camera2.internal.compat.CameraManagerCompat.openCamera(CameraManagerCompat.java:185)
at androidx.camera.camera2.internal.Camera2CameraImpl.openCameraDevice(Camera2CameraImpl.java:871)
at androidx.camera.camera2.internal.Camera2CameraImpl.openInternal(Camera2CameraImpl.java:236)
at androidx.camera.camera2.internal.Camera2CameraImpl.tryAttachUseCases(Camera2CameraImpl.java:691)
at androidx.camera.camera2.internal.Camera2CameraImpl.lambda$attachUseCases$Camera2CameraImpl(Camera2CameraImpl.java:649)
at androidx.camera.camera2.internal.-$$Lambda$Camera2CameraImpl$_NFNV64YCFFY0Tn3VRiyE3Ss3S0.run(Unknown Source:4)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.workOnQueue(SequentialExecutor.java:230)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.run(SequentialExecutor.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
根据日志,我没有插入相机权限,但我这样做了。也许我错过了其他权限?
在Husayn 和Shark 的建议下我解决了这个问题。任何具有 Android 6 或更高版本 (API 23+) 的设备都需要运行时权限。
检查用户是否授予了相机权限。否则,请请求该许可。在调用 CameraX 代码之前,在 onCreate()
方法中插入以下代码:
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST);
}
其中 CAMERA_REQUEST
是一个常量。这是一个例子:
private static final int CAMERA_REQUEST = 100;
然后,会出现一个对话框,用户可以在对话框中允许或拒绝权限。我们可以通过以下方法查看结果:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "CameraX permission granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "CameraX permission denied", Toast.LENGTH_SHORT).show();
}
}
}
我尝试为 CameraX 实现预览,但我的代码中有两个错误,我无法解决:
CameraSelector 不在 androidx.camera.core.CameraSelector 中 public。无法从外部包访问。
无法解析符号'previewView'
编辑:我解决了问题,但仍然无法预览。我之前没有提到,但我在 Android 清单中插入了权限。
这是我的代码:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PreviewView previewView = (PreviewView) findViewById(R.id.previewView);
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
preview.setSurfaceProvider(previewView.createSurfaceProvider());
cameraProvider.unbindAll();
cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, ContextCompat.getMainExecutor(this));
}
}
Build.gradle(模块:app),在依赖项部分
def camerax_version = "1.0.0-beta07"
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:1.0.0-alpha14"
activity_main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
我知道自 Camera-View 版本 1.0.0-alpha16 以来 createSurfaceProvider() 已重命名为 getSurfaceProvider(),但是当我尝试调用最后一个方法时 Android Studio 没有解决它。
这是日志(错误)
2020-11-22 20:59:01.944 10830-10830/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2020-11-22 20:59:01.945 10830-10830/? E/Zygote: accessInfo : 1
2020-11-22 20:59:03.214 10830-10885/com.android.unipi.camerademo E/Camera_APM :: [APM]APM's Thread is started
2020-11-22 20:59:03.216 10830-10885/com.android.unipi.camerademo E/Camera_APM :: [APM] This app is forground app
2020-11-22 20:59:03.223 10830-10872/com.android.unipi.camerademo E/SequentialExecutor: Exception while executing runnable androidx.camera.camera2.internal.-$$Lambda$Camera2CameraImpl$_NFNV64YCFFY0Tn3VRiyE3Ss3S0@5d0b8a
java.lang.SecurityException: validateClientPermissionsLocked:1145: Caller "com.android.unipi.camerademo" (PID 10188, UID 10830) cannot open camera "0" without camera permission
at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:855)
at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:499)
at android.hardware.camera2.CameraManager.openCameraForUid(CameraManager.java:670)
at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:638)
at androidx.camera.camera2.internal.compat.CameraManagerCompatApi28Impl.openCamera(CameraManagerCompatApi28Impl.java:70)
at androidx.camera.camera2.internal.compat.CameraManagerCompat.openCamera(CameraManagerCompat.java:185)
at androidx.camera.camera2.internal.Camera2CameraImpl.openCameraDevice(Camera2CameraImpl.java:871)
at androidx.camera.camera2.internal.Camera2CameraImpl.openInternal(Camera2CameraImpl.java:236)
at androidx.camera.camera2.internal.Camera2CameraImpl.tryAttachUseCases(Camera2CameraImpl.java:691)
at androidx.camera.camera2.internal.Camera2CameraImpl.lambda$attachUseCases$Camera2CameraImpl(Camera2CameraImpl.java:649)
at androidx.camera.camera2.internal.-$$Lambda$Camera2CameraImpl$_NFNV64YCFFY0Tn3VRiyE3Ss3S0.run(Unknown Source:4)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.workOnQueue(SequentialExecutor.java:230)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.run(SequentialExecutor.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: android.os.ServiceSpecificException: validateClientPermissionsLocked:1145: Caller "com.android.unipi.camerademo" (PID 10188, UID 10830) cannot open camera "0" without camera permission (code 1)
at android.os.Parcel.createException(Parcel.java:1980)
at android.os.Parcel.readException(Parcel.java:1934)
at android.os.Parcel.readException(Parcel.java:1884)
at android.hardware.ICameraService$Stub$Proxy.connectDevice(ICameraService.java:359)
at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:463)
at android.hardware.camera2.CameraManager.openCameraForUid(CameraManager.java:670)
at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:638)
at androidx.camera.camera2.internal.compat.CameraManagerCompatApi28Impl.openCamera(CameraManagerCompatApi28Impl.java:70)
at androidx.camera.camera2.internal.compat.CameraManagerCompat.openCamera(CameraManagerCompat.java:185)
at androidx.camera.camera2.internal.Camera2CameraImpl.openCameraDevice(Camera2CameraImpl.java:871)
at androidx.camera.camera2.internal.Camera2CameraImpl.openInternal(Camera2CameraImpl.java:236)
at androidx.camera.camera2.internal.Camera2CameraImpl.tryAttachUseCases(Camera2CameraImpl.java:691)
at androidx.camera.camera2.internal.Camera2CameraImpl.lambda$attachUseCases$Camera2CameraImpl(Camera2CameraImpl.java:649)
at androidx.camera.camera2.internal.-$$Lambda$Camera2CameraImpl$_NFNV64YCFFY0Tn3VRiyE3Ss3S0.run(Unknown Source:4)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.workOnQueue(SequentialExecutor.java:230)
at androidx.camera.core.impl.utils.executor.SequentialExecutor$QueueWorker.run(SequentialExecutor.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
根据日志,我没有插入相机权限,但我这样做了。也许我错过了其他权限?
在Husayn 和Shark 的建议下我解决了这个问题。任何具有 Android 6 或更高版本 (API 23+) 的设备都需要运行时权限。
检查用户是否授予了相机权限。否则,请请求该许可。在调用 CameraX 代码之前,在 onCreate()
方法中插入以下代码:
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST);
}
其中 CAMERA_REQUEST
是一个常量。这是一个例子:
private static final int CAMERA_REQUEST = 100;
然后,会出现一个对话框,用户可以在对话框中允许或拒绝权限。我们可以通过以下方法查看结果:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "CameraX permission granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "CameraX permission denied", Toast.LENGTH_SHORT).show();
}
}
}