目前市面上二维码的扫描似乎用开源google的zxing比较多,接下去以2.2版本做一个简析吧,勿喷。。。

下载下来后定位两个文件夹,core和android,core是一些核心的库,android是针对android的一些代码。

zxing二维码扫描的流程简析(Android版)_第1张图片

我们先看核心库,在package com.google.zxing中的一些生成二维码的类关系

zxing二维码扫描的流程简析(Android版)_第2张图片

接口Writer里面有两个encode的重载函数,不同的格式的二维码有各自的类实现了Writer接口,MultiformatWriter类比较特殊,根据代码的注释可见其其实是个工厂类,根据BarcodeFormat实例化不同的Writer,然后最终调用各自的Encode.encode()方法

 1 public final class MultiFormatWriter implements Writer { 2  3   @Override 4   public BitMatrix encode(String contents, 5                           BarcodeFormat format, 6                           int width, 7                           int height) throws WriterException { 8     return encode(contents, format, width, height, null); 9   }10 11   @Override12   public BitMatrix encode(String contents,13                           BarcodeFormat format,14                           int width, int height,15                           Map<EncodeHintType,?> hints) throws WriterException {16 17     Writer writer;18     switch (format) {19       case EAN_8:20         writer = new EAN8Writer();21         break;22       case EAN_13:23         writer = new EAN13Writer();24         break;25       case UPC_A:26         writer = new UPCAWriter();27         break;28       case QR_CODE:29         writer = new QRCodeWriter();30         break;31       case CODE_39:32         writer = new Code39Writer();33         break;34       case CODE_128:35         writer = new Code128Writer();36         break;37       case ITF:38         writer = new ITFWriter();39         break;40       case PDF_417:41         writer = new PDF417Writer();42         break;43       case CODABAR:44         writer = new CodaBarWriter();45         break;46       case DATA_MATRIX:47         writer = new DataMatrixWriter();48         break;49       case AZTEC:50         writer = new AztecWriter();51         break;52       default:53         throw new IllegalArgumentException("No encoder available for format " + format);54     }55     return writer.encode(contents, format, width, height, hints);56   }57 58 }

然后看解析二维码的类结构

zxing二维码扫描的流程简析(Android版)_第3张图片

关键就是这个MultiformatReader,里面聚合了多个reader,并且根据客户端设置的DecodeHintType值,确定添加reader以及添加reader的顺序,最后调用reader.decode方法

  1 public final class MultiFormatReader implements Reader {  2   3   private Map<DecodeHintType,?> hints;  4   private Reader[] readers;  5   6   @Override  7   public Result decode(BinaryBitmap image) throws NotFoundException {  8     setHints(null);  9     return decodeInternal(image); 10   } 11  12   @Override 13   public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException { 14     setHints(hints); 15     return decodeInternal(image); 16   } 17  18   public Result decodeWithState(BinaryBitmap image) throws NotFoundException { 19     // Make sure to set up the default state so we don't crash 20     if (readers == null) { 21       setHints(null); 22     } 23     return decodeInternal(image); 24   } 25  26   public void setHints(Map<DecodeHintType,?> hints) {//根据设置的hint来设置reader 27     this.hints = hints; 28  29     boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); 30     @SuppressWarnings("unchecked") 31     Collection<BarcodeFormat> formats = 32         hints == null ? null : (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS); 33     Collection<Reader> readers = new ArrayList<Reader>(); 34     if (formats != null) { 35       boolean addOneDReader = 36           formats.contains(BarcodeFormat.UPC_A) || 37           formats.contains(BarcodeFormat.UPC_E) || 38           formats.contains(BarcodeFormat.EAN_13) || 39           formats.contains(BarcodeFormat.EAN_8) || 40           formats.contains(BarcodeFormat.CODABAR) || 41           formats.contains(BarcodeFormat.CODE_39) || 42           formats.contains(BarcodeFormat.CODE_93) || 43           formats.contains(BarcodeFormat.CODE_128) || 44           formats.contains(BarcodeFormat.ITF) || 45           formats.contains(BarcodeFormat.RSS_14) || 46           formats.contains(BarcodeFormat.RSS_EXPANDED); 47       // Put 1D readers upfront in "normal" mode 48       if (addOneDReader && !tryHarder) { 49         readers.add(new MultiFormatOneDReader(hints)); 50       } 51       if (formats.contains(BarcodeFormat.QR_CODE)) { 52         readers.add(new QRCodeReader()); 53       } 54       if (formats.contains(BarcodeFormat.DATA_MATRIX)) { 55         readers.add(new DataMatrixReader()); 56       } 57       if (formats.contains(BarcodeFormat.AZTEC)) { 58         readers.add(new AztecReader()); 59       } 60       if (formats.contains(BarcodeFormat.PDF_417)) { 61          readers.add(new PDF417Reader()); 62       } 63       if (formats.contains(BarcodeFormat.MAXICODE)) { 64          readers.add(new MaxiCodeReader()); 65       } 66       // At end in "try harder" mode 67       if (addOneDReader && tryHarder) { 68         readers.add(new MultiFormatOneDReader(hints)); 69       } 70     } 71     if (readers.isEmpty()) { 72       if (!tryHarder) { 73         readers.add(new MultiFormatOneDReader(hints)); 74       } 75  76       readers.add(new QRCodeReader()); 77       readers.add(new DataMatrixReader()); 78       readers.add(new AztecReader()); 79       readers.add(new PDF417Reader()); 80       readers.add(new MaxiCodeReader()); 81  82       if (tryHarder) { 83         readers.add(new MultiFormatOneDReader(hints)); 84       } 85     } 86     this.readers = readers.toArray(new Reader[readers.size()]); 87   } 88  89   @Override 90   public void reset() { 91     if (readers != null) { 92       for (Reader reader : readers) { 93         reader.reset(); 94       } 95     } 96   } 97  98   private Result decodeInternal(BinaryBitmap image) throws NotFoundException {//最终都调用这个方法 99     if (readers != null) {100       for (Reader reader : readers) {101         try {102           return reader.decode(image, hints);103         } catch (ReaderException re) {104           // continue105         }106       }107     }108     throw NotFoundException.getNotFoundInstance();109   }110 111 }

DecodeHintType的语法比较有意思,还在理解中

 1 public enum DecodeHintType { 2  3   /** 4    * Unspecified, application-specific hint. Maps to an unspecified {@link Object}. 5    */ 6  OTHER(Object.class), 7  8   /** 9    * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;10    * use {@link Boolean#TRUE}.11    */12   PURE_BARCODE(Void.class),13 14   /**15    * Image is known to be of one of a few possible formats.16    * Maps to a {@link List} of {@link BarcodeFormat}s.17    */18   POSSIBLE_FORMATS(List.class),19 20   /**21    * Spend more time to try to find a barcode; optimize for accuracy, not speed.22    * Doesn't matter what it maps to; use {@link Boolean#TRUE}.23    */24   TRY_HARDER(Void.class),25 26   /**27    * Specifies what character encoding to use when decoding, where applicable (type String)28    */29   CHARACTER_SET(String.class),30 31   /**32    * Allowed lengths of encoded data -- reject anything else. Maps to an {@code int[]}.33    */34   ALLOWED_LENGTHS(int[].class),35 36   /**37    * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;38    * use {@link Boolean#TRUE}.39    */40   ASSUME_CODE_39_CHECK_DIGIT(Void.class),41 42   /**43    * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.44    * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;45    * use {@link Boolean#TRUE}.46    */47   ASSUME_GS1(Void.class),48 49   /**50    * The caller needs to be notified via callback when a possible {@link ResultPoint}51    * is found. Maps to a {@link ResultPointCallback}.52    */53   NEED_RESULT_POINT_CALLBACK(ResultPointCallback.class),54 55   // End of enumeration values.56   ;57 58   /**59    * Data type the hint is expecting.60    * Among the possible values the {@link Void} stands out as being used for61    * hints that do not expect a value to be supplied (flag hints). Such hints62    * will possibly have their value ignored, or replaced by a63    * {@link Boolean#TRUE}. Hint suppliers should probably use64    * {@link Boolean#TRUE} as directed by the actual hint documentation.65    */66   private final Class<?> valueType;67 68   DecodeHintType(Class<?> valueType) {69     this.valueType = valueType;70   }71   72   public Class<?> getValueType() {73     return valueType;74   }75 76 }

然后我们看下android里面是如何调用的,入口是CaptureActivity,在com.google.zxing.client.android package中,以下描述一个通用的流程

zxing二维码扫描的流程简析(Android版)_第4张图片

CaptureAct中的onResume中的initCamera初始化CaptureActHandler,其构造函数中新起了一个DecodeThread去异步准备一个DecodeHandler,然后调用restartPreviewAndDecode方法,让DecodeHandler去处理R.id.decode的消息,当然这里需要处理一些线程同步问题,代码里用到了CountDownLatch来控制。DecodeHanlder处理R.id.decode消息后用传递R.id.decode_succeeded消息给CaptureActHanlder,最终再调用handleDecode传递给CaptureAct.

更多相关文章

  1. android 工程里缺少 R.java 文件原因和解决方法
  2. Android软件广告屏蔽方法及代码
  3. Android异步处理常用方法
  4. Android 7.0系统启动流程分析
  5. Android设置TextView显示指定个数字符,超过部分显示...(省略号)的
  6. Android 环信官方Demo3.3.2详细配置方法

随机推荐

  1. activity启动模式
  2. Android 2.2兼容性移植
  3. 怎么在android的XML文件里加入凝视
  4. 关于android中px,dip,dp,sp等单位
  5. MPAndroidChart项目实战(八)——自定义分段
  6. Eclipse中导入Android工程
  7. 网格布局(计算器界面设计)
  8. Android(安卓)自定义消息右上角的数字提
  9. Android(安卓)开发进阶之『清除应用中的
  10. Android各大发布市场