兼容Androidx所有Android版本摄像头预览与获取图片
1、添加引用
ependencies {
def camerax_version = "1.0.0-beta06"
// CameraX 核心库
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX 生命周期
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX view 集合,比如 cameraview,preview等
implementation "androidx.camera:camera-view:1.0.0-alpha10"
2、AndroidManifest.xml 添加权限
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.any" />
3、布局文件
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_trans"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换摄像头"
app:layout_constraintStart_toStartOf="@+id/viewFinder"
app:layout_constraintTop_toTopOf="@+id/viewFinder" />
<Button
android:id="@+id/btn_takePhoto"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginBottom="50dp"
android:elevation="2dp"
android:scaleType="fitCenter"
android:text="拍照"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.camera.view.PreviewView
android:id="@+id/viewFinder"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
4、activity中全部源码
package cn.wildfire.chat.app;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.File;
import java.io.IOException;
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.content.ContextCompat;
import cn.wildfirechat.chat.R;
public class RLSB2Activity extends AppCompatActivity implements View.OnClickListener {
SurfaceView surfaceview;
SurfaceHolder holder;
Camera mCamera;
PreviewView mViewFinder;
private ImageCapture mImageCapture;
private int mFacing = CameraSelector.LENS_FACING_BACK;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rlsb2);
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
mViewFinder=findViewById(R.id.viewFinder);
initView();
findViewById(R.id.btn_trans).setOnClickListener(this);
findViewById(R.id.btn_takePhoto).setOnClickListener(this);
}
private static final String TAG = "MainActivity";
protected void initView() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {Manifest.permission.CAMERA}, 1);
}
}
startCamera();
}
private void startCamera() {
//返回当前可以绑定生命周期的 ProcessCameraProvider
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(new Runnable() {
@SuppressLint("RestrictedApi")
@Override
public void run() {
try {
//将相机的生命周期和activity的生命周期绑定,camerax 会自己释放,不用担心了
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
//预览的 capture,它里面支持角度换算
Preview preview = new Preview.Builder().build();
//创建图片的 capture
mImageCapture = new ImageCapture.Builder()
.setFlashMode(ImageCapture.FLASH_MODE_AUTO)
.build();
//选择后置摄像头
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(mFacing).build();
//预览之前先解绑
cameraProvider.unbindAll();
//将数据绑定到相机的生命周期中
Camera camera = cameraProvider.bindToLifecycle(RLSB2Activity.this, cameraSelector, preview, mImageCapture);
//将previewview 的 surface 给相机预览
preview.setSurfaceProvider(mViewFinder.createSurfaceProvider(camera.getCameraInfo()));
} catch (Exception e) {
e.printStackTrace();
}
}
}, ContextCompat.getMainExecutor(this));
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_trans:
switchCamera();
break;
case R.id.btn_takePhoto:
takePhoto();
break;
}
}
public void switchCamera() {
/**
* 白屏的问题是 PreviewView 移除所有View,且没数据到 Surface,
* 所以只留背景色,可以对次做处理
*/
mFacing = mFacing == CameraSelector.LENS_FACING_FRONT?
CameraSelector.LENS_FACING_BACK:CameraSelector.LENS_FACING_FRONT;
startCamera();
}
public void takePhoto() {
//获取根目录
String path=""+ Environment.getExternalStorageDirectory();
if (mImageCapture != null) {
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
//创建文件
File file = new File(path,"testx.jpg");
if (file.exists()) {
file.delete();
}
//创建包文件的数据,比如创建文件
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
//开始拍照
mImageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
// Uri savedUri = outputFileResults.getSavedUri();
Toast.makeText(RLSB2Activity.this, "保存成功: ", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
Toast.makeText(RLSB2Activity.this, "保存失败", Toast.LENGTH_SHORT).show();
}
});
}
}
}