2015-04-01 18 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()一直叫,只是沒有成功或失敗回調將被調用。