2015-04-01 140 views
1

我试图使用Camera2 API来读取使用zbar和QR码。不幸的是,我发现了以下错误,当我尝试并完成活动后,我已经成功地扫描QR码:停止CaptureCallback要求

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并干净地将结果返回给我的主要活动?

回答

0

这可能是因为您将Camera2Basic代码的mBackgroundThread.join();更改为mBackgroundThread.join(1);

即使您调用mCaptureSession.close(),摄像机流水线中可能仍会有一些请求捕捉“在飞行中”,因此在关闭捕捉会话后它们仍会出现并调用onCaptureCompleted(...)

原代码允许这些挥之不去的调用关闭线程之前得到解决,但你只有1毫秒后关闭它,这是不足够的时间,以确保它们得到解决。你应该先让它完成业务。

5

你打电话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(); 
    } 

}; 

它看起来像当前的行为,因为documentation for CameraDevice#close()说,可能是一个错误打电话,除了最后onClosed(CameraDevice)电话,从设备或将出现活动会话,和任何剩余提交的捕获请求没有进一步的回调都将被丢弃,仿佛abortCaptures()一直叫,只是没有成功或失败回调将被调用。