当前位置:网站首页>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
边栏推荐
- c#:泛型反射
- SQL常用的命令
- Download xshell 6 and xftp6 official websites
- SQL server requires to query the information of all employees with surname 'Wang'
- SSDB基础1
- OpenHarmony开源开发者成长计划,寻找改变世界的开源新生力!
- Simplified path (force buckle 71)
- Android Development: the client obtains the latest value in the database in real time and displays it on the interface
- Xlslib use
- Parsing headless jsonarray arrays
猜你喜欢
Keysight has chosen what equipment to buy for you
简化路径(力扣71)
Network protocol: SCTP flow control transmission protocol
ArcMap connecting ArcGIS Server
Oracle配置st_geometry
12 examples to consolidate promise Foundation
为何PostgreSQL即将超越SQL Server?
SQL常用的命令
2022.04.23 (the best time for lc_714_to buy and sell stocks, including handling charges)
Introduction to micro build low code zero Foundation (lesson 3)
随机推荐
Getting started with vcpkg
Using Visual Studio code to develop Arduino
Codeforces Round #784 (Div. 4)
Simple use of viewbinding
JS to get the local IP address
js获取本机ip地址
ArcGIS JS API dojoconfig configuration
Use of kotlin collaboration in the project
SSDB基础
Raspberry pie uses root operation, and the graphical interface uses its own file manager
Audio signal processing and coding - 2.5.3 the discrete cosine transform
mysql_linux版本的下载及安装详解
SSDB foundation 2
All table queries and comment description queries of SQL Server
[record] typeerror: this getOptions is not a function
SSDB Foundation
openlayers 5.0 加载arcgis server 切片服务
SSDB foundation 1
开关电源设计分享及电源设计技巧图解
c1000k TCP 连接上限测试