成都关键词seo推广平台,手机端关键词排名优化软件,网站开发前准备,学院网站源码相机功能
安卓中的相机调用功能也经历了很多的方案升级#xff0c;目前可选的官方方案是CameraX、Camera2、Camera#xff08;废弃#xff09;#xff0c;还有一些第三方免费或者是付费的相机库。对于大多数开发者#xff0c;建议使用 CameraX。
CameraX
CameraX 是 An…相机功能
安卓中的相机调用功能也经历了很多的方案升级目前可选的官方方案是CameraX、Camera2、Camera废弃还有一些第三方免费或者是付费的相机库。对于大多数开发者建议使用 CameraX。
CameraX
CameraX 是 Android Jetpack 库的一部分旨在简化相机应用的开发。它构建在 Camera2 API 之上为开发者提供了更简洁的接口相比于Camera和Camera2有更好的设备兼容性。
简单易用相比 Camera2CameraX 简化了相机操作提供了更直观的 API可以更快实现常见的相机功能。
向后兼容性CameraX 支持 Android 5.0 (API 21) 及以上版本解决了 Camera2 在一些设备上的兼容性问题。
生命周期感知CameraX 会自动处理生命周期问题例如当用户切换到后台时停止相机回到前台时重新启动。
内置扩展CameraX 提供了诸如 HDR、夜间模式、美颜等功能支持基于不同设备硬件的特性自动调整。不过这个需要看手机型号很多手机并不支持。
CameraX拍照
项目依赖配置
在 build.gradle 文件中添加 CameraX 相关依赖
def camerax_version 1.2.0-alpha04 implementation androidx.camera:camera-core:$camerax_version//核心库 implementation androidx.camera:camera-camera2:$camerax_version//基于 Camera2 的实现模块 implementation androidx.camera:camera-lifecycle:$camerax_version//自动管理相机的生命周期 implementation androidx.camera:camera-view:1.0.0-alpha31//显示相机预览的 UI 组件 implementation androidx.camera:camera-extensions:1.0.0-alpha31//额外的高级相机功能如 HDR 和美颜
权限配置AndroidManifest.xml
运行相机需要对相机权限做出声明
uses-permission android:nameandroid.permission.CAMERA / uses-feature android:nameandroid.hardware.camera android:requiredfalse /
android:requiredfalse这意味着相机功能并不是应用的必需条件。如果设备没有相机应用仍然可以安装和运行。如果是true而设备本身没有相机那应用就无法正常运行。
布局文件activity_main.xml
!-- CameraX 预览控件 -- androidx.camera.view.PreviewView android:idid/previewView android:layout_width0dp android:layout_height0dp app:layout_constraintTop_toTopOfparent app:layout_constraintBottom_toTopOfid/captureButton app:layout_constraintStart_toStartOfparent app:layout_constraintEnd_toEndOfparent / !-- 拍照按钮 -- Button android:idid/captureButton android:layout_widthwrap_content android:layout_heightwrap_content android:text拍照 app:layout_constraintTop_toBottomOfid/previewView app:layout_constraintBottom_toBottomOfparent app:layout_constraintStart_toStartOfparent app:layout_constraintEnd_toEndOfparent /
Activity中
package com.example.cameraxdemo; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.util.Log; import android.widget.Button; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.camera.core.Camera; import androidx.camera.core.CameraSelector; import androidx.camera.core.ImageCapture; import androidx.camera.core.ImageCaptureException; import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.view.PreviewView; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.google.common.util.concurrent.ListenableFuture; import java.io.File; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MainActivity extends AppCompatActivity { private static final int REQUEST_CODE_PERMISSIONS 10; private static final String[] REQUIRED_PERMISSIONS new String[]{Manifest.permission.CAMERA}; private PreviewView previewView; private ImageCapture imageCapture; private ExecutorService cameraExecutor; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); previewView findViewById(R.id.previewView); Button captureButton findViewById(R.id.captureButton); // 请求相机权限如果有权限直接启动相机 if (allPermissionsGranted()) { startCamera(); } else { ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS); } // 点击拍照按钮时执行拍照 captureButton.setOnClickListener(view - takePhoto()); cameraExecutor Executors.newSingleThreadExecutor(); } // 初始化相机 private void startCamera() { ListenableFutureProcessCameraProvider cameraProviderFuture ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() - { try { // 获取 CameraProvider ProcessCameraProvider cameraProvider cameraProviderFuture.get(); // 创建预览 Preview preview new Preview.Builder().build(); // 创建 ImageCapture用于拍照 imageCapture new ImageCapture.Builder().build(); // 选择后置摄像头 CameraSelector cameraSelector CameraSelector.DEFAULT_BACK_CAMERA; // 将预览与 PreviewView 绑定 preview.setSurfaceProvider(previewView.getSurfaceProvider()); // 绑定预览和 ImageCapture 到相机生命周期 cameraProvider.unbindAll(); Camera camera cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture); } catch (ExecutionException | InterruptedException e) { Log.e(CameraXDemo, Error starting camera: , e); } }, ContextCompat.getMainExecutor(this)); } // 拍照逻辑 private void takePhoto() { if (imageCapture null) { return; } // 创建保存文件 File photoFile new File(getExternalFilesDir(null), System.currentTimeMillis() .jpg); // 设置拍照输出选项 ImageCapture.OutputFileOptions outputFileOptions new ImageCapture.OutputFileOptions.Builder(photoFile).build(); // 执行拍照 imageCapture.takePicture(outputFileOptions, cameraExecutor, new ImageCapture.OnImageSavedCallback() { Override public void onImageSaved(NonNull ImageCapture.OutputFileResults outputFileResults) { runOnUiThread(() - Toast.makeText(MainActivity.this, Photo saved: photoFile.getAbsolutePath(), Toast.LENGTH_SHORT).show()); } Override public void onError(NonNull ImageCaptureException exception) { Log.e(CameraXDemo, Photo capture failed: exception.getMessage(), exception); } }); } // 检查是否已经获得所有权限 private boolean allPermissionsGranted() { for (String permission : REQUIRED_PERMISSIONS) { if (ContextCompat.checkSelfPermission(this, permission) ! PackageManager.PERMISSION_GRANTED) { return false; } } return true; } // 权限请求结果回调 Override public void onRequestPermissionsResult(int requestCode, NonNull String[] permissions, NonNull int[] grantResults) { if (requestCode REQUEST_CODE_PERMISSIONS) { if (allPermissionsGranted()) { startCamera(); } else { Toast.makeText(this, Permissions not granted by the user., Toast.LENGTH_SHORT).show(); finish(); } } } Override protected void onDestroy() { super.onDestroy(); cameraExecutor.shutdown(); } }
使用MediaStore遵循分区存储
// 创建 ContentValues ContentValues contentValues new ContentValues(); contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, System.currentTimeMillis() .jpg); contentValues.put(MediaStore.Images.Media.MIME_TYPE, image/jpeg); contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES /CameraXDemo); // 设置输出选项 ImageCapture.OutputFileOptions outputFileOptions new ImageCapture.OutputFileOptions.Builder(getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).build(); // 拍照 imageCapture.takePicture(outputFileOptions, cameraExecutor, new ImageCapture.OnImageSavedCallback() { Override public void onImageSaved(NonNull ImageCapture.OutputFileResults outputFileResults) { Uri savedUri outputFileResults.getSavedUri(); if (savedUri ! null) { runOnUiThread(() - Toast.makeText(CameraActivity.this, Photo saved to MediaStore: savedUri, Toast.LENGTH_SHORT).show()); } else { Log.e(TAG, Image not saved properly.); } } Override public void onError(NonNull ImageCaptureException exception) { Log.e(TAG, Photo capture failed: exception.getMessage(), exception); } });
切换前后置摄像头
主要思路是重新绑定摄像头在重新绑定之前切换前后摄像头参数即可
public class MainActivity extends AppCompatActivity { private PreviewView previewView; private ImageCapture imageCapture; private ProcessCameraProvider cameraProvider; private CameraSelector cameraSelector; private boolean isFrontCamera false; // 默认后置摄像头 Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); previewView findViewById(R.id.previewView); // 启动相机 startCamera(); // 切换摄像头按钮点击事件 findViewById(R.id.switchCameraButton).setOnClickListener(v - { isFrontCamera !isFrontCamera; switchCamera(); }); } private void startCamera() { // 获取 CameraProvider ListenableFutureProcessCameraProvider cameraProviderFuture ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() - { try { cameraProvider cameraProviderFuture.get(); // 默认使用后置摄像头 cameraSelector CameraSelector.DEFAULT_BACK_CAMERA; bindCameraUseCases(); } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); } }, ContextCompat.getMainExecutor(this)); } private void bindCameraUseCases() { // 创建预览 Preview preview new Preview.Builder().build(); // 将 Preview 连接到 PreviewView preview.setSurfaceProvider(previewView.getSurfaceProvider()); // 拍照设置 imageCapture new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .build(); // 解绑之前的所有用例 cameraProvider.unbindAll(); // 绑定预览和拍照功能到相机 cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview, imageCapture); } private void switchCamera() { // 切换前后置摄像头 if (isFrontCamera) { cameraSelector CameraSelector.DEFAULT_FRONT_CAMERA; } else { cameraSelector CameraSelector.DEFAULT_BACK_CAMERA; } // 重新绑定摄像头 bindCameraUseCases(); } // 拍照方法 private void takePicture() { if (imageCapture ! null) { ContentValues contentValues new ContentValues(); contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, my_image_ System.currentTimeMillis() .jpg); contentValues.put(MediaStore.Images.Media.MIME_TYPE, image/jpeg); ImageCapture.OutputFileOptions outputFileOptions new ImageCapture.OutputFileOptions.Builder(getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).build(); imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() { Override public void onImageSaved(ImageCapture.OutputFileResults outputFileResults) { Uri savedUri outputFileResults.getSavedUri(); Log.d(CameraXApp, Image saved: savedUri); } Override public void onError(ImageCaptureException exception) { Log.e(CameraXApp, Error saving image: exception.getMessage()); } }); } } }
CameraX视频拍摄
项目依赖配置
除了CameraX的基础依赖库还需要新增下面的库
implementation androidx.camera:camera-video:$camerax_version // 视频录制相关库
权限配置
录制视频除了需要获取相机权限还需要额外添加录音权限
uses-permission android:nameandroid.permission.RECORD_AUDIO /
Activity中
public class VideoRecordActivity extends AppCompatActivity { private static final String TAG VideoRecordActivity; private PreviewView previewView;// 预览摄像头捕获内容的视图 private ExecutorService cameraExecutor;// 用于处理相机操作的后台线程 private boolean isRecording; // 记录否正在录制的状态 private VideoCaptureRecorder videoCapture; //捕获视频的核心组件 // private Recording recording; private ProcessCameraProvider cameraProvider;// 相机的生命周期管理组件 private CameraSelector cameraSelector;// 前置或后置摄像头 private Recording recording;//当前正在进行的录制实例 private ImageView ivRecord; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_video_record); previewView findViewById(R.id.preview); //拍照 ivRecord findViewById(R.id.tv_take); ivRecord.setOnClickListener(view - { // 如果当前正在录制点击按钮停止录制否则就是开始录制 if (isRecording) { stopRecording(); } else { startRecording(); } }); // 创建单线程后台线程池 cameraExecutor Executors.newSingleThreadExecutor(); startCamera(); requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 11); } // 启动相机预览 private void startCamera() { ListenableFutureProcessCameraProvider cameraProviderFuture ProcessCameraProvider.getInstance(this); // 异步获取摄像头的命周期管理器实例 cameraProviderFuture.addListener(() - { try { // 获取摄像头生命周期管理器实例 cameraProvider cameraProviderFuture.get(); // 创建预览实例 Preview preview new Preview.Builder().build(); // 将预览内容绑定到 PreviewView 上 preview.setSurfaceProvider(previewView.getSurfaceProvider()); // 视频录制用例 Recorder recorder new Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.HD)) // 设置录制质量为 HD .build(); // 创建 VideoCapture 用例这个一个获取视频的核心组件 videoCapture VideoCapture.withOutput(recorder); // 默认使用后置摄像头 cameraSelector CameraSelector.DEFAULT_BACK_CAMERA; //解绑所有之前的摄像头用例 cameraProvider.unbindAll(); // 将预览和视频录制绑定到生命周期 cameraProvider.bindToLifecycle(VideoRecordActivity.this, cameraSelector, preview, videoCapture); } catch (ExecutionException | InterruptedException e) { Log.e(TAG, Error starting camera, e); } }, ContextCompat.getMainExecutor(this));// 在主线程执行 } private void startRecording() { if (isRecording) { Toast.makeText(this, Recording is already in progress, Toast.LENGTH_SHORT).show(); return; } // 创建保存视频的 ContentValues指定文件名和文件类型 ContentValues contentValues new ContentValues(); contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, video_ System.currentTimeMillis()); contentValues.put(MediaStore.MediaColumns.MIME_TYPE, video/mp4); // 使用 MediaStoreOutputOptions 指定输出位置 MediaStoreOutputOptions options new MediaStoreOutputOptions.Builder(getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI) .setContentValues(contentValues).build(); // 准备录制前检查录音权限 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) ! PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, 请先获取录音权限, Toast.LENGTH_SHORT).show(); return; } // 准备录制视频并启用音频录制 PendingRecording pendingRecording videoCapture.getOutput() .prepareRecording(VideoRecordActivity.this, options) .withAudioEnabled(); // 如果需要音频录制调用该方法 // 启动录制并且设定录制回调 //回调中的videoRecordEvent会有下面几种状态 //VideoRecordEvent.Start录制开始。 //VideoRecordEvent.Pause录制暂停。 //VideoRecordEvent.Resume录制恢复。 //VideoRecordEvent.Finalize录制完成停止或失败。 //VideoRecordEvent.Status录制状态更新持续获取统计信息。 recording pendingRecording.start(ContextCompat.getMainExecutor(this), videoRecordEvent - { Log.d(TAG, Recording videoRecordEvent videoRecordEvent); Log.d(TAG, Recording videoRecordEvent getRecordingStats videoRecordEvent.getRecordingStats()); if (videoRecordEvent instanceof VideoRecordEvent.Start) { Log.d(TAG, Recording started); isRecording true; refreshUI(videoRecordEvent); } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) { Log.d(TAG, Recording finalized); Toast.makeText(this, 已保存, Toast.LENGTH_SHORT).show(); isRecording false; refreshUI(videoRecordEvent); } }); } private void stopRecording() { if (recording ! null isRecording) { recording.stop(); // 停止录制 recording null; } } //更新UI private void refreshUI(VideoRecordEvent videoRecordEvent) { if (videoRecordEvent instanceof VideoRecordEvent.Start) { //开始录制把相关的ui换成录制的效果 ivRecord.setImageResource(R.mipmap.icon_stop_record); } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) { //结束录制 ivRecord.setImageResource(R.mipmap.icon_record); }else{ //这里可以自行扩展其他的状态 } } Override protected void onDestroy() { super.onDestroy(); cameraExecutor.shutdown(); } }