Android开发笔记(一百八十一)使用CameraX拍照
Posted aqi00
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android开发笔记(一百八十一)使用CameraX拍照相关的知识,希望对你有一定的参考价值。
常言道,眼睛是心灵的窗户,那么相机便是手机的窗户了,主打美颜相机功能的拍照手机大行其道,可见对于手机App来说,如何恰如其分地运用相机开发至关重要。
android的SDK一开始就自带了相机工具Camera,从Android5.0开始又推出了升级版的camera2,然而不管是初代的Camera还是二代的camera2,编码过程都比较繁琐,对于新手而言有点艰深。为此谷歌公司在Jetpack库中集成了增强的相机库CameraX,想让相机编码(包括拍照和录像)变得更加方便。CameraX基于camera2开发,它提供一致且易用的API接口,还解决了设备兼容性问题,从而减少了编码工作量。
不管是拍照还是录像,都要在AndroidManifest.xml中添加相机权限,还要添加存储卡访问权限,如下所示:
<!-- 相机 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 存储卡读写 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
由于CameraX来自Jetpack库,因此要修改模块的build.gradle,往dependencies节点添加以下几配置,表示导入指定版本的camerax库:
// camerax库各版本见 https://mvnrepository.com/artifact/androidx.camera/camera-core
implementation 'androidx.camera:camera-core:1.0.1'
// camerax库各版本见 https://mvnrepository.com/artifact/androidx.camera/camera-camera2
implementation 'androidx.camera:camera-camera2:1.0.1'
// camerax库各版本见 https://mvnrepository.com/artifact/androidx.camera/camera-lifecycle
implementation 'androidx.camera:camera-lifecycle:1.0.1'
// camerax库各版本见 https://mvnrepository.com/artifact/androidx.camera/camera-view
implementation 'androidx.camera:camera-view:1.0.0-alpha28'
使用CameraX拍照之前要先初始化相机,包括界面预览以及参数设定等等,具体的初始化步骤说明如下。
1、准备一个预览视图对象PreviewView,并添加至当前界面;
2、获取相机提供器对象ProcessCameraProvider;
3、构建预览对象Preview,指定预览的宽高比例;
4、构建摄像头选择器对象CameraSelector,指定使用前置摄像头还是后置摄像头;
5、构建图像捕捉器对象ImageCapture,分别设置捕捉模式、旋转角度、宽高比例、闪光模式等拍照参数;
6、调用相机提供器对象的bindToLifecycle方法,把相机选择器、预览视图、图像捕捉器绑定到相机提供器;
7、调用预览视图对象的setSurfaceProvider方法,设置预览视图的表面提供器;
把上述的初始化步骤串起来,写到一个自定义的相机视图控件中,形成了以下的CameraX初始化代码:
private Context mContext; // 声明一个上下文对象
private PreviewView mCameraPreview; // 声明一个预览视图对象
private CameraSelector mCameraSelector; // 声明一个摄像头选择器
private Preview mPreview; // 声明一个预览对象
private ProcessCameraProvider mCameraProvider; // 声明一个相机提供器
private ImageCapture mImageCapture; // 声明一个图像捕捉器
private VideoCapture mVideoCapture; // 声明一个视频捕捉器
private ExecutorService mExecutorService; // 声明一个线程池对象
private LifecycleOwner mOwner; // 声明一个生命周期拥有者
private int mCameraType = CameraSelector.LENS_FACING_BACK; // 摄像头类型
private int mAspectRatio = AspectRatio.RATIO_16_9; // 宽高比例
private int mFlashMode = ImageCapture.FLASH_MODE_AUTO; // 闪光灯模式
private String mMediaDir; // 媒体保存目录
public CameraXView(Context context, AttributeSet attrs)
super(context, attrs);
mContext = context;
mCameraPreview = new PreviewView(mContext); // 创建一个预览视图
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mCameraPreview.setLayoutParams(params);
addView(mCameraPreview); // 把预览视图添加到界面上
mExecutorService = Executors.newSingleThreadExecutor(); // 创建一个单线程线程池
mMediaDir = mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();
// 打开相机
public void openCamera(LifecycleOwner owner, int cameraMode, OnStopListener sl)
mOwner = owner;
mCameraMode = cameraMode;
mStopListener = sl;
mHandler.post(() -> initCamera()); // 初始化相机
// 初始化相机
private void initCamera()
ListenableFuture future = ProcessCameraProvider.getInstance(mContext);
future.addListener(() ->
try
mCameraProvider = (ProcessCameraProvider) future.get();
resetCamera(); // 重置相机
catch (Exception e)
e.printStackTrace();
, ContextCompat.getMainExecutor(mContext));
// 重置相机
private void resetCamera()
int rotation = mCameraPreview.getDisplay().getRotation();
// 构建一个摄像头选择器
mCameraSelector = new CameraSelector.Builder().requireLensFacing(mCameraType).build();
// 构建一个预览对象
mPreview = new Preview.Builder()
.setTargetAspectRatio(mAspectRatio) // 设置宽高比例
.build();
// 构建一个图像捕捉器
mImageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) // 设置捕捉模式
.setTargetRotation(rotation) // 设置旋转角度
.setTargetAspectRatio(mAspectRatio) // 设置宽高比例
.setFlashMode(mFlashMode) // 设置闪光模式
.build();
bindCamera(MODE_PHOTO); // 绑定摄像头
// 设置预览视图的表面提供器
mPreview.setSurfaceProvider(mCameraPreview.getSurfaceProvider());
// 绑定摄像头
private void bindCamera(int captureMode)
mCameraProvider.unbindAll(); // 重新绑定前要先解绑
try
if (captureMode == MODE_PHOTO) // 拍照
// 把相机选择器、预览视图、图像捕捉器绑定到相机提供器的生命周期
Camera camera = mCameraProvider.bindToLifecycle(
mOwner, mCameraSelector, mPreview, mImageCapture);
catch (Exception e)
e.printStackTrace();
// 关闭相机
public void closeCamera()
mCameraProvider.unbindAll(); // 解绑相机提供器
mExecutorService.shutdown(); // 关闭线程池
初始化相机之后,即可调用图像捕捉器的takePicture方法拍摄照片了,拍照代码示例如下:
private String mPhotoPath; // 照片保存路径
// 获取照片的保存路径
public String getPhotoPath()
return mPhotoPath;
// 开始拍照
public void takePicture()
mPhotoPath = String.format("%s/%s.jpg", mMediaDir, DateUtil.getNowDateTime());
ImageCapture.Metadata metadata = new ImageCapture.Metadata();
// 构建图像捕捉器的输出选项
ImageCapture.OutputFileOptions options = new ImageCapture.OutputFileOptions.Builder(new File(mPhotoPath))
.setMetadata(metadata).build();
// 执行拍照动作
mImageCapture.takePicture(options, mExecutorService, new ImageCapture.OnImageSavedCallback()
@Override
public void onImageSaved(ImageCapture.OutputFileResults outputFileResults)
mStopListener.onStop("已完成拍摄,照片保存路径为"+mPhotoPath);
@Override
public void onError(ImageCaptureException exception)
mStopListener.onStop("拍摄失败,错误信息为:"+exception.getMessage());
);
然后在App代码中集成新定义的增强相机控件,先在布局文件中添加CameraXView节点,如下所示。
<com.example.chapter14.widget.CameraXView
android:id="@+id/cxv_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
再给Java代码补充CameraXView对象的初始化以及拍照动作,其中关键代码示例如下:
private CameraXView cxv_preview; // 声明一个增强相机视图对象
private View v_black; // 声明一个视图对象
private ImageView iv_photo; // 声明一个图像视图对象
private final Handler mHandler = new Handler(Looper.myLooper()); // 声明一个处理器对象
// 初始化相机
private void initCamera()
// 打开增强相机,并指定停止拍照监听器
cxv_preview.openCamera(this, CameraXView.MODE_PHOTO, (result) ->
runOnUiThread(() ->
iv_photo.setEnabled(true);
Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
);
);
// 处理拍照动作
private void dealPhoto()
iv_photo.setEnabled(false);
v_black.setVisibility(View.VISIBLE);
cxv_preview.takePicture(); // 拍摄照片
mHandler.postDelayed(() -> v_black.setVisibility(View.GONE), 500);
运行测试App,点击拍照图标,观察到增强相机的拍照效果如下面两图所示,其中第一张图为准备拍照时的预览界面,第二张图为拍照结束后的观赏界面。
以上是关于Android开发笔记(一百八十一)使用CameraX拍照的主要内容,如果未能解决你的问题,请参考以下文章
Android开发笔记(一百八十八)工作管理器WorkManager