最近在优化扫码功能,对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根据传回来的数据做业务上的处理