当前位置:网站首页>Pit encountered using camera x_ When onpause, the camera is not released, resulting in a black screen when it comes back
Pit encountered using camera x_ When onpause, the camera is not released, resulting in a black screen when it comes back
2022-04-23 19:14:00 【cjzcjl】
Preface :
Recently, in order to realize the work content of photography , Think it over and decide to use Camera X As a photo of this project API, The main reasons are :1、API There is no in use Camera V2 API The amount of code required is large , Although I have relevant working experience , But think of the amount of code , Compared with Camera X Example , I still don't want to use .2、 Better compatibility , And provide common API Basically meet the requirements , Image focusing 、 Flash, etc API Have it all. , More suitable for Demo Quickly build .
problem :
In my opinion Android developer The examples introduced in have their own demo After building , I am right. Camera X Have a certain understanding of the application of . But found OnPause Then come back , The preview is lost . So I thought of two possibilities :
1、PreviewView Problems caused by possible destruction .
2、 Related to the life cycle of the camera , I may not have used it well .
Start with the first possibility . Try to OnResume Call the following code when :
if (mPreview != null) {
// Add... To the preview window surface passageway
mPreview.setSurfaceProvider(mPreviewView.getSurfaceProvider());
}
exactly OnResume Then the preview screen can come back , But still have to wait 5 Second . So doubt is more likely and possible 2 of .
As before Camera V2 Experience , If the camera resource is not released, it will cause some exceptions , In general, other applications that need to call the camera will also have problems . So I opened my demo, Then open wechat to scan , I found that the preview after scanning is also black 5 Seconds before it comes out , More in line with the above intuition and experience . So in OnPause Call in unBindAll Release the camera ,OnResume Reinitialize and set the preview window , The problem was solved .
Detailed code :
Camera logic :
package com.example.cameraXDemo;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.View;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraInfoUnavailableException;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
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 androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import com.bumptech.glide.Glide;
import com.example.piccut.R;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CameraXDemoActivity_1 extends Activity implements LifecycleOwner {
private ProcessCameraProvider mCameraPRrovider = null;
private int mLensFacing = CameraSelector.LENS_FACING_BACK;
private PreviewView mPreviewView;
private LifecycleRegistry mLifecycleRegistry;
/** Camera **/
private ImageCapture mImageCapture;
private ExecutorService mTakePhotoExecutor;
private Button mBtnTakePhoto;
private ImageView mImagePhoto;
private Preview mPreview;
private Button mBtnFlashLight;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Special thread for photographing , Let it not jam the main thread :
mTakePhotoExecutor = Executors.newSingleThreadExecutor();
// Permission to apply for
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
}
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.markState(Lifecycle.State.CREATED);
setContentView(R.layout.camera_x_demo);
mBtnFlashLight = findViewById(R.id.btn_flash_light);
mPreviewView = (PreviewView) findViewById(R.id.pv);
mBtnTakePhoto = findViewById(R.id.btn_take_photo);
mImagePhoto = findViewById(R.id.iv_photo);
// Photo button
mBtnTakePhoto.setOnClickListener(v -> {
takePhoto(mImageCapture);
});
// The flash
mBtnFlashLight.setOnClickListener(v -> {
switch ((String) v.getTag()) {
case "auto":
mImageCapture.setFlashMode(ImageCapture.FLASH_MODE_ON);
((Button) v).setText(" The flash : Normally open ");
v.setTag("on");
break;
case "on":
mImageCapture.setFlashMode(ImageCapture.FLASH_MODE_OFF);
((Button) v).setText(" The flash : close ");
v.setTag("off");
break;
default:
mImageCapture.setFlashMode(ImageCapture.FLASH_MODE_AUTO);
((Button) v).setText(" The flash : Automatically ");
v.setTag("auto");
break;
}
});
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
bindCameraUseCases(mCameraPRrovider, null);
}
@Override
protected void onStart() {
super.onStart();
mLifecycleRegistry.markState(Lifecycle.State.STARTED);
}
@Override
protected void onResume() {
super.onResume();
ListenableFuture<ProcessCameraProvider> processCameraProvider = ProcessCameraProvider.getInstance(this);
// When you come back, you need to rebind :
processCameraProvider.addListener(() -> {
try {
mCameraPRrovider = processCameraProvider.get();
// Bind preview window, etc
bindCameraUseCases(mCameraPRrovider, null);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, getMainExecutor()); // Only in the main thread
mLifecycleRegistry.markState(Lifecycle.State.RESUMED);
}
@Override
protected void onPause() {
super.onPause();
// Release camera resources when you go out
mCameraPRrovider.unbindAll();
}
@Override
protected void onDestroy() {
super.onDestroy();
mLifecycleRegistry.markState(Lifecycle.State.DESTROYED);
mTakePhotoExecutor.shutdown();
}
/** Returns true if the device has an available back camera. False otherwise */
private boolean hasBackCamera() {
try {
return mCameraPRrovider.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA);
} catch (CameraInfoUnavailableException e) {
e.printStackTrace();
}
return false;
}
/** Returns true if the device has an available front camera. False otherwise */
private boolean hasFrontCamera() {
try {
return mCameraPRrovider.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA);
} catch (CameraInfoUnavailableException e) {
e.printStackTrace();
}
return false;
}
private void bindCameraUseCases(ProcessCameraProvider cameraProvider, Surface surface) {
int aspectRatio = AspectRatio.RATIO_4_3;
// Preview interface :
mPreview = new Preview.Builder()
.setTargetAspectRatio(aspectRatio)
.setTargetRotation(mPreviewView.getDisplay().getRotation())
.build();
// Add... To the preview window surface passageway
mPreview.setSurfaceProvider(mPreviewView.getSurfaceProvider());
// Photo capture :
mImageCapture = new ImageCapture.Builder()
.setTargetAspectRatio(aspectRatio)
// Low delay photography , The reaction speed will be faster
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.setTargetRotation(mPreviewView.getDisplay().getRotation())
.setFlashMode(ImageCapture.FLASH_MODE_AUTO) // Flash adjustment
.build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setTargetAspectRatio(aspectRatio)
.setTargetRotation(mPreviewView.getDisplay().getRotation())
.build();
// Binding relationships that may exist before unbinding
cameraProvider.unbindAll();
// If there is a rear camera, choose the rear , Otherwise, use the front :
if (hasBackCamera()) {
mLensFacing = CameraSelector.LENS_FACING_BACK;
} if (hasFrontCamera()) {
// mLensFacing = CameraSelector.LENS_FACING_FRONT;
} else {
throw new IllegalStateException(" Neither front nor rear Cameras ");
}
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(mLensFacing).build();
// Binding lifecycle 、 Preview window 、 Camera acquisition device, etc
cameraProvider.bindToLifecycle(this,
cameraSelector, mPreview, mImageCapture, imageAnalysis);
}
/** Actual photo logic **/
private void takePhoto(ImageCapture imageCapture) {
if (null == imageCapture) {
Log.e("cjztest", "imageCapture is null");
return;
}
String fileFormatPattern = "yyyy-MM-dd-HH-mm-ss-SSS";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(fileFormatPattern);
// Save it to APP Local folder :
// File cacheFileDir = getCacheDir(); //APP Inside cache Address
File cacheFileDir = getExternalCacheDir(); // Shared 、 Everyone can visit cache Address
if (cacheFileDir.exists() && cacheFileDir.isDirectory()) {
File newFile = new File(cacheFileDir.getAbsolutePath() + String.format("/%s.jpg", simpleDateFormat.format(System.currentTimeMillis())));
Log.i("cjztest", "newFile:" + newFile.getAbsolutePath());
try {
newFile.createNewFile();
if (!newFile.exists()) {
return;
}
ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions.Builder(newFile)
.setMetadata(new ImageCapture.Metadata())
.build();
// After the photo is taken, it is received from the callback
imageCapture.takePicture(outputOptions, mTakePhotoExecutor, new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
Uri savedUri = outputFileResults.getSavedUri() == null ?
Uri.fromFile(newFile) :
outputFileResults.getSavedUri();
// Get a picture of the button
runOnUiThread(() -> {
if (newFile.exists()) {
Glide.with(mImagePhoto)
.load(newFile)
// .apply(RequestOptions.circleCropTransform())
.into(mImagePhoto);
}
});
// We can only change the foreground Drawable using API level 23+ API
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Update the gallery thumbnail with latest picture taken
// setGalleryThumbnail(savedUri);
}
// Implicit broadcasts will be ignored for devices running API level >= 24
// so if you only target API level 24+ you can remove this statement
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
sendBroadcast(
new Intent(android.hardware.Camera.ACTION_NEW_PICTURE, savedUri)
);
}
// If the folder selected is an external media directory, this is
// unnecessary but otherwise other apps will not be able to access our
// images unless we scan them using [MediaScannerConnection]
String mimeType = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(".jpg");
MediaScannerConnection.scanFile(CameraXDemoActivity_1.this,
new String[] {savedUri.getPath()},
new String[] {mimeType},
new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
Log.i("cjztest", " New file scan complete , file size :" + newFile.length());
}
});
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
Log.e("cjztest", " Photo failed ");
}
});
} catch (IOException e) {
Log.e("cjztest", " Failed to create file ");
e.printStackTrace();
}
}
Log.i("cjztest", "cacheFileDir:" + cacheFileDir);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
Interface description :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:background="#FF000000">
<Button
android:id="@+id/btn_flash_light"
android:text=" The flash : Automatically "
android:tag="auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|top"/>
<androidx.camera.view.PreviewView
android:id="@+id/pv"
android:layout_width="match_parent"
android:layout_height="700dp"/>
<ImageView
android:id="@+id/iv_photo"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="bottom|left"
android:scaleType="fitXY"/>
<Button
android:id="@+id/btn_take_photo"
android:text=" Taking pictures "
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="bottom|center"
/>
</FrameLayout>
Gitee Address :
版权声明
本文为[cjzcjl]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204210600587496.html
边栏推荐
- Openharmony open source developer growth plan, looking for new open source forces that change the world!
- [记录]TypeError: this.getOptions is not a function
- [报告] Microsoft :Application of deep learning methods in speech enhancement
- Using 8266 as serial port debugging tool
- Codeforces Round #784 (Div. 4)
- The flyer realizes page Jump through routing routes
- Partage de la conception de l'alimentation électrique de commutation et illustration des compétences en conception de l'alimentation électrique
- ArcMap publishing slicing service
- SQL Server database in clause and exists clause conversion
- 深度学习环境搭建步骤—gpu
猜你喜欢
[记录]TypeError: this.getOptions is not a function
Raspberry pie 18b20 temperature
Use of fluent custom fonts and pictures
SQL常用的命令
C: generic reflection
Using Visual Studio code to develop Arduino
该买什么设备,Keysight 给你挑好了
Raspberry pie uses root operation, and the graphical interface uses its own file manager
The fifth bullet of MySQL learning -- detailed explanation of transaction and its operation characteristics
Introduction to micro build low code zero Foundation (lesson 3)
随机推荐
开关电源设计分享及电源设计技巧图解
Simplified path (force buckle 71)
剑指 Offer II 116. 省份数量-空间复杂度O(n),时间复杂度O(n)
Openlayers 5.0 discrete aggregation points
Openlayers 5.0 two centering methods
openlayers 5.0 两种居中方式
openlayers 5.0 热力图
The type initializer for ‘Gdip‘ threw an exception
Zlib realizes streaming decompression
White screen processing method of fulter startup page
Why is PostgreSQL about to surpass SQL Server?
坐标转换WGS-84 转 GCJ-02 和 GCJ-02转WGS-84
Openlayers 5.0 loading ArcGIS Server slice service
Modify the font size of hint in editext
机器学习目录
js上传文件时控制文件类型和大小
2022.04.23(LC_714_买卖股票的最佳时机含手续费)
redis优化系列(三)解决主从配置后的常见问题
WebView saves the last browsing location
Coordinate conversion WGS-84 to gcj-02 and gcj-02 to WGS-84