OnPictureTaken()时间/保存问题

时间:2014-01-27 15:41:44

标签: android camera

我正在创建一个自定义相机应用程序(它将包含在一个更大的主应用程序中),该应用程序使用相机 - 视图和图片库预览加载视图 - 因此用户可以拍照或选择一个先前存在的。如果用户确实拍了照片,我只想显示一个确认对话框,如果确认,则将控制权交还给主要活动。我无法存储照片:需要快速将其用作附件,并且一旦通过主要活动发送,请将其丢弃。

当我拍照并且调用onPictureTaken()时出现问题:它要么不起作用,要么花费很长时间来保存照片。此外,我似乎无法弄清楚如何在现场提取照片,而不将其保存到目录;我计划立即删除目录,但必须有一个更清洁的方式(基本上,我只是想访问该原始字节数组,而不必保存它)。

我希望它是模块化的(在我即将开展的项目中会大量使用相机),我认为这会增加整体延迟。

我关注了Google的开发者Android Guide on Cameras,我的大部分代码都来自那里提供的示例。

我也在使用ActionBarSherlock。

我目前有三个班级:

CameraManager

public class CameraManager {

private static Camera CAMERA;

    /** Check if this device has a camera */
    public static boolean  doesDeviceHaveCamera(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            return true;
        } 
        else {
            return false;
        }
    }

    public static Camera getCameraInstance(){
        CAMERA = null;
        try {
            CAMERA = Camera.open();
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
        }
        return CAMERA;
    }
}

CameraPreview

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "CameraPreview";
    private SurfaceHolder surfaceHolder;
    private Camera camera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        this.camera = camera;
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // deprecated setting, but required on Android versions prior to 3.0
    }

    public void surfaceCreated(SurfaceHolder holder) {
        try {
            camera.setPreviewDisplay(holder);
            camera.startPreview();
        } 
        catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (surfaceHolder.getSurface() == null){
            return;
        }
        try {
            camera.stopPreview();
        } 
        catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here
        camera.setDisplayOrientation(90);
        // start preview with new settings
        try {
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
        } 
        catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

CameraActivity

public class CameraActivity extends SherlockActivity {

    private static final String TAG = "CameraActivity";
    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;
    private Camera camera;
    private CameraPreview preview;
    private PictureCallback picture = new PictureCallback() { 
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
            if (pictureFile == null){
                Log.d(TAG, "Error creating media file, check storage permissions: media file is null.");
                return;
            }
            try {
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            } 
            catch (FileNotFoundException e) {
                Log.d(TAG, "File not found: " + e.getMessage());
            } 
            catch (IOException e) {
                Log.d(TAG, "Error accessing file: " + e.getMessage());
            }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        setContentView(R.layout.camera_view);

        /**Get a camera instance**/
        if(CameraManager.doesDeviceHaveCamera(this)){
            camera = CameraManager.getCameraInstance();
        }
        else{
            return;
        }

        /**Create a SurfaceView preview (holds the camera feed) and set it to the corresponding XML layout**/
        preview = new CameraPreview(this, camera);
        FrameLayout previewContainer = (FrameLayout) findViewById(R.id.camera_preview);
        previewContainer.addView(preview);

        /**Set up a capture button, which takes the picture**/
        Button captureButton = (Button) findViewById(R.id.button_capture);
        captureButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                camera.takePicture(null, null, picture);
            }
        });
    }

    /** Create a File for saving an image or video */
    private static File getOutputMediaFile(int type){
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this.

        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyDirectory");
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyDirectory", "failed to create directory");
                return null;
            }
        }
        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE){
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                    "IMG_"+ timeStamp + ".jpg");
        } 
        else if(type == MEDIA_TYPE_VIDEO) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                    "VID_"+ timeStamp + ".mp4");
        } 
        else {
            return null;
        }
        return mediaFile;
    }
}

我正在主活动屏幕上的按钮上调用 CameraActivity

2 个答案:

答案 0 :(得分:2)

  

当我拍照并且onPictureTaken()被调用时出现问题:它要么不起作用,要么花费很长时间来保存照片

这是一个大文件,您正在主应用程序线程上写一个文件。

  基本上,我只想访问原始字节数组,而不必保存它

然后不要保存它。 小心使用静态数据成员将字节数组放在主活动可以使用的地方(当你完成它时,null输出静态引用,所以内存可以是垃圾收集)。

答案 1 :(得分:1)

如果您open the camera on a secondary event thread,将在该主题上调用您的pictureTaken()回调,而不会阻碍UI响应。请注意,您仍然可以从camera.takePicture()调用onClick(),即从UI线程调用。{/ p>

这仍然不是一个银弹:你可能想要将文件卸载到另一个工作线程,让相机拍下一张照片。正如上面所写的Mark,如果您只需要实时访问原始字节数组,请不要写入文件。