【Android】条形码/二维码扫描——ZXing源码分析及相关jar包导入

转载自:http://blog.csdn.net/u010574567/article/details/51916604

*********************1.源码分析*************************
针对3.2.1版本源码 与其他版本代码可能会有出入,但核心思想基本不变。 
首先从com.google.zxing.client.Android包中的目录结构分析:

Book:

这个文件夹中有5个类: 
BrowseBookListener 实现了adapter的点击事项响应,通过获取ISBN,然后跳转到Google books中查询响应的详细信息。 
SearchBookContentsActivity 通过google books查询图书相关信息的具体实现 
SearchBookContentsAdapter,SearchBookContentsListItem 为listview的适配器和item类的内容,这在之前的文章中介绍过,不再赘述。 
SearchBookContentsResult 包含了searchbookcontent类的基本内容,成员变量及get、set方法等

Camera

这是一个控制摄像头的类,open文件中是打开摄像头及一些配置方法,open文件夹外面的是一些camera属性的操作。 
CameraFacing 枚举变量 值为0代表后置摄像头、1代表前置摄像头 
OpenCamera 表示一个已打开的摄像头,同时保存着camera的原始数据CameraInfo以及摄像头朝向、方位等信息。 
OpenCameraInterface 帮助我们打开摄像头的一个类,如果没有特殊偏好,默认打开后置摄像头。 
AutoFocusManager自动对焦相关的函数 
CameraConfigurationManager initFromCameraParameters通过屏幕分辨率和相机分辨率,去寻找最合适的预览分辨率。 setDesiredCameraParameters读取配置设置相机的对焦模式、闪光灯模式以及屏幕到相机的转动角度等信息 
CameraConfigurationUtils 配置android相机的一些方法 
FrontLightMode 枚举闪光灯是否开启 
CameraManager camera的核心类,其他类都是在这里调用的。openDriver用于camera的打开及初始化。 
PreviewCallback 回调类,当扫描到结果时会调用这个类返回结果。

Cliboard

ClipboardInterface 剪贴板接口,实现内容的复制粘贴

Encode

根据内容实现各种格式的从新编码

History

历史扫描记录,这里google采用了数据库的存储方式并用listView显示出来,基本与作者之前的文章一致,可以看数据库操作 和 listview显示

Result

result文件夹下内容很多,首先看入口ResultHandlerFactory这个类。他根据条形码的类型启动不同的Handler,具体的类型可以看ParsedResultType这个枚举中的内容,每个Handler具体就不介绍了。 
这里写图片描述

Share

主要实现分享app应用,书签等内容

Wifi

NetworkType 网络类型枚举类 
WifiConfigManager 网络配置管理,修改网络类型等内容。


AmbientLightManager 
—根据外界光线情况选择是否打开闪光灯补光 
BeepManager 
—管理声音 
CaptureActivity ———程序的主入口

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();
    state = State.SUCCESS;

    // Start ourselves capturing previews and decoding.
    //开启预览框
    this.cameraManager = cameraManager;
    cameraManager.startPreview();
    //preview回调函数与DecodeHandler绑定、绘制扫描框
    restartPreviewAndDecode();
  }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在restartPreviewAndDecode()中

 private void restartPreviewAndDecode() {
    if (state == State.SUCCESS) {
      state = State.PREVIEW;
      cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
      activity.drawViewfinder();
    }
  }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果状态是SUCCESS将会开始绘制预览框,通过调用viewfinderView.drawViewfinder();

public synchronized void requestPreviewFrame(Handler handler, int message) {
    OpenCamera theCamera = camera;
    if (theCamera != null && previewing) {
      previewCallback.setHandler(handler, message);
      theCamera.getCamera().setOneShotPreviewCallback(previewCallback);
    }
  }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

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

DecodeHandler 
得到了扫描的结果,调用handleDecode进行解码

  activity.handleDecode((Result) message.obj, barcode, scaleFactor);
 
 
  • 1
  • 1

进而我们看handleDecode类

  public void handleDecode(Result rawResult, Bitmap barcode, float scaleFactor) {
    inactivityTimer.onActivity();
    lastResult = rawResult;
    //根据扫描结果 调用resulthandler工厂分析类型
    ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);

    boolean fromLiveScan = barcode != null;
    if (fromLiveScan) {
      //加入历史
      historyManager.addHistoryItem(rawResult, resultHandler);
      // Then not from history, so beep/vibrate and we have an image to draw on
      beepManager.playBeepSoundAndVibrate();
      drawResultPoints(barcode, scaleFactor, rawResult);
    }

    switch (source) {
      case NATIVE_APP_INTENT:
      case PRODUCT_SEARCH_LINK:
        handleDecodeExternally(rawResult, resultHandler, barcode);
        break;
      case ZXING_LINK:
        if (scanFromWebPageManager == null || !scanFromWebPageManager.isScanFromWebPage()) {
          handleDecodeInternally(rawResult, resultHandler, barcode);
        } else {
          handleDecodeExternally(rawResult, resultHandler, barcode);
        }
        break;
      case NONE:
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        if (fromLiveScan && prefs.getBoolean(PreferencesActivity.KEY_BULK_MODE, false)) {
          Toast.makeText(getApplicationContext(),
                         getResources().getString(R.string.msg_bulk_mode_scanned) + " (" + rawResult.getText() + ')',
                         Toast.LENGTH_SHORT).show();
          // Wait a moment or else it will scan the same barcode continuously about 3 times
          restartPreviewAfterDelay(BULK_MODE_SCAN_DELAY_MS);
        } else {
          //将结果显示出来
          handleDecodeInternally(rawResult, resultHandler, barcode);
        }
        break;
    }
  }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

源码中一些类的简单介绍,详细介绍在以后具体项目中再做详述。 
Rect类:用于表示一个矩形区域,并可以对这个区域进行一些操作。有4个参数代表4个边缘(left, top, right,bottom),要注意的是left,top是包含的,而right,bottom是不包含的。例如(20,10,50,100)指的是(20,10)到(49,99)这个矩形区域的内容。

WindowManager类:http://blog.csdn.net/xieqibao/article/details/6567814这里有比较精炼的介绍,就不多说了。

Display类: 引用Display.java中的注释

Provides information about the size and density of a logical display. 
A logical display does not necessarily represent a particular physical display device such as the built-in screen or an external monitor. The contents of a logical display may be presented on one or more physical displays according to the devices that are currently attached and whether mirroring has been enabled.

其中有个很重要的getRotation()方法,由于官方demo只能横屏,所以需要理解后进行修改。 
这里返回的Surface.ROTATION_X(X=0,90,180,270) 值得是图像要弥补渲染所需要顺时针转动的角度,他和设备所处的转动角度是相反的。比如设备竖直朝上是一开始的位置,将设备逆时针旋转90度,图像为了保持不变,需要顺时针旋转90度,所以这样rotation的值就是Surface.ROTATION_90。


*****************2.jar包导入Android Studio*****************

如果项目中没有看到libs文件夹,把项目目录切换到project而不是Android目录 然后新建文件夹libs 
这里写图片描述


首先是官方链github源码链接 注意在Branch里面选择版本,这里以3.2.1最新版为例 
https://github.com/zxing/zxing 
之后我们下载core.jar 地址在下面,选择对应版本,注意要与之前的源码一样,因为会有很多改动及函数增加,不同版本会认不到 
http://repo1.maven.org/maven2/com/google/zxing/ 
在README中有一些简单的介绍,包括支持的语言,支持的code格式,可以去看一下。 
这里写图片描述 
对Android来说,只有android-core、android、android-integration、androidteset有用(由于我们直接去下core.jar 所以core文件夹里的内容可以不用去管了) 
android-integration 提供了一种简单的方式将扫码整合到调用的应用中 
androidtest是模拟调用方 
android文件里面是一整个demo,包含识别多种格式的条形码,多国语言,二维码分享,建有扫描历史数据库,还包括一些辅助功能如灯光、震动、声音、联网查询书籍等等,在下一篇源码分析当中再做介绍。


这里我们只关心android 这个demo,所以直接导入android文件夹到AS里,然后在project中新建libs文件夹(一般是没有的),然后把我们下载的core-3.2.1.jar粘贴进来,然后右键jar文件,点击add as library,然后发现我们可以去查看jar库里的文件了。 
这里写图片描述 
这里有可能出现问题,注意查看project structure里面是否正确的导入了。 
这里写图片描述 
之后我们将android-core文件夹里的CameraConfigurationUtils.java文件拷到com.google.zxing.client.android/camera中 
这里写图片描述 
如图,应该现在可以运行了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值