2

我正在修改适用于 Android 的 Google Camera2 API 示例,可在此处找到:https ://github.com/googlesamples/android-Camera2Basic

我正在将捕获的图像上传到 Cloudinary,显然需要在后台线程中这样做,这样 UI 就不会被阻塞。

然而,我遇到的问题是,当上传图像时,UI 实际上被阻止了,尽管据我所知,它不应该是,因为处理程序是使用 Looper 从后台线程创建的,如下所示:

private void startBackgroundThread() {
    mBackgroundThread = new HandlerThread("CameraBackground");
    mBackgroundThread.start();
    mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}

ImageSaver 类,负责将捕获的图像写入磁盘,如下所示:

private static class ImageSaver implements Runnable {
    /**
     * The JPEG image
     */
    private final Image mImage;
    /**
     * The file we save the image into.
     */
    private final File mFile;

    public ImageSaver(Image image, File file ) {
        mImage = image;
        mFile = file;
    }

    @Override
    public void run() {
        ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);
        FileOutputStream output = null;
        try {
            output = new FileOutputStream(mFile);
            output.write(bytes);
            InputStream is = new ByteArrayInputStream(bytes);
            Map uploadResult = CloudinaryManager.getInstance().uploader().upload(is, ObjectUtils.asMap(
                    "api_key", CloudinaryManager.CLOUDINARY_API_KEY,
                    "api_secret", CloudinaryManager.CLOUDINARY_SECRET_KEY
            ));
            System.out.println("result");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            mImage.close();
            if (null != output) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

ImageSaver 在此处添加到 Handler 中:

 private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
        = new ImageReader.OnImageAvailableListener() {

    @Override
    public void onImageAvailable(ImageReader reader) {
        mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
    }
};

我将不胜感激任何帮助或建议,为我指明正确的方向。

4

2 回答 2

1

我相信这是因为相机正在使用背景中的锁......因为你从 ImageReader 获取图像,我怀疑它会持有锁,直到你完成资源......所以作为一个建议,我会填充onImageAvailable里面的字节数组,关闭你获取的图片,然后把字节数组发送给AsyncTask执行保存

于 2017-02-11T19:29:27.553 回答
0

我遇到了同样的问题,经过一些调查和测试,发现它实际上并没有冻结 UI,它冻结了在许多相机应用程序上给人相同印象的相机预览。

如果您查看 unLockFocus() 方法,您可以看到它将相机设置回正常的预览状态。

查看调用它的点,您可以看到它直到图像被保存:

           .
           .
           .
           CameraCaptureSession.CaptureCallback CaptureCallback
                    = new CameraCaptureSession.CaptureCallback() {

                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                               @NonNull CaptureRequest request,
                                               @NonNull TotalCaptureResult result) {
                    showToast("Saved: " + mFile);
                    Log.d(TAG, mFile.toString());
                    unlockFocus();
                }
            };

通过在相机保存序列中的较早点调用它,可以启用预览,并且 UI 会更早地再次解锁。

我已经进行了实验,如果在获取图像之后和保存之前调用它似乎可以工作 - 我还在 captureCallback 中删除了对 unLockFocus 的原始调用。请注意,我没有对比赛条件等进行任何适当的测试,因此我强烈建议您自己试验以确保您的案例有效(如果我做更多验证,我会更新它):

    /**
     * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
     * still image is ready to be saved.
     */
    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
            = new ImageReader.OnImageAvailableListener() {

        @Override
        public void onImageAvailable(ImageReader reader) {
            Log.d(TAG,"onImageAvailable");

            //Get the image
            Image cameraImage = reader.acquireNextImage();

            //Now unlock the focus so the UI does not look locked - note that this is a much earlier point than in the
            //original Camera2Basic example from google as the original place was causing the preview to lock during any
            //image manipulation and saving.
            unlockFocus();

            //Save the image file in the background - note check you have permissions granted by user or this will cause an exception.
            mBackgroundHandler.post(new ImageSaver(getActivity().getApplicationContext(), cameraImage, outputPicFile);

        }

    };
于 2017-03-13T20:21:52.373 回答