2019独角兽企业重金招聘Python工程师标准>>>

zxing2.3.0目录结构(android相关)

下载zxing2.3.0后,与android相关的有三个目录:

android:就是Barcode Scanner,中文名"条码扫描器"。下文中简写为BS。

android-integration:提供一种简单的途径将Barcode Scanner整合到调用方app中

androidtest:模拟调用方app,通过android-integration整合Barcode Scanner

如果将androidtest看做你的app的话,那么上面三者的关系将会如下图:

android-integration

zxing项目的本意是将BS作为一个独立的app,可以单独使用,同时亦可简单被其他app调用,在调用的过程中给用户的感觉它们是一个整体。在这中间起到”简单整合”作用的便是android-integration。

正如android-integration的文档中所述,android-integration的作用在于为调用方提供一个简单的方法实现扫描并接受扫描的结果,调用方完全不必了解BS的代码原理(不必为了整合到调用方app中而学习BS代码),只需按照简单的几个步骤即可轻松实现编解码。

但是这样看起来简单的整合存在一个问题:作为独立应用的BS必须与调用方app一起被安装,否则android-integration会要求用户到应用市场下载BS。而BS同时包含了编解码功能,如果只需要解码功能,那多余的那部分编码功能只是徒增了app的大小却没有任何用处。研究BS源码是势在必行。

integration的使用方法只需简单的两步,具体使用方法可参考IntentIntegrator类的注释。

androidtest

这是一个完整的应用Barcode Scanner的实例,从主界面上即可看出可用的操作,其实大部分操作都是在BS中完成的:

该例子需要引入android-support-v4.jar,core-2.3.0.jar,还依赖android-integration。

androidtest代码比较简单,基本上没什么需要解释的。第一个Run benchmark是一个用来解码本地图片的功能,该功能会扫描${sdcard}/zxingbenchmark目录下的条码图片,并解码,例子中仅仅打印了图片的编码格式,可以通过com.google.zxing.Result.getText()获取被编码的文本。

该功能的核心类就是com.google.zxing.MultiFormatReader和com.google.zxing.Result。后面我们在分析Barcode Scanner的时候会再次遇到MultiFormatReader。

Barcode Scanner

是一个功能强大的条码扫描器,不仅支持多种类型的条码,还支持多国语言,分享二维码,查看扫描历史,反向扫描等功能。

包结构

android:与CaptureActivity直接相关的核心组件。包含了发生震动管理器,闪光灯等等,后面介绍

book:如果查询的结果是图书信息,用户可以选择查询该书的更进一步的详细信息,该包即包含了搜索与展示书籍的相关类。

camera/camera.open:摄像头相关组件,核心类是CameraManager

clipboard:剪贴板

encode:编码功能的各个组件集合。核心类为QRCodeEncoder,最终实施编码的是MultiFormatWriter类

history:扫描历史管理,核心类是HistoryManager

result:条码扫描的结果被分为不同的类型,所有的类型都定义在com.google.zxing.client.result.ParsedResultType中,对于不同的类型都有对应的处理方法:xxxResultHandler,所有的ResultHandler都包含在此包中。不同的xxxResultHandler还提供了扫描结果页面要展示几个button,每个button的文本以及需要绑定的事件等等。

result.supplement:对已经扫描并解码的结果做额外处理的工具集。比如扫描出来的是isbn号,如果在设置中选择了“检索更多信息”则会在扫描出isbn号之后自动去网上查询该书的信息,最后将书的信息展示出来,而如果没选中,则只会将isbn号码展示。

share:分享二维码功能,亦是编码功能的入口所在。

wifi:是WifiResultHandler的辅助类集合。如果扫描到的二维码是对wifi信息的编码,那么最终扫描结果页会展示一个“连接到网络”的按钮,点击此按钮就会自动尝试连接。该包中所包含的类则是链接网络所需的工具类。

代码解析

按照功能来分,其实BS是由:扫描 、历史和分享(生成二维码) 组成。

## 新增内容(2014/3/16) ##

概览

在较为详细地对代码进行全面分析之前,我把扫码+解码的流程说的更简单一些,因为很多功能我们并不需要太关注,比如声音、对焦、闪光灯等等,我们关注的只是这一套动作是怎么实现的:

* 打开预览界面。zxing借助的肯定是camera的功能,通过分析和了解camera的工作原理可知,调用Camera.startPreview()后,就可以从屏幕中看到预览界面。

* 捕捉画面。处在previewing状态的画面,随时都可以捕获(即使不对焦也可以,只是模糊一点而已)。调用Camera.setOneShotPreviewCallback(),该方法会在启动preview之后,预览界面展示出来后调用(只调用一次便自动解绑),向回调函数Camera.PreviewCallback.onPreviewFrame()中传回当前画面的字节数组。

* 解析。拿到字节数组就可以解码了。这部分逻辑是包含在core中的,zxing的应用层无需关注的逻辑。

## 新增内容 ##

详述

在分析这三部分功能之前,先来看下配置。在界面上对应“设置”,在代码中则是利用了PreferenceFragment类,将用户对Camera以及扫描行为的设置保存在SharePreferences中。后文提到的“配置”均指用户在设置中进行的设置。

扫描

进入扫描界面后大致做了如下的事情:配置Camera并启动Camera、构建preview与扫描窗口、捕捉画面并解码、将解码结果交给不同ResultHandler去处理。下面逐一进行分析。

1. 配置Camera并启动Camera

启动Camera是在CaptureActivity.initCamera中进行的,最重要的两句代码是:

cameraManager.openDriver(surfaceHolder);
...handler = new CaptureActivityHandler(this, decodeFormats, decodeHints,characterSet, cameraManager);
...

CameraManager是相机管理类,是BS中唯一与Camera打交道的类,CameraManager.openDriver主要做了三件事:

    /*** Opens the camera driver and initializes the hardware parameters.* * @param holder The surface object which the camera will draw preview frames into.* @throws IOException Indicates the camera driver failed to open.*/public synchronized void openDriver(SurfaceHolder holder) throws IOException {Camera theCamera = camera;if (theCamera == null) {// 1. 获取手机背面的摄像头theCamera = OpenCameraInterface.open();if (theCamera == null) {throw new IOException();}camera = theCamera;}// 2. 设置摄像头预览viewtheCamera.setPreviewDisplay(holder);if (!initialized) {initialized = true;configManager.initFromCameraParameters(theCamera);if (requestedFramingRectWidth > 0 && requestedFramingRectHeight > 0) {setManualFramingRect(requestedFramingRectWidth, requestedFramingRectHeight);requestedFramingRectWidth = 0;requestedFramingRectHeight = 0;}}Camera.Parameters parameters = theCamera.getParameters();String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save// these,// temporarilytry {// 3. 读取配置并设置相机参数configManager.setDesiredCameraParameters(theCamera, false);} catch (RuntimeException re) {// Driver failedLog.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters");Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened);// Reset:if (parametersFlattened != null) {parameters = theCamera.getParameters();parameters.unflatten(parametersFlattened);try {theCamera.setParameters(parameters);configManager.setDesiredCameraParameters(theCamera, true);} catch (RuntimeException re2) {// Well, darn. Give upLog.w(TAG, "Camera rejected even safe-mode parameters! No configuration");}}}}

CameraConfigurationManager是相机辅助类,主要用于设置相机的各类参数。核心方法有两个:

  • initFromCameraParameters:计算了屏幕分辨率和当前最适合的相机像素

  • setDesiredCameraParameters:读取配置设置相机的对焦模式、闪光灯模式等等

CaptureActivityHandler类是一个针对扫描任务的Handler,可接收的message有启动扫描(restart_preview)、扫描成功(decode_succeeded)、扫描失败(decode_failed)等等。

在创建一个CaptureActivityHandler对象的时候也做了三件事:

    CaptureActivityHandler(CaptureActivity activity, Collection<BarcodeFormat> decodeFormats,Map<DecodeHintType, ?> baseHints, String characterSet, CameraManager cameraManager) {this.activity = activity;// 1. 启动扫描线程decodeThread = new DecodeThread(activity, decodeFormats, baseHints, characterSet,new ViewfinderResultPointCallback(activity.getViewfinderView()));decodeThread.start();state = State.SUCCESS;// Start ourselves capturing previews and decoding.this.cameraManager = cameraManager;// 2. 开启相机预览界面cameraManager.startPreview();// 3. 将preview回调函数与decodeHandler绑定、调用viewfinderViewrestartPreviewAndDecode();}

restartPreviewAndDecode方法又调用了CameraManager.requestPreviewFrame:

    /*** A single preview frame will be returned to the handler supplied. The data* will arrive as byte[] in the message.obj field, with width and height* encoded as message.arg1 and message.arg2, respectively.* <br/>* * 1:将handler与preview回调函数绑定;<br/>* 2:注册preview回调函数<br/>* 综上,该函数的作用是当相机的预览界面准备就绪后就会调用hander向其发送传入的message* * @param handler The handler to send the message to.* @param message The what field of the message to be sent.*/public synchronized void requestPreviewFrame(Handler handler, int message) {Camera theCamera = camera;if (theCamera != null && previewing) {previewCallback.setHandler(handler, message);// 绑定相机回调函数,当预览界面准备就绪后会回调Camera.PreviewCallback.onPreviewFrametheCamera.setOneShotPreviewCallback(previewCallback);}}

2. 构建preview与扫描窗口

首先相机有自己的preview界面,然后我们需要构造一个扫描窗口,引导用户将条码置于窗口中完成扫描。

构造扫描窗口是在CaptureActivityHandler.restartPreviewAndDecode中,通过调用activity.drawViewfinder()来实现的。这里有个画扫描窗口的类叫ViewfinderView,该类也是想要改变扫描窗口风格所必须重构的一个类。

由于网上已经有很多重构ViewfinderView的帖子,本文不再赘述,可以参考《基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果》

相机的preview界面显示出来后即可开始扫描,所以需要监听preview是否已经显示这个事件,这就是Camera.PreviewCallback的作用。PreviewCallback.onPreviewFrame做的事便是当preview界面展示出来的时候向DecodeHandler发送一个decode消息,DecodeHandler收到该消息后会执行decode方法来解码。

注意,检测并触发捕获画面动作的,是Camera.setOneShotPreviewCallback()这个方法。该函数被调用后,如果预览界面已经打开,就会将包含当前preview frame的byte数组传给回调函数,此时再向DecodeHandler发送decode消息。

3. 捕捉画面并解码

具体参考DecodeHandler.decode方法。(本文只从宏观上对zxing进行分析,对于解码的原理将会另开博文进行介绍)

4. 将解码结果交给不同ResultHandler去处理

当DecodeHandler.decode完成解码后会向CaptureActivityHandler发消息。如果编码成功则调用CaptureActivity.handleDecode方法对扫描到的结果进行分类处理。

该方法中首先获取ResultHandler:

// 解析rawResult,根据不同类型result生成对应的ResultHandler
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);

然后调用handleDecodeInternally和handleDecodeExternally对ResultHandler进行处理。谈到这两个方法,就不得不再分析一下IntentSource。

enum IntentSource {/*** 本地app向BS(Barcode Scanner)发起的启动指令* 比如在androidtest项目中,利用整合的android-integration对BS发起调用指令:com.google.zxing.client.android.SCAN* BS中该启动命令对应的Source类型便是NATIVE_APP_INTENT*/NATIVE_APP_INTENT,/*** 打开BS的时候传入查询商品的url,与最终扫描到的product id结合进行查询* 两种url的形式不同*/PRODUCT_SEARCH_LINK,ZXING_LINK,/*** 直接打开BS*/NONE}

结合CaptureActivity.onResume中的部分代码来理解:

            } else if (dataString != null && dataString.contains("http://www.google")&& dataString.contains("/m/products/scan")) {// Scan only products and send the result to mobile Product// Search.source = IntentSource.PRODUCT_SEARCH_LINK;sourceUrl = dataString;decodeFormats = DecodeFormatManager.PRODUCT_FORMATS;} else if (isZXingURL(dataString)) {// Scan formats requested in query string (all formats if none// specified).// If a return URL is specified, send the results there.// Otherwise, handle it ourselves.source = IntentSource.ZXING_LINK;sourceUrl = dataString;Uri inputUri = Uri.parse(dataString);scanFromWebPageManager = new ScanFromWebPageManager(inputUri);decodeFormats = DecodeFormatManager.parseDecodeFormats(inputUri);// Allow a sub-set of the hints to be specified by the caller.decodeHints = DecodeHintManager.parseDecodeHints(inputUri);}

NATIVE_APP_INTENT和NONE很好理解,而PRODUCT_SEARCH_LINK和ZXING_LINK是指定查询商品的url(而不是交给zxing分析后再决定去哪里查询),将扫描出来的内容拼凑到url中,然后在浏览器中展示结果。

理解了IntentSource,就容易看懂handleDecodeInternally其实就是将结果展示到界面上。handleDecodeExternally稍复杂些,当source == IntentSource.NATIVE_APP_INTENT时,BS会将扫描分析的结果存到Intent中返回给调用方app,因此调用方app在启动BS的时候一定要使用startActivityForResult。这一点可以在androidtest的IntentIntegrator.initiateScan方法的最后看到。

历史

每扫描成功一次会有一次记录,逻辑相对简单,不再花更多时间分析。

分享

对于分享,其实我们更关注的是其编码的实现。这部分代码就比扫描少得多,精简过后,核心包已经减少到2个:

点击分享会进入到分享界面,每一种分享方式最终会生成一个二维码,二维码界面是EncodeActivity,核心代码只需参考onResume中的这一句:

Bitmap bitmap = qrCodeEncoder.encodeAsBitmap();

进入encodeAsBitmap中,最终看到的是与MultiFormatReader相对应的方法MultiFormatWriter,此方法是生成二维码的关键。

以上是对zxing项目android部分的代码简单介绍。

Barcode Scanner的代码我已经加了较为完整的注释,代码上传至git.oschina.net:Zxing-Simplification

转载于:https://my.oschina.net/madmatrix/blog/189031

【基于zxing的编解码实战】zxing项目源码解读(2.3.0版本,Android部分)相关推荐

  1. 基于Java的环保企业网站管理系统+项目源码(SSM框架)

    活动地址:毕业季·进击的技术er 博主介绍:✌在职Java研发工程师.专注于程序设计.源码分享.技术交流.专注于Java技术领域和毕业设计✌ 项目名称 基于Java的环保企业网站管理系统+项目源码(S ...

  2. 基于SSM搭建的学生信息管理系统项目源码+学习视频

    基于SSM搭建的学生信息管理系统 目录 基于SSM搭建的学生信息管理系统 1.为什么要编写学生信息管理系统 1.1编写项目的起因: 2.编写学生信息管理系统的过程 2.1项目成果的展示: 登录界面: ...

  3. 基于ssm Vue+elementui农家乐管理系统java 项目源码介绍

    一.源码描述   这是一款基于web的前后端分离JAVA+SSM和vue.js源码 基于B/S开发,包含毕业论文和答辩ppt,开发工具idea支持eclipse,MySQL,适合作为毕业设计使用,感兴 ...

  4. 钢七连实战C3-P2:项目源码结构 面向对象基础 堆分配

    钢七连软件培训 C3-P2  面向对象  第2节 1.怎样阅读一套项目源码 2.面向对象基本技术 https://blog.csdn.net/weixin_42644456 一.通用的学习路线,解决办 ...

  5. 基于SpringBoot框架的管理系统【完整项目源码】

    基于SpringBoot框架的管理系统 介绍 基于SpringBoot框架的管理系统 简洁版 : 实现 登录 . 注册 . 增 . 删 . 改 . 查 : 可继续完善增加前端.校验.其他功能等: 可作 ...

  6. 基于SSM框架的管理系统【完整项目源码】

    基于SSM框架的管理系统 [文末附源码] 1前言 基于SSM框架的管理系统简洁版: 实现登录.注册.增.删.改.查: 可继续完善增加前端.校验.其他功能等: 可作为SSM项目开发练习基础模型: 课程设 ...

  7. 基于SSM的视频管理系统【完整项目源码】

    项目介绍  1.第一款面向大众的java版的视频管理系统. 2.妖气山视频管理系统理论上可以制作任何类型的视频网站. 软件架构 前端:javaex 后端:ssm 数据库:mysql 编译器:eclip ...

  8. 【基于zxing的编解码实战】初识条形码

    2019独角兽企业重金招聘Python工程师标准>>> 条形码定义     条形码(barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符 ...

  9. 推荐一款基于Vue的开源智慧物业解决方案项目源码

    项目介绍 「e家宜业」是一整套基于AGPL开源协议开源的智慧物业解决方案.实现了微信公众号.小程序.PC.H5.智能硬件多端打通,旨在提升物业公司效率.规范物业服务流程.提升物业服务满意度.加强小区智 ...

  10. 黑马最新Android P2P金融项目开发实战 视频+项目源码

    p2p金融项目,结合现有第三方应用市场上主流p2p金融理财产品特点,集成了新的技术与框架.该项目内容包含p2p金融理财业务流程,数据加密.解密,客户端异常信息上传,用户登录注册,数据的图表展示,第三方 ...

最新文章

  1. Vue route页面跳转,传递参数接收到的参数为空
  2. c++ 获取文件的hashcode_jsp 实现文件上传和下载
  3. 赛尔原创 | N-LTP:基于预训练模型的中文自然语言处理平台
  4. js上拉加载ajax数据,原生ajax写的上拉加载实例
  5. java http 返回值_java发送http请求,无需等待返回结果
  6. ie和谷歌在java中空格兼容,谷歌和IE浏览器的兼容性问题,相同的html结构竟然在两个浏览器不一样...
  7. 再说变体结构 - 回复 彬 的问题
  8. 电力行业巡检对讲通信系统
  9. 腾达无线加密与Win7
  10. eviews计算covar_第7章 我国商业银行风险溢出效应的度量—基于GARCH-CoVaR模型
  11. 信噪比 香农公式_「香农公式」信噪比/香农公式 - seo实验室
  12. 三角函数π/2转化_数学集训营 | NO.16 任意角的三角函数之必考点
  13. 方舟服务器设置文档,方舟云服务器设置
  14. 实战录 | 云端卫士之DPDK技术简介
  15. Masked Siamese Networksfor Label-Efficient Learning
  16. JAVA判断两个数是否亲和数_亲和数
  17. 如何零基础创建自己的微信小程序
  18. 【ninja】Ninja安装和基本使用
  19. 数据库应用----Mongodb 4.0 版本 基础操作---复制集,选举方法、部署认证 (二)
  20. 操作系统 第二章 进程的描述与控制(4)进程同步(重点)

热门文章

  1. Oracle10g BIGFILE表空间带来的好处
  2. H264--H264编码--4
  3. python web框架 多线程_Django基础一之web框架的本质
  4. RoaringBitmap分析及使用
  5. python的with用法
  6. CTR点击率预估实战分享
  7. python安装详细步骤windows10_Windows10系统安装Python教程
  8. 201约花鸟画 考c语言试题,全国计算机二级C语言上机100题..doc
  9. python大众点评霸王餐_不收藏肯定后悔!大众点评前员工告诉你,如何利用点评APP吃霸王餐!...
  10. 双系统linux安装cetos,电脑安装windows和centOS系统双系统