我正在尝试使用camera2 api使用zbar读取二维码。不幸的是,当我在成功扫描二维码后尝试完成活动时,出现以下错误:

Handler (android.os.Handler) {282a7034} sending message to a Handler on a dead thread
java.lang.IllegalStateException: Handler (android.os.Handler) {282a7034} sending message to a Handler on a dead thread
    at android.os.MessageQueue.enqueueMessage(MessageQueue.java:325)
    at android.os.Handler.enqueueMessage(Handler.java:631)
    at android.os.Handler.sendMessageAtTime(Handler.java:600)
    at android.os.Handler.sendMessageDelayed(Handler.java:570)
    at android.os.Handler.post(Handler.java:326)
    at android.hardware.camera2.dispatch.HandlerDispatcher.dispatch(HandlerDispatcher.java:61)
    at android.hardware.camera2.dispatch.MethodNameInvoker.invoke(MethodNameInvoker.java:88)
    at android.hardware.camera2.dispatch.DuckTypingDispatcher.dispatch(DuckTypingDispatcher.java:53)
    at android.hardware.camera2.dispatch.ArgumentReplacingDispatcher.dispatch(ArgumentReplacingDispatcher.java:74)
    at android.hardware.camera2.dispatch.BroadcastDispatcher.dispatch(BroadcastDispatcher.java:54)
    at android.hardware.camera2.dispatch.MethodNameInvoker.invoke(MethodNameInvoker.java:88)
    at android.hardware.camera2.impl.CallbackProxies$DeviceCaptureCallbackProxy.onCaptureCompleted(CallbackProxies.java:120)
    at android.hardware.camera2.impl.CameraDeviceImpl$CameraDeviceCallbacks$4.run(CameraDeviceImpl.java:1362)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.os.HandlerThread.run(HandlerThread.java:61)

下面是相关的代码片段:
private CameraCaptureSession.CaptureCallback mCaptureCallback
        = new CameraCaptureSession.CaptureCallback() {

    @Override
    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
                                   TotalCaptureResult result) {
        Bitmap barcodeBmp = mTextureView.getBitmap();
        if(barcodeBmp == null)
            return;
        int width = barcodeBmp.getWidth();
        int height = barcodeBmp.getHeight();

        Image mQRCode = new Image(width, height, "RGB4");
        final ImageScanner scanner = new ImageScanner();
        scanner.setConfig(0, Config.X_DENSITY, 3);
        scanner.setConfig(0, Config.Y_DENSITY, 3);
        scanner.setConfig(0, Config.ENABLE, 0); //Disable all the Symbols
        scanner.setConfig(Symbol.QRCODE, Config.ENABLE, 1); //Only QRCODE is enable

        int[] pixels = new int[(width * height)];
        barcodeBmp.getPixels(pixels, 0, width, 0, 0, width, height);
        mQRCode.setData(pixels);
        int scanResult = scanner.scanImage(mQRCode.convert("Y800"));

        Log.i(TAG, "Result = " + scanResult);

        if(scanResult != 0) {

            Log.i(TAG, "Getting results");
            SymbolSet syms = scanner.getResults();
            Log.i(TAG, "Have results");
            for(Symbol sym : syms) {
                Intent returnIntent = new Intent();
                returnIntent.putExtra("Result", sym.getData());
                setResult(RESULT_OK, returnIntent);
                closeCamera();
                stopBackgroundThread();
                mActivity.finish();
            }

        }
    }

};

private void closeCamera() {
    try {
        mCameraOpenCloseLock.acquire();
        if (null != mCaptureSession) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (null != mCameraDevice) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
        if (null != mImageReader) {
            mImageReader.close();
            mImageReader = null;
        }
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
    } finally {
        mCameraOpenCloseLock.release();
    }
}

private void stopBackgroundThread() {
    if(mBackgroundThread != null) {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join(1);
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

如何停止调用captureCallback并将结果干净地返回到主活动?

最佳答案

您正在呼叫CameraDevice#close(),但这不会立即关闭摄像机。你应该让线程一直运行直到设备完成。
您的代码可能基于Google’s Camera2 sample app。要整洁地完成所有工作,请停止CameraDevice.StateCallback中的线程,而不是重写#onClosed(CameraDevice)方法:

private CameraDevice.StateCallback mStateCallback
        = new CameraDevice.StateCallback() {

    // ...

    @Override
    public void onClosed(CameraDevice camera) {
        // Keep the thread alive until the camera is closed.
        stopBackgroundThread();
    }

};

当前的行为可能是一个bug,因为documentation for CameraDevice#close()表示:
紧接着在这个调用之后,除了最后的onClosed(CameraDevice)调用之外,不会再发生来自设备或活动会话的回调,并且任何剩余的提交的捕获请求都将被丢弃,就像abortCaptures()已经被调用一样,除了不会调用成功或失败的回调。

关于android - 停止CaptureCallback请求,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29402828/

10-09 17:22