Zxing扫码流程梳理

最近在优化扫码功能,对Zxing提供的demo做了一个梳理,下面时序图看不清楚的可以下载下来看,本来想精简下的,发现精简后流程就不清晰了。


扫码大致流程:应用扫码activity启动------->启动摄像头——>获得bitmap照片----->对得到的照片做编码解析----->获得对应的信息做处理。


<pre name="code" class="html">启动流程如下:
CaptureActivity启动整个流程就5个步骤,都在CaptureActivity的onresume中,具体内容如下:

1.生成cameraManager对象。
 cameraManager = new CameraManager(getApplication())。
  进去看构造方法做了什么事
  public CameraManager(Context context) {
    this.context = context;
    this.configManager = new CameraConfigurationManager(context);
    previewCallback = new PreviewCallback(configManager);
  }
  生成2个实例CameraConfigurationManager PreviewCallback,分别用做camera参数配置和camera预览数据回调
  所谓camera预览数据回调就是Camera抓取到数据后回调此对象回传数据给调用方
  
  
2.实例化扫码UI控件
  viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
  viewfinderView.setCameraManager(cameraManager);
  获得CameraManager实例,设置CameraManager实例到viewfinderView,为UI展示提供尺寸。
  viewfinderView是一个自定义view,在ondraw中根据CameraManager中CameraConfigurationManager的配置参数来绘制UI
  为后面UI绘制做准备。
  
  
3.打开摄像头
  cameraManager.openDriver(surfaceHolder);
  进去看具体做了什么
 public synchronized void openDriver(SurfaceHolder holder) throws IOException {
	.....
    if (theCamera == null) {
      theCamera = OpenCameraInterface.open(requestedCameraId);//打开指定id的摄像头
      if (theCamera == null) {
        throw new IOException("Camera.open() failed to return object from driver");
      }
    }
	....
	
	configManager.initFromCameraParameters(theCamera);
    try {
      configManager.setDesiredCameraParameters(theCamera, false);//配置摄像头的各种参数
    } catch (RuntimeException re) {
     ....
    }
    cameraObject.setPreviewDisplay(holder);//设置Camera的显示holder容器

  }


4.设置对应的回调。

   获得一个handler实例

   if (handler == null) {
     handler = new CaptureActivityHandler(this, decodeFormats, decodeHints, characterSet, cameraManager);
   }
   进去看具体做了什么
   CaptureActivityHandler(CaptureActivity activity,
                         Collection<BarcodeFormat> decodeFormats,
                         Map<DecodeHintType,?> baseHints,
                         String characterSet,
                         CameraManager cameraManager) {
    this.activity = activity;
    decodeThread = new DecodeThread(activity, decodeFormats, baseHints, characterSet,
        new ViewfinderResultPointCallback(activity.getViewfinderView()));
    decodeThread.start();
	
    this.cameraManager = cameraManager;
    cameraManager.startPreview();
    restartPreviewAndDecode();
  }
  4.1首先new DecodeThread()一个实例
	decodeThread.start();启动线程
	  看这个线程做了什么
	  public void run() {
		Looper.prepare();
		handler = new DecodeHandler(activity, hints);
		handlerInitLatch.countDown();
		Looper.loop();
	  }
	 只是简单的生成DecodeHandler实例
   
  4.2然后cameraManager.startPreview();
	  看下这个方法做了什么
	  public synchronized void startPreview() {
		OpenCamera theCamera = camera;
		if (theCamera != null && !previewing) {
		  theCamera.getCamera().startPreview();
		  previewing = true;
		  autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());
		}
	  }
	  theCamera.getCamera().startPreview();//开始预览
	  
	  autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());//自动对焦管理类
	  在这个管理类中最终会调
	  camera.autoFocus(this);//设置Camera的对焦
	  
  4.3最后restartPreviewAndDecode();
	  private void restartPreviewAndDecode() {
		if (state == State.SUCCESS) {
		  state = State.PREVIEW;
		  cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
		  activity.drawViewfinder();
		}
     }
     将4.1中的handler传到cameraManager,然后再传到previewCallback
	 具体看requestPreviewFrame(Handler handler, int message)
	  public synchronized void requestPreviewFrame(Handler handler, int message) {
		OpenCamera theCamera = camera;
		if (theCamera != null && previewing) {
		  previewCallback.setHandler(handler, message);
		  theCamera.getCamera().setOneShotPreviewCallback(previewCallback);
		}
	  }
	previewCallback.setHandler(handler, message);通过setHandler方法设置到PreviewCallback中
	而previewCallback又通过setOneShotPreviewCallback(previewCallback)方法设置到Camera。
5.绘制扫码界面,开始处理扫码数据。
drawViewfinder绘制扫码界面,这个方法由CaptureActivityHandler实例调起,此时已经可以处理扫描到的条码或二维码等等各种支持的码。


上述步骤是整个扫码启动的流程,启动摄像头后如何拿到摄像头拍照数据和数据如何解码,请看下面流程

==============解码流程如下: =======================

1.上述4.3中setOneShotPreviewCallback(previewCallback)会设置一个previewCallback回调到Camera,Camera
  抓取到数据数据回调previewCallback中的onPreviewFrame(byte[] data, Camera camera)方法
  @Override
  public void onPreviewFrame(byte[] data, Camera camera) {
    Point cameraResolution = configManager.getCameraResolution();
    Handler thePreviewHandler = previewHandler;
    if (cameraResolution != null && thePreviewHandler != null) {
      Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
          cameraResolution.y, data);
      message.sendToTarget();
      previewHandler = null;
    } else {
      Log.d(TAG, "Got preview callback, but no handler or resolution available");
    }
  }
  这里面的thePreviewHandler是通过4.3中previewCallback.setHandler(handler, message);设置进来的
  有上面4.3可知是DecodeHandler的实例。
2.具体处理看DecodeHandler中的handleMessage(Message message)
  @Override
  public void handleMessage(Message message) {
    if (!running) {
      return;
    }
    switch (message.what) {
      case R.id.decode:
        decode((byte[]) message.obj, message.arg1, message.arg2);
        break;
      case R.id.quit:
        running = false;
        Looper.myLooper().quit();
        break;
    }
  }
  decode方法中对数据做处理,然后将处理后的数据传到CaptureActivityHandler,具体代码如下
  Handler handler = activity.getHandler();
    if (rawResult != null) {
      // Don't log the barcode contents for security.
      long end = System.currentTimeMillis();
      Log.d(TAG, "Found barcode in " + (end - start) + " ms");
      if (handler != null) {
        Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
        Bundle bundle = new Bundle();
        bundleThumbnail(source, bundle);        
        message.setData(bundle);
        message.sendToTarget();
      }
    } else {
      if (handler != null) {
        Message message = Message.obtain(handler, R.id.decode_failed);
        message.sendToTarget();
      }
    }
3.再看CaptureActivityHandler中的handleMessage(Message message)
  @Override
  public void handleMessage(Message message) {
    switch (message.what) {
      case R.id.restart_preview:
        restartPreviewAndDecode();
        break;
      case R.id.decode_succeeded:
        System.out.println("decode_succeeded");
        state = State.SUCCESS;
        Bundle bundle = message.getData();
        Bitmap barcode = null;
        float scaleFactor = 1.0f;
        if (bundle != null) {
          byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
          if (compressedBitmap != null) {
            barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
            // Mutable copy:
            barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
          }
          scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR);          
        }
        activity.handleDecode((Result) message.obj, barcode, scaleFactor);
        break;
      case R.id.decode_failed:
        break;
      case R.id.return_scan_result:
        break;
      case R.id.launch_product_query:
        break;
    }
  }
  对传过来的数据做进一步的处理后传到调用的activity
  activity.handleDecode((Result) message.obj, barcode, scaleFactor);
4.上层activity根据传回来的数据做业务上的处理


 
 

猜你喜欢

转载自blog.csdn.net/nshzzu130/article/details/52596610
今日推荐