1.想要了解介紹的參考官網:
https://developer.android.google.cn/training/camerax/architecture
2.實作預覽
效果如圖

2.1第一步:引入依賴
(1)添加Google Maven 代碼庫
buildscript {
repositories {
google()
jcenter()
}
}
(2)添加java1.8
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// For Kotlin projects
kotlinOptions {
jvmTarget = "1.8"
}
}
(3)添加camerax相關庫,最新的版本號可以去maven 庫官網查看
//CameraX
def camerax_version = "1.1.0-alpha06"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha24"
2.2第二步:添加權限
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
其中第一個是檢查設備攝像頭硬體的,.any代表前置或后置都可以
2.3第三步:6.0后動態權限
注:在詢問權限回呼中,如果用戶選擇
允許——grantResults == 0
始終允許——后續則不需要再詢問權限了
禁止——grantResults == -1
禁止不再詢問——其實你代碼里還是詢問了,只是他直接回傳了grantResults == -1
/**
* 檢查是否擁有權限
*/
private void checkPermission(){
if (Build.VERSION.SDK_INT >= 23) {//6.0以上才用動態權限
boolean cameraPermission = hasPermission(Manifest.permission.CAMERA);
if (cameraPermission) {
startCamera();
} else {
requestPermissions(new String[]{Manifest.permission.CAMERA},CAMERA_PERMISSION_REQUEST_CODE);
}
}
}
/**
*詢問權限回呼
*/
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
Log.d(TAG, "onRequestPermissionsResult: " + grantResults[0]);
if (grantResults[0] == 0) {
//已允許權限
startCamera();
}else if (grantResults[0] == -1) {
//被禁止
Toast.makeText(this,"獲取相機權限失敗,請重新進入或手動設定權
限!",Toast.LENGTH_SHORT).show();
finish();
}
}
}
2.4 第四步:使用PreviewView作為預覽控制元件
<androidx.camera.view.PreviewView
android:id="@+id/act_cameraTest_pv_cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
2.5 第五步:開始預覽
/**
* 開始預覽
*/
private void startCamera() {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(new Runnable() {
@SuppressLint("RestrictedApi")
@Override
public void run() {
try {
//將相機的生命周期和activity的生命周期系結,camerax 會自己釋放
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
Preview preview = new Preview.Builder().build();
//創建圖片的 capture
mImageCapture = new ImageCapture.Builder()
.setFlashMode(ImageCapture.FLASH_MODE_OFF)
.build();
//選擇前置攝像頭
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_FRONT).build();
// Unbind use cases before rebinding
cameraProvider.unbindAll();
// Bind use cases to camera
//引數中如果有mImageCapture才能拍照,否則會報下錯
//Not bound to a valid Camera [ImageCapture:androidx.camera.core.ImageCapture-bce6e930-b637-40ee-b9b9-
mCamera = cameraProvider.bindToLifecycle(CameraTestActivity.this, cameraSelector, preview,mImageCapture);
preview.setSurfaceProvider(pvCameraPreview.getSurfaceProvider());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, ContextCompat.getMainExecutor(this));
}
3.實作拍照(只獲取靜態圖片+拍照保存到本地)
官方提供了兩個拍照方法,下面是原始碼中的代碼
第一個是獲取相機預覽影像的靜態圖片

第二個是直接保存到檔案,形成一個.jpg照片的,比上面多一個引數
3.1只獲取靜態圖片
/**
* 獲取靜態圖片
*/
public void takeStaticPhoto(View view) {
if (mImageCapture != null) {
//開始拍照
mImageCapture.takePicture(ContextCompat.getMainExecutor(this), new
ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(ImageProxy image) {
super.onCaptureSuccess(image);
//ImageProxy 轉 Bitmap
mBitmap = BaseImageUtils.imageProxyToBitmap(image);
imgShowStaticPhoto.setBackground(new
BitmapDrawable(getApplicationContext().getResources(),mBitmap));
//使用完image關閉
image.close();
}
@Override
public void one rror(ImageCaptureException exception) {
super.onError(exception);
Log.d(TAG, "onError: ");
}
});
}
}
3.2 拍照保存到本地
/**
* 拍照并存到存盤空間
* @param view
*/
public void takeFilePhoto(View view) {
if (mImageCapture != null) {
File dir = new File(savePath);
if (!dir.exists()) {
dir.mkdirs();
}
//創建檔案
File file = new File(savePath,"CameraXPhoto.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(CameraTestActivity.this, "照片保存成功:保存位置-我的手機/Android/data/com.test.cameraxdemo/files/photo ", Toast.LENGTH_SHORT).show();
}
@Override
public void one rror(@NonNull ImageCaptureException exception) {
Toast.makeText(CameraTestActivity.this, "照片保存失敗", Toast.LENGTH_SHORT).show();
}
});
}
}
4.問題處理
4.1 Not bound to a valid Camera [ImageCapture:androidx.camera.core.ImageCapture-
問題現象:
呼叫拍照方法報錯
原因:
沒有系結ImageCapture
解決方法:
在startCamera()方法中有一段系結到Lifecycle的代碼
![]()

可以看到如果我把最后一個引數去掉代碼不會報錯也可以正常跑起來,因為這個方法原始碼是下圖這樣的,所以傳參的時候傳三個到多個都是可以的,如果報上面的錯,應該是這里的ImageCapture引數沒有傳,加上之后可以解決這個問題,

4.2 CameraX 連續拍照兩次后拍斬訓呼方法一直無回應
問題現象:
連續呼叫兩次mImageCapture.takePicture()后發現再呼叫就一直沒有回應,如果你退出會進入onError回呼,提示找不到camera,
這種情況下會發現控制臺有兩行提示語如下:
D/ImageCapture: Send image capture request [current, pending] = [0, 1]
W/ImageCapture: Too many acquire images. Close image to be able to process next.
D/ImageCapture: Send image capture request [current, pending] = [0, 1]
W/ImageCapture: Too many acquire images. Close image to be able to process next.
分析原因:
捕獲的image太多了,需要關閉才能向下執行,那么去看下 ImageCapture 原始碼搜索下image.close(),發現一共有四處:兩處是在catch的時候呼叫的,兩處是在判斷否的時候呼叫的,也就是說正常情況下拍照并成功回傳之后并沒有close,所以會造成這個問題,

解決辦法:
在mImageCapture.takePicture()的成功回呼函式中,等你使用完image之后手動把它關閉,這個問題就可以解決了,
mImageCapture.takePicture(ContextCompat.getMainExecutor(this), new ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(ImageProxy image) {
super.onCaptureSuccess(image);
//ImageProxy 轉 Bitmap
Bitmap bitmap = imageProxyToBitmap(image);
//使用完image關閉
image.close();
}
@Override
public void one rror(ImageCaptureException exception) {
super.onError(exception);
Log.d(TAG, "onError: ");
}
});
需要原始碼的可以點個贊,點個關注,然后私信我,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/297609.html
標籤:其他
上一篇:Android 記憶體泄露分析
