У меня есть задача внедрить фото-функцию в приложение-опрос, потому что в нем есть опросы, в которых респондент должен что-то нарисовать. Все работает хорошо, за исключением случаев, когда он заполняет анкеты, которые оба требуют картинупервый работает без ошибок, а второй дает сбой и сразу переходит к onError () - Method. но когда я заполняю опрос без фото между ними работает
Вот PictureActivity
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class PictureActivity extends AppCompatActivity {
private Camera2Pic model;
private Button takePic;
private TextureView textureView;
private Fragebogen fragebogen;
private ErhebungsSet set;
/**
* Initialisiert View-Komponenten und das Model
* @param savedInstanceState
*/
@RequiresApi(api = Build.VERSION_CODES.M)
@SuppressLint({"ClickableViewAccessibility", "ResourceType", "WrongViewCast"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_picture);
textureView = findViewById(R.id.texture);
takePic = findViewById(R.id.takePic);
takePic.setText("\uD83D\uDCF7");
takePic.setTextSize(40);
textureView.setSurfaceTextureListener(textureListener);
set = Persister.getErhebungsSet();
model = new Camera2Pic(PictureActivity.this,textureView, set.getErhebungenListe().get(getIntent().getIntExtra("key",0)).getSurvey());
takePic.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onClick(View view) {
try {
model.first = true;
model.takePic();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
});
textureView.setOnTouchListener((view, motionEvent) -> model.focusTouch(view, motionEvent));
}
/**
* Stellt die Texture zur verfügung
*/
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
try {
model.openCamera();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
/**
* Überprüft on die Rechte für die Kamera gegeben sind
* @param requestCode
* @param permissions
* @param grantReesults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantReesults){
if(requestCode == 101){
if(grantReesults[0]== PackageManager.PERMISSION_DENIED){
Toast.makeText(getApplicationContext(),"Sorry, camera permission is neccesary", Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onResume() {
super.onResume();
model.startBackgroundThread();
if (textureView.isAvailable()){
try {
model.openCamera();
}catch (CameraAccessException e){
e.printStackTrace();
}
}else{
textureView.setSurfaceTextureListener(textureListener);
}
}
/**
* Stoppt die übertragung
*/
@Override
protected void onPause(){
super.onPause();
}
}
А вот модель
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class Camera2Pic {
private static final int statePreview = 0;
private static final int waitLock = 1;
private int mState;
private Bitmap bitmap;
private Context context;
private ImageView imageView;
private CameraDevice cameraDevice;
private String cameraID;
private Size dimension;
private CameraCaptureSession cameraCaptureSession;
private CaptureRequest.Builder captureRequestBuilder;
private Handler mBackgroundHandler;
private HandlerThread handlerThread;
private TextureView textureView;
public Boolean first;
private Fragebogen fragebogen;
private ImageReader reader;
private ImageReader.OnImageAvailableListener readerListenenr;
@RequiresApi(api = Build.VERSION_CODES.M)
public Camera2Pic(Context context, TextureView textureView, Fragebogen fragebogen) {
this.context = context;
this.textureView = textureView;
this.fragebogen = fragebogen;
readerListenenr = reader -> photo();
first = true;
}
/**
*Diese Methode lässt die Kamera den Bereich fokussieren auf den man Clickt
*und bleibt bei dem Fokus
*
* @param view
* @param motionEvent
* @return boolean
*
*
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public Boolean focusTouch(View view, MotionEvent motionEvent) {
int pointerId = motionEvent.getPointerId(0);
int pointerIndex = motionEvent.findPointerIndex(pointerId);
float x = motionEvent.getX(pointerIndex);
float y = motionEvent.getY(pointerIndex);
Rect touchRect = new Rect((int) (x - 100), (int) (y - 100), (int) (x + 100), (int) (y + 100));
if (cameraID == null) return false;
MeteringRectangle focusArea = null;
try {
focusArea = new MeteringRectangle(touchRect, MeteringRectangle.METERING_WEIGHT_DONT_CARE);
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
mState = statePreview;
} catch (CameraAccessException e) {
e.printStackTrace();
}catch (IllegalStateException e){
Toast.makeText(context,"Bitte einen Moment Geduld", Toast.LENGTH_SHORT).show();
}catch (IllegalArgumentException e){
DisplayMetrics metrics = new DisplayMetrics();
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(metrics);
touchRect = new Rect((int) (metrics.heightPixels/2 - 100), (int) (metrics.widthPixels/2 - 100), metrics.heightPixels/2 + 100, metrics.widthPixels/2 + 100);
focusArea = new MeteringRectangle(touchRect, MeteringRectangle.METERING_WEIGHT_DONT_CARE);
}
try {
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusArea});
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
cameraCaptureSession.capture(captureRequestBuilder.build(),null,mBackgroundHandler);
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
cameraCaptureSession.capture(captureRequestBuilder.build(),null,mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}catch (IllegalStateException e){
Toast.makeText(context,"Bitte einen Moment Geduld", Toast.LENGTH_LONG).show();
}
return false;
}
/**
* Ruft die openCamera() Funktion auf wenn die Bedingungen erfüllt sind
*/
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
try {
openCamera();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
cameraDevice = camera;
try {
createCamerPreview();
}catch (CameraAccessException e){
e.printStackTrace();
}
showMessage("Für den Fragebogen "+fragebogen.getName()+" muss ein Foto aufgenommen werden<p><b>Bitte Foto aufnehmen</b></p>");
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
cameraDevice.close();
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
cameraDevice.close();
cameraDevice = null;
}
};
/**
* Erstellt die klassische Kamera perspektive
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void createCamerPreview() throws CameraAccessException {
SurfaceTexture texture = textureView.getSurfaceTexture();
texture.setDefaultBufferSize(dimension.getWidth(),dimension.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(CameraCaptureSession session) {
if (cameraDevice == null) {
return;
}
cameraCaptureSession = session;
try {
updatePreview();
}catch (CameraAccessException e){
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Toast.makeText(context, "Configuration Changed", Toast.LENGTH_LONG).show();
}
},null);
}
/**
* erneuert die Kamera perspektive
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void updatePreview() throws CameraAccessException {
if(cameraDevice==null){
return;
} try {
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
}catch (IllegalStateException e){
e.printStackTrace();
}
}
/**
* Öffnet die Kamera
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void openCamera() throws CameraAccessException {
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
cameraID = manager.getCameraIdList()[0];
CameraCharacteristics cc = manager.getCameraCharacteristics(cameraID);
StreamConfigurationMap map = cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
dimension = map.getOutputSizes(SurfaceTexture.class)[0];
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(((Activity)context),new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},101);
return;
}
manager.openCamera(cameraID, stateCallback, null);
}
/**
* Nimmt ein Foto auf und ruft die Überprüfung auf
* @throws CameraAccessException
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public void takePic() throws CameraAccessException {
initReader();
List<Surface> outputSurface = new ArrayList<>(2);
outputSurface.add(reader.getSurface());
Surface surface = new Surface(textureView.getSurfaceTexture());
outputSurface.add(surface);
final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
captureBuilder.addTarget(surface);
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
photo();
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result){
switch (mState){
case statePreview:
break;
case waitLock:
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
break;
}
}
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
}
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
process(result);
try {
createCamerPreview();
}catch (CameraAccessException e){
e.printStackTrace();
}
}
@Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Toast.makeText(context, "Focus don't Locked", Toast.LENGTH_LONG).show();
}
};
cameraDevice.createCaptureSession(outputSurface, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
try {
cameraCaptureSession.setRepeatingRequest(captureBuilder.build(), captureListener, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (IllegalStateException e){
Toast.makeText(context,"Bitte einen Moment Geduld",Toast.LENGTH_LONG).show();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
}
},mBackgroundHandler);
}
/**
* Fragt den Benutzer ob er das geschossen Foto behalten will.
* Falls Ja wird das Bild gespeichert ansonsten kann er noch ein Bild machen
*/
@SuppressLint("NewApi")
@RequiresApi(api = Build.VERSION_CODES.M)
public void show(){
AlertDialog.Builder adb = new AlertDialog.Builder(context);
imageView = new ImageView(context);
imageView.setImageBitmap(bitmap);
imageView.setPadding(10,10,10,10);
adb.setPositiveButton("OK", (dialogInterface, i) -> {
dialogInterface.cancel();
try {
save(toBase64());
} catch (IOException e) {
e.printStackTrace();
}
((Activity)context).finish();
});
adb.setNegativeButton("Nochmal", (dialogInterface, i) -> dialogInterface.cancel());
adb.setView(imageView);
try {
adb.create().show();
}catch(WindowManager.BadTokenException e){
}
}
/**
* Speicher das Bild auf dem Gerät und wandelt es in eine String um.
* Mit dem String wird das Bild im JSON-String gespeichert
* @param meta
* @throws IOException
*/
public void save(String meta) throws IOException {
Toast.makeText(context,"Gespeichert",Toast.LENGTH_LONG).show();
if(meta.isEmpty()){
meta = "{}";
}
Persister.addPic(meta);
}
@RequiresApi(api = Build.VERSION_CODES.M)
public void photo(){
Image image = reader.acquireLatestImage();
if(image!=null) {
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
if(first) {
first = false;
show();
}
if (image != null) {
image.close();
}
}
reader.setOnImageAvailableListener(readerListenenr, mBackgroundHandler);
}
/**
* Konventiert ein Bild in einen String mit Hilfe von Base64
*
* @return String der das Bild representier
*
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public String toBase64(){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 40, byteArrayOutputStream);
byte[] bytes = byteArrayOutputStream.toByteArray();
return Base64.encodeToString(bytes, Base64.DEFAULT);
}
/**
* Startet den Kamerahintergrund-Thread
*/
public void startBackgroundThread(){
handlerThread = new HandlerThread("Camera Background");
handlerThread.start();
mBackgroundHandler = new Handler(handlerThread.getLooper());
}
/**
* Stoppt den Kamerahintergrund-Thread
*/
@SuppressLint("NewApi")
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void stopBackgroundThread() throws InterruptedException {
handlerThread.quitSafely();
handlerThread.join();
handlerThread = null;
mBackgroundHandler = null;
}
public void initReader(){
CameraManager manager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = null;
try {
characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
} catch (CameraAccessException e) {
e.printStackTrace();
}
Size[] jpegSize = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
int width = 0;
int height = 0;
if(jpegSize!=null && jpegSize.length>0){
width = jpegSize[0].getWidth()/2;
height = jpegSize[0].getHeight()/2;
}
reader = ImageReader.newInstance(width , height, ImageFormat.JPEG,2);
}
public void showMessage(String s){
AlertDialog.Builder adb = new AlertDialog.Builder(context);
TextView textView = new TextView(context);
String content = s;
textView.setText(Html.fromHtml(content));
textView.setTextSize(23);
adb.setPositiveButton("Ok", (dialog, which) -> {});
adb.setView(textView);
adb.create().show();
}
}
И эти функциигде я запускаю PictureActivity
private void displaySurveyItem() {
Button buttonNext = findViewById(R.id.button_erhebung_next);
showSkipText(false);
buttonNext.setOnClickListener(v -> nextPage(erhebung));
if ((erhebung.getSurvey().getPage(erhebung.getAktPageNr()).isItem())
&& (!erhebung.aktPageAnswered())) {
buttonNext.setEnabled(false);
delayWorker.schedule(() -> buttonNext.setEnabled(true), 1, TimeUnit.SECONDS);
}
if (fragebogen != null) {
if (erhebung.showTHX()) {
if(fragebogen.getHasPic()) {
PictureActivity activity = new PictureActivity();
startActivityForResult(new Intent(SurveyFillOutActivity.this, activity.getClass()), 0);
}else{
showFragebodenEnd();
}
} else {
FragebogenPage fragebogenPage = fragebogen.getPage(erhebung.getAktPageNr());
fillTextView(fragebogenPage.getTitel(), R.id.erhebung_title, R.id.erhebung_title_space, true);
fillTextView(fragebogenPage.getText1(), R.id.erhebung_text1, R.id.erhebung_text1_space, false);
fillTextView(fragebogenPage.getText2(), R.id.erhebung_text2, R.id.erhebung_text2_space, false);
fillTextView(fragebogenPage.getFutter(), R.id.erhebung_footer, R.id.erhebung_footer_space, true);
toggleQuestionsVisibility(View.VISIBLE);
buildAnswerPanel();
int backButtonVisibility = erhebung.aktPageIsFirst() ? View.INVISIBLE : View.VISIBLE;
findViewById(R.id.button_erhebung_back).setVisibility(backButtonVisibility);
}
}
}
А вот и сообщение об ошибке
W/Camera: An error occurred while connecting to camera: 0
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: ch.zh.ipw.quest, PID: 25694
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.hardware.camera2.CameraDevice.close()' on a null object reference
at ch.zh.ipw.quest.camera2scanner.Camera2Pic$2.onError(Camera2Pic.java:202)
at android.hardware.camera2.impl.CameraDeviceImpl$8.run(CameraDeviceImpl.java:301)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6939)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Я думаю, что эта ошибка возникает, потому что камера используется все, но как я могу предотвратить это. Пожалуйста, спросите, если у вас есть вопросы о коде или приложении и заранее благодарим вас