为什么我的android camera2应用程序这么慢

时间:2019-09-12 13:50:43

标签: java android-studio android-camera2

我正在开发一个相机应用程序,您可以在该应用程序中拍照并在AlertDialog中对其进行查看。在此对话框中,您可以拍照并保存或拍摄新照片。 完成后,我意识到我的代码非常慢。 当我触摸takePic-Button时,我等待5秒钟,直到显示AlertDialog。

这是模型类:

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class Model {

    private static final int statePreview = 0;
    private static final int waitLock = 1;
    private int mState;
    private Bitmap bitmap;
    private Context context;
    private File file;
    private Activity activity;
    private ImageView imageView;
    private AlertDialog.Builder adb;

    private static final SparseIntArray orientation = new SparseIntArray();
    private CameraDevice cameraDevice;
    private String cameraID;
    private Size dimension;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest captureRequest;
    private CaptureRequest.Builder captureRequestBuilder;
    private Handler mBackgroundHandler;
    private HandlerThread handlerThread;
    private TextureView textureView;
    public Boolean done;


    public Model(Context context, TextureView textureView,Activity activity) {
        this.activity = activity;
        this.context = context;
        this.textureView = textureView;
        done = false;
        adb = new AlertDialog.Builder(context);
    }

    /**
     *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 = new MeteringRectangle(touchRect, MeteringRectangle.METERING_WEIGHT_DONT_CARE);

                try {
                    cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
                    mState = statePreview;
               } catch (CameraAccessException e) {
                   e.printStackTrace();
                }catch (IllegalStateException e){
                    Toast.makeText(context,"Not focused yet",Toast.LENGTH_SHORT).show();
                }


        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();
        }

        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();
            }
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            cameraDevice.close();
        }

        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @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;

        }

        //captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
        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 {


        //lockFocus();


        done = false;
        //CameraStateHandler csh = new CameraStateHandler(getActivity(),this);
        if(cameraDevice==null){
            return;
        }



        CameraManager manager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
        Size[] jpegSize = null;
        jpegSize = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);

        int width = 640;
        int height = 480;

        if(jpegSize!=null && jpegSize.length>0){
            width = jpegSize[0].getWidth();
            height = jpegSize[0].getHeight();
        }

        final ImageReader reader = ImageReader.newInstance(width,height,ImageFormat.JPEG,1);
        List<Surface> outputSurface = new ArrayList<>(2);
        outputSurface.add(reader.getSurface());
        outputSurface.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);

        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
                //getWindowManager().getDefaultDisplay().getRotation();



        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,orientation.get(rotation));

        Long tsLong = System.currentTimeMillis()/1000;

        file = new File(Environment.getExternalStorageDirectory()+"/"+tsLong.toString()+".jpg");



//        System.out.println(file.getAbsolutePath());

        ImageReader.OnImageAvailableListener readerListenenr = new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader imageReader) {
                Image image = null;
                image = reader.acquireLatestImage();
                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);
                check();


                if (image != null) {
                    image.close();

                }

            }

        };


        reader.setOnImageAvailableListener(readerListenenr,mBackgroundHandler);

        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);
                        if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED) {
                            //unLockFocus();
                            //Toast.makeText(getApplicationContext(), "Focus Locked", Toast.LENGTH_LONG).show();
                        }
                        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();
                }


            }

            @Override
            public void onConfigureFailed(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
     */
    public void check(){

        AlertDialog.Builder adb = new AlertDialog.Builder(context);

        imageView = new ImageView(context);
        imageView.setImageBitmap(bitmap);

        adb.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                System.out.println("Ok Button gedrückt");
                try {
                    save(toBase64());
                    dialogInterface.cancel();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }).setView(imageView);
        adb.setNegativeButton("Nochmal", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                dialogInterface.cancel();

            }
        });
        if(done==false) {
            adb.create().show();
               done=true;

               }
    }

    /**
     * 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 {

        // Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

         // imageView.setImageBitmap(bitmap);

        byte[] bytes = Base64.decode(meta.getBytes(),Base64.DEFAULT);
        Toast.makeText(context,"Saved",Toast.LENGTH_LONG).show();
        OutputStream outputStream = null;
        outputStream = new FileOutputStream(file);
        outputStream.write(bytes);
        outputStream.close();
        //    addImagetoGallery(file.getAbsolutePath(), PictureActivity.this);



    }

    /**
     * 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)
    protected void stopBackgroundThread() throws InterruptedException {

        handlerThread.quitSafely();
        handlerThread.join();
        handlerThread = null;
        mBackgroundHandler = null;

    }

    public Bitmap getBitmap() {return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

    public AlertDialog.Builder getAdb() {
        return adb;
    }

    public void setAdb(AlertDialog.Builder adb) {


}

这是控制器

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class PictureActivity extends AppCompatActivity {



    private ImageReader imageReader;

    private File file;
    private Bitmap bitmap;
    private Model model;
    private ImageButton button;
    private TextureView textureView;

    /**
     * Initialisiert View-Komponenten und das Model
     * @param savedInstanceState
     */
    @SuppressLint({"ClickableViewAccessibility", "ResourceType"})
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_picture);
        textureView = (TextureView) findViewById(R.id.texture);
        button = (ImageButton) findViewById(R.id.takePic);
        textureView.setSurfaceTextureListener(textureListener);
        model = new Model(PictureActivity.this,textureView,this);
        button.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void onClick(View view) {
                try {
                    model.takePic();

                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }

            }

        });

        textureView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                return model.focusTouch(view, motionEvent);

            }
        });

    }

    /**
     * Stellt das 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();
                //finsh
            }
        }

    }

    /**
     * Stellt Kamera uf Texture dar
     */
    @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
     */
    @SuppressLint("NewApi")
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    protected void onPause(){

        try {
            model.stopBackgroundThread();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        super.onPause();

    }


}




        this.adb = adb;
    }

    public ImageView getImageView() {
        return imageView;
    }

    public void setImageView(ImageView imageView) {
        this.imageView = imageView;
    }

}

0 个答案:

没有答案
相关问题