我试图在应用程序中添加摄像头设备,所以我使用了本教程的代码,因为我自己并不真正知道如何做:https://inducesmile.com/android/android-camera2-api-example-tutorial/
有时可以正常工作,但有时在打开相机的过程中出现问题,最后Logcat显示已达到打开相机的超时时间。
如何解决此问题以使其每次都能正常工作?
我还在本教程中为我的应用程序添加了一些代码,但是我认为问题不出在这里。
我已将OnPause中的第450行(closeCamera();
分解为注释,因为例如在更改手机的方向时需要使用它。
我添加了测试(cameraDevice!=null
)(第211和217行:OnError and OnDisconnect
),因为有时cameraDevice已经是null
。
我什至不知道问题何时产生。
package com.example.test;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
public class CameraTestActivity extends AppCompatActivity {
private static final String TAG = "CameraTestActivity";
private Button takePictureButton;
private TextureView textureView;
private ImageView imageView;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private String cameraId;
protected CameraDevice cameraDevice;
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest captureRequest;
protected CaptureRequest.Builder captureRequestBuilder;
private Size imageDimension;
private ImageReader imageReader;
private File file;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private boolean mFlashSupported;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
private static Place place_selected;
private String photo_name;
private static boolean isNewPlace;
private static int Nb_photos = 0;
public static Place getPlaceSelected(){
return place_selected;
}
public static boolean getIsNewPlace(){
return isNewPlace;
}
public static int getNbPhotos(){
return Nb_photos;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_test);
Intent intent = getIntent();
place_selected = new Place();
place_selected.setPlace_name(intent.getStringExtra("place_name"));
place_selected.setLatitude(intent.getFloatExtra("latitude",(float)0.0));
place_selected.setLongitude(intent.getFloatExtra("longitude",(float)0.0));
place_selected.setDescription(intent.getStringExtra("description"));
isNewPlace = intent.getStringExtra("NewPlace?").equals("yes");
Log.d(TAG, "onCreate: Intent captured: "+place_selected);
Log.d(TAG, "It's a new place = "+isNewPlace);
Button restart = (Button) findViewById(R.id.enable_disable);
restart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
closeCamera();
openCamera();
}
});
textureView = (TextureView) findViewById(R.id.texture);
assert textureView != null;
textureView.setSurfaceTextureListener(textureListener);
takePictureButton = (Button) findViewById(R.id.btn_takepicture);
assert takePictureButton != null;
takePictureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePicture();
}
});
imageView = (ImageView) findViewById(R.id.imageView);
final SeekBar seekbar = findViewById(R.id.my_seekBar);
if (!isNewPlace){
imageView.setImageDrawable(InfoMarkerActivity.bigImage.getDrawable());
imageView.setAlpha((float) 0.4);
seekbar.setMax(0);
seekbar.setMax(1000);
seekbar.setProgress(400);
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
int value = seekbar.getProgress();
int max = seekBar.getMax();
imageView.setAlpha((float) value/max);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
else {
imageView.setVisibility(View.INVISIBLE);
seekbar.setVisibility(View.INVISIBLE);
}
//Button Continue
Button btnContinue = (Button) findViewById(R.id.button_continue);
btnContinue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Nb_photos==0){
new AlertDialog.Builder(CameraTestActivity.this)
.setTitle("Error")
.setMessage("You need to take at least one picture")
.setNegativeButton("OK", null)
//.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
else{
Intent intent = new Intent(CameraTestActivity.this, EndActivity.class);
intent.putExtra("photo_name",photo_name);
startActivity(intent);
}
}
});
}
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
//open your camera here
openCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Transform you image captured size according to the surface width and height
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
//This is called when the camera is open
Log.e(TAG, "onOpened");
cameraDevice = camera;
createCameraPreview();
}
@Override
public void onDisconnected(CameraDevice camera) {
if (cameraDevice!=null){
cameraDevice.close();
}
}
@Override
public void onError(CameraDevice camera, int error) {
if (cameraDevice!=null){
cameraDevice.close();
}
cameraDevice = null;
}
};
final CameraCaptureSession.CaptureCallback captureCallbackListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(CameraTestActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
}
};
protected void startBackgroundThread() {
mBackgroundThread = new HandlerThread("Camera Background");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
protected void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected void takePicture() {
if(null == cameraDevice) {
Log.e(TAG, "cameraDevice is null");
return;
}
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
int width = 640;
int height = 480;
if (jpegSizes != null && 0 < jpegSizes.length) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
// Orientation
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
FileManager fm = new FileManager(this);
if (!fm.SurveysFolderExists()){
fm.CreateSurveysFolder();
}
if (!fm.PhotosFolderExists(place_selected.getPlace_name(),FileManager.SURVEYS_FOLDER)){
fm.CreatePhotosFolder(place_selected,FileManager.SURVEYS_FOLDER);
}
Calendar CurrentDateTime = Calendar.getInstance();
int year = CurrentDateTime.get(Calendar.YEAR);
int month = CurrentDateTime.get(Calendar.MONTH);
int day = CurrentDateTime.get(Calendar.DAY_OF_MONTH);
int hour = CurrentDateTime.get(Calendar.HOUR);
int min = CurrentDateTime.get(Calendar.MINUTE);
int sec = CurrentDateTime.get(Calendar.SECOND);
int msec = CurrentDateTime.get(Calendar.MILLISECOND);
photo_name = place_selected.getPlace_name() + "_"+day+"."+month+"."+year+"_"+hour+"."+min+"."+sec+"."+msec+".jpg";
String path = getFilesDir()+"/"+FileManager.SURVEYS_FOLDER+place_selected.getPlace_name()+"/"+photo_name;
final File file = new File(path);
Log.d(TAG,"takePicture: Photo saved: "+photo_name);
Log.d(TAG,"takePicture: Photo's path: "+path);
Nb_photos++;
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes);
} finally {
if (null != output) {
output.close();
}
}
}
};
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Toast.makeText(CameraTestActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
createCameraPreview();
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
protected void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
Surface surface = new Surface(texture);
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback(){
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
//The camera is already closed
if (null == cameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(CameraTestActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void openCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
Log.e(TAG, "is camera open");
try {
cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
// Add permission for camera and let user grant the permission
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(CameraTestActivity.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION);
return;
}
manager.openCamera(cameraId, stateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Log.e(TAG, "openCamera X");
}
protected void updatePreview() {
if(null == cameraDevice) {
Log.e(TAG, "updatePreview error, return");
}
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void closeCamera() {
if (null != cameraDevice) {
cameraDevice.close();
cameraDevice = null;
}
if (null != imageReader) {
imageReader.close();
imageReader = null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// close the app
Toast.makeText(CameraTestActivity.this, "Sorry!!!, you can't use this app without granting permission", Toast.LENGTH_LONG).show();
finish();
}
}
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
startBackgroundThread();
if (textureView.isAvailable()) {
openCamera();
} else {
textureView.setSurfaceTextureListener(textureListener);
}
}
@Override
protected void onPause() {
Log.e(TAG, "onPause");
closeCamera();
stopBackgroundThread();
super.onPause();
}
}
07-10 12:38:39.909 4175-4175/com.example.test E/CameraTestActivity: onResume
07-10 12:38:39.934 1635-1870/system_process V/WindowManager: Adding window Window{38a264ba u0 com.example.test/com.example.test.CameraTestActivity} at 6 of 12 (after Window{1c6250ac u0 com.example.test/com.example.test.InfoMarkerActivity})
07-10 12:38:40.068 4175-4201/com.example.test D/EGL_emulation: eglMakeCurrent: 0xadc34ac0: ver 2 0 (tinfo 0xadc39420)
07-10 12:38:40.091 4175-4201/com.example.test D/EGL_emulation: eglMakeCurrent: 0xadc34ac0: ver 2 0 (tinfo 0xadc39420)
07-10 12:38:40.127 4175-4201/com.example.test D/EGL_emulation: eglMakeCurrent: 0xadc34ac0: ver 2 0 (tinfo 0xadc39420)
07-10 12:38:40.130 4175-4175/com.example.test E/CameraTestActivity: is camera open
07-10 12:38:40.131 4175-4175/com.example.test I/CameraManagerGlobal: getCameraService: Reconnecting to camera service
07-10 12:38:40.131 4175-4201/com.example.test D/EGL_emulation: eglMakeCurrent: 0xadc34ac0: ver 2 0 (tinfo 0xadc39420)
07-10 12:38:40.140 1184-2130/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.140 1184-2130/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.141 1184-2130/? I/CameraService: getCameraCharacteristics: Switching to HAL1 shim implementation...
07-10 12:38:40.141 1184-2130/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.141 1184-2130/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.142 1184-2353/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.142 1184-2353/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.142 1184-2353/? I/CameraService: getCameraCharacteristics: Switching to HAL1 shim implementation...
07-10 12:38:40.142 1184-2353/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.142 1184-2353/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.144 1184-2352/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.144 1184-2352/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.147 1184-2130/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.147 1184-2130/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.157 1184-2353/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.158 1184-2353/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.158 1184-1594/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.158 1184-1594/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.164 1184-2130/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.164 1184-2130/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:40.165 4175-4175/com.example.test I/CameraManager: Using legacy camera HAL.
07-10 12:38:40.173 1184-2353/? V/EmulatedCamera_Camera: getCameraInfo
07-10 12:38:40.173 1184-2353/? V/EmulatedCamera_BaseCamera: getCameraInfo
07-10 12:38:45.169 4175-4175/com.example.test E/CameraDeviceUserShim: waitForOpen - Camera failed to open after timeout of 5000 ms
07-10 12:38:45.170 4175-4175/com.example.test E/CameraTestActivity: openCamera X
07-10 12:38:45.173 4175-4201/com.example.test D/EGL_emulation: eglMakeCurrent: 0xadc34ac0: ver 2 0 (tinfo 0xadc39420)
07-10 12:38:45.303 1635-1664/system_process I/ActivityManager: Displayed com.example.test/.CameraTestActivity: +5s421ms
07-10 12:38:45.304 4175-4175/com.example.test I/Choreographer: Skipped 310 frames! The application may be doing too much work on its main thread.