【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中 
這裏寫圖片描述 
如圖,應該現在可以運行了。


發佈了14 篇原創文章 · 獲贊 5 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章