Какой лучший способ вызвать StartPreview() после захвата изображения?

Как только вызов выполняется в Camera.takePicture(), мой просмотр перестанет обновляться, как описано в документах. Какой лучший способ обнаружить, что процесс захвата изображения закончен, и вызвать startPreview(), чтобы он снова начал обновление?

Вызов не может быть помещен ни в один из обратных вызовов, переданных takePicture, в соответствии с документами, поскольку все они должны были возвратиться до того, как я его вызову.

Мое последнее предположение заключается в создании обработчика и отправке отложенного Runnable к нему из обратного вызова JPEG (или в зависимости от того, какой из последних заданных обратных вызовов возвращается).

Ответ 1

Вы должны запустить mCamera.takePicture из AsyncTask (или потока), однако AsyncTaks - это более простой вариант.

Очень простая реализация (которая, конечно же, может быть изменена):

Метод, вызываемый для съемки

/**
 * Execute the AsyncTask that will handle the preview of the captured photo.
 */
public void takePicture() {
    TakePictureTask takePictureTask = new TakePictureTask();
    takePictureTask.execute();
}

Подкласс AsyncTask

/**
 * A pretty basic example of an AsyncTask that takes the photo and
 * then sleeps for a defined period of time before finishing. Upon
 * finishing, it will restart the preview - Camera.startPreview().
 */

private class TakePictureTask extends AsyncTask<Void, Void, Void> {

    @Override
    protected void onPostExecute(Void result) {
        // This returns the preview back to the live camera feed
        mCamera.startPreview();
    }

    @Override
    protected Void doInBackground(Void... params) {
        mCamera.takePicture(null, null, mPictureCallback);

        // Sleep for however long, you could store this in a variable and
        // have it updated by a menu item which the user selects.
        try {
            Thread.sleep(3000); // 3 second preview
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }

}

Поле PictureCallback

private PictureCallback mPictureCallback = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        File file = null;

        // Check whether the media is mounted with read/write permission.
        if (Environment.MEDIA_MOUNTED.equals(
                Environment.getExternalStorageState())) {
            file = getOutputMediaFile();
        }

        if (file == null) {
            Log.d(TAG, "Error creating media file, check storage persmissions!");
            return;
        }

        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(data);
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};

Ответ 2

Так как PictureCallback запускается в отдельном потоке (он не будет блокировать пользовательский интерфейс), вам не нужно использовать AsyncTask для вызова захвата.

Существует два способа сделать то, что вы хотите сделать, проще всего:

mCamera.startPreview(); //preview has to be started before you can take a picture
mCamera.takePicture(null, null, mPictureCallback); //take a picture

private PictureCallback mPictureCallback = new PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        camera.startPreview(); //once your camera has successfully finished
                               //its capture it safe to restart the preview
        ... //anything else you want to do to process that image
    }
}

Второй будет использовать анонимную функцию, например:

mCamera.takePicture(null, null, new PictureCallback(){
    ...
});

Оба имеют свои возможности, в зависимости от ваших потребностей.