ZXing 源碼分析(簡閱)

導讀

  • 雖然有句話在程序員中說:”別人造好的輪子,不要重複發明輪子”,但是隻會用別人的東西,對自己個人技術的提升也是不可能的0.0 那麼最好的方式就是看源碼.
  • 本篇文章就是個人在使用ZXing後看官方Demo源碼的讀後感,有不對的地方歡迎評論指出,一起討論.

源碼操作:


官方源碼Demo結構圖:

官方源碼Demo結構圖

由圖可知官方Demo裏面有兩個項目:
1. CaptureActivity 官方的”二維碼掃描器”項目
2. ZXingTestActivity 測試CaptureActivity用的,有興趣的同學自己看下,以後有時間再補充


com.google.zxing.client.android 包

與CaptureActivity直接相關的核心組件。包含了發生震動管理器,閃光燈等等

  • AmbientLightManager implements SensorEventListener 光線管理器(環境光亮屏幕自動變暗,反之)

使用 (當我們閃光燈模式選擇自動時會調用):
1. CaptureActivity onCreate() 實例化AmbientLightManager ambientLightManager = new AmbientLightManager(this);
2. 在要使用的方法啓動ambientLightManager.start(cameraManager)或關閉ambientLightManager.start()

  • BeepManager implements MediaPlayer.OnErrorListener, Closeable 掃描成功後的手機震動和提示音管理器

使用:
1. CaptureActivity onCreate() 中 BeepManager beepManager = new BeepManager(this);
2. CaptureActivity onResume() 中 beepManager.updatePrefs();
3. CaptureActivity onPause() 中 beepManager.close();
4. 在要使用的方法啓動 beepManager.playBeepSoundAndVibrate();

  • CaptureActivity “條形碼掃描器”主頁面,主要邏輯

  • CaptureActivityHandler 消息處理類

幾個消息說明:
1. DecodeHandler 的 decode_succeeded 解碼成功
2. DecodeHandler 的 decode_failed 解碼失敗
3. CaptureActivity 的 restart_preview 啓動掃描
4. CaptureActivity 的 return_scan_result 返回條形碼結果內容界面
5. CaptureActivity 的 launch_product_query 查詢商品(打開瀏覽器)

  • Contents 常量類(掃碼類型)

  • DecodeFormatManger 配置”解碼類型”管理類:

主要方法:
通過parseDecodeFormats() ,返回我們掃描後得到的 “解碼格式” (一維碼,二維碼,其他)
1. DecodeFormatManager.parseDecodeFormats(intent);
2. DecodeFormatManager.parseDecodeFormats(inputUri);

  • DecodeHandler 解碼消息處理類:

主要方法:
DecodeHandler.decode(byte[] data, int width, int height) 解碼取景器矩形中的數據以及所需時間 解碼的核心類
DecodeHandler類被DececodeThread線程中實例化 Handler handler = new DecodeHandler(activity, hints);

  • DecodeHintManager 解碼線索管理類 (根據傳進來的參數(Uri,intent),返回線索)

小說明:
1. “hints 線索”: 用於通過條形碼閱讀器,更快或準確的解碼
2. 傳線索給 CaptrueActivity ,交給DecodeThread 處理

主要方法 (在CaptureActivity onResume() 中被調用):
1. DecodeHintManager.parseDecodeHints(intent);
2. decodeHints = DecodeHintManager.parseDecodeHints(inputUri);

  • DecodeThread 這個線程處理所有圖像的解碼

主要處理從 CaptureActivity 拿到的hints 線索

  • FinishListenr implements DialogInterface.OnClickListener,DialogInterface.OnCancelListener

Dialog 監聽器(用於出現bug時退出Activity)

*使用:(結合 AlertDialog.Builder)*
 AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(getString(R.string.app_name));
    builder.setMessage(getString(R.string.msg_camera_framework_bug));
    builder.setPositiveButton(R.string.button_ok, new FinishListener(this));
    builder.setOnCancelListener(new FinishListener(this));
    builder.show();
  • HelpActivity 幫助頁面(webView查看幫助文檔)

  • HttpHelper 網絡請求工具類:

小說明:
1. HttpConnection 安全的網絡請求(處理了可能出現的異常)
2. 訪問特定的主機名或者以外的主機名
3. 能請求不同的網絡數據類型 (html,xml,json,text)
4. 請求數據成功,把數據存到StringBuilder 緩衝區

主要方法(搜索圖書資源用):
1. downloadViaHttp(String uri, ContentType type) 下載全部資源
2. downloadViaHttp(String uri, ContentType type, int maxChars) 下載自定大小資源
3. unredirect(Uri uri) 未定向訪問網絡 (如果訪問的uri不包含上面的Host,就訪問默認的uri)

 使用:
   CharSequence content = HttpHelper.downloadViaHttp(uri,HttpHelper.ContentType.JSON);

 如:
   HttpHelper.downloadViaHttp("https://www.googleapis.com/books/v1/volues?q=isbn:" + isbn,HttpHelper.ContentType.JSON);
  • InactivityTimer 一段時間不操作(5分鐘 ),關閉該應用(工具類)

使用在生命週期方法中:
1. 在onCreate() 初始化該對象 InactivityTimer = new InactivityTimer(this);
2. 在onResume() ; inactivityTimer.onResume()
3. 在onPause() ; inactivityTimer.onPause();
4. 在onDestroy() ; inactivityTimer.shutdown();
5. 在處理解碼的handleDecode() 初始化該方法 ; inactivityTimer.onActivity() 啓動裏面的線程方法,讓應用在解碼時不執行InactivityTimer

  • Intents 這個類提供了在發送條形碼掃描器的意圖所使用的常量。

  • IntentSource 枚舉類

1. NATIVE_APP_INTENT
  本地app向條碼掃描器(Barcode Scanner)發起的啓動指令
     * 比如在androidtest項目中,利用整合的android-integration對條碼掃描器發起調用指令
     * :com.google.zxing.client.android.SCAN
     * 條碼掃描器中該啓動命令對應的Source類型便是NATIVE_APP_INTENT

2. PRODUCT_SEARCH_LINK   ,   ZXING_LINK
  打開條碼掃描器的時候傳入查詢商品的url,與最終掃描到的product id結合進行查詢 兩種url的形式不同

3. NONE
  直接打開條碼掃描器
  • LocaleManager 處理任何特定地區的設備邏輯(適配設備語言的工具類)

  • PreferencesActivity “設置”裏面的一些常量

    用PreferencesFragment replace PreferencesActivity

  • PreferencesFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener “設置”頁面實現

  1. 佈局在 res/xml/Preferences
  2. 一般結合PreferencesActivity 一起使用
  3. 裏面有很多的Preference對象調用
  4. “自定義搜索網址”單獨實現
  5. “條碼類型”,設置幾個雙選框選項,最少選擇一項
  • ScanFromWebPageManager 工具類:

傳一個html的url,通過佔位符{CODE},{RAWCODE},{META},{FORMAT},{TYPE}返回一個對應的,我們能處理的url
1. 讓我們可以從一個網頁調用ZXing進行掃描,通過回調URL的方式,返回結果到我們的網站
2. 如掃到 01234,鏈接到 http://foo.com/products/01234/description 網頁
3. {CODE}是一種返回代碼值的佔位符

  • ViewfinderView SurferView相機預覽界面(取景器矩形和部分透明,激光掃描儀點動畫和結果)

  • ViewfinderResultPointCallback SurferView相機預覽回調


com.google.zxing.client.android.book 包

如果查詢的結果是圖書信息,用戶可以選擇查詢該書的更進一步的詳細信息,該包即包含了搜索與展示書籍的相關類。

  • BrowseBookListener SearrchBookContentsActivity 中的Item按鍵監聽器

  • SearchBookContentsActivity 聯網”搜索圖書”頁面

  • SearchBookContentsAdapter Adapter適配器

  • SearchBookContentsListItem 顯示圖書搜索結果的頁碼和摘要的列表項

  • SearchBookContentsResult 圖書搜索結果數據bean類


com.google.zxing.client.android.camera 包

  • AutoFocusManager implements Camera.AutoFocusCallback 自動對焦
 *在CameraManager中被使用*
 AutoFocusManager implements Camera.AutoFocusCallback  自動對焦
使用:(在Camera中被使用)

OpenCamera theCamera = camera;

AutoFocusManager  autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());  

1. autoFocusManager.start();
2. autoFocusManager.stop();
  • CameraConfigurationManager 設置相機的參數信息類

主要方法:
1. initFromCameraParameters(OpenCamera camera) 計算了屏幕分辨率和當前最適合的相機像素
2. setDesiredCameraParameters(OpenCamera camera, boolean safeMode) 讀取配置設置相機的對焦模式、閃光燈模式等等
3. getPreviewSizeOnScreen()
4. getCameraResolution()
5. getScreenResolution()
6. getCWNeededRotation()
7. getTorchState(Camera camera)
8. setTorch(Camera camera, boolean newSetting)

*第二個方法setDesiredCameraParameters(...)擴展*
1. 可以在這個方法里加 CameraConfigurationUtils.setZoom(parameters, 2.0); 直接固定焦距

2. 可以在setDesiredCameraParameters(Camera camera, boolean safeMode) 方法最後加上:
  camera.setDisplayOrientation(90); 設置相機預覽爲豎屏

3. 修改爲豎屏後,由於像素點沒有對調會造成扭曲變形,在 initFromCameraParameters(Camera camera) 方法中:

 在Log.d(TAG, "Screen resolution: " + screenResolution);後加上如下的代碼:

/** 因爲換成了豎屏顯示,所以不替換屏幕寬高得出的預覽圖是變形的 */
Point screenResolutionForCamera = new Point();
screenResolutionForCamera.x = screenResolution.x;
screenResolutionForCamera.y = screenResolution.y;
// preview size is always something like 480*320, other 320*480
if (screenResolution.x < screenResolution.y) {
    screenResolutionForCamera.x = screenResolution.y;
    screenResolutionForCamera.y = screenResolution.x;
}

 最後,將screenResolution替換爲screenResolutionForCamera:

cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera);


  • CameraConfigurationUtils 主要爲CameraConfigurationManager服務的工具類

1.findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) 獲取最佳的相機預覽分辨率

  • CameraManager 攝像頭管理類(打開,關閉)

camera/camera.open包的核心類:

  1. 閃光燈開關,CameraManager.setTorch(true),方法父類是CameraConfigurationManager ,閃光燈開啓同時啓動自動對焦
  2. 打開攝像頭驅動 CameraManager.openDriver(SurfaceHolder)
  3. 設置掃碼框顯示位置 getFramingRectInPreview()
  4. 設置掃碼框矩形的大小(根據屏幕分辨率) getFramingRect()
  5. 設置掃碼框矩形的大小(自定義 setManualFramingRect(int width, int height))
  • FrontLightMode 閃光燈枚舉(開,關,自動)

  • PreviewCallback 當預覽界面出來的時候PreviewCallback.onPreviewFrame()向DecodeHandler 發送一個decode消息,DecodeHandler收到後執行decode方法解碼


com.google.zxing.client.android.camera.open 包

  • CameraFacing 打開前置或後置攝像頭 枚舉(BACK,FRONT)

  • OpenCamera bean類(獲取攝像頭部分參數index,camera,facing,orientation )

  • OpenCameraInterface 打開攝像頭的接口類

這個類被CameraManager 的 OpenDirver() 調用:
OpenCamera theCamera = OpenCameraInterface.open(OpenCameraInterface.NO_REQUESTED_CAMERA);


com.google.zxing.client.android.clipboard 包

  • ClipboardInterface 用於調用Android系統自帶的ClipboardManager

com.google.zxing.client.android.encode

編碼功能的各個組件集合。核心類爲QRCodeEncoder,最終實施編碼的是MultiFormatWriter類

  • ContactEncoder 根據聯繫人信息實現編碼方案,如名片或mecard

  • EncodeActivity 生成二維碼,全屏顯示的類

  • Formatter 封裝了一些簡單的格式化邏輯,協助重構{ @link ContactEncoder }。

  • MECARDContactEncoder 根據MECARD格式編碼的聯繫人信息。

  • QRCodeEncoder 這個類負責在條形碼編碼時,解碼用戶的請求和提取所有數據

重要方法:
encodeASBitmap() 生成二維碼

  • VCardContactEncoder 根據名片格式編碼的聯繫信息。

  • VCardFieldFormatter 名片範圍格式化邏輯

  • VCardTelDisplayFormatter 名片電話展示格式化邏輯


com.google.zxing.client.android.history 包

  • DBHelper 創建數據庫,更新數據庫

  • HistoryActivity “歷史記錄” 頁面,以及邏輯實現

  • HistoryItem 單條”歷史記錄” 要顯示的內容 bean類

  • HistoryItemAdapter 歷史記錄 顯示數據用到的適配器

  • HistoryManager “歷史記錄” 數據庫數據操作 (history包核心類)

  1. 添加”歷史記錄”
  2. 保存”歷史記錄”到本地
  3. 刪除所有”歷史記錄” 方法
  4. 刪除某一條”歷史記錄” 方法
  5. CaptureActivity 初始化 HistoryManager 時要刪除的 history ID ,trimHistory()方法
  6. 查詢 某一條 “歷史記錄”
  7. 查詢 所有 “歷史記錄 “

com.google.zxing.client.android.result 包

條碼掃描的結果被分爲不同的類型,所有的類型都定義在com.google.zxing.client.result.ParsedResultType中,對於不同的類型都有對應的處理方法:xxxResultHandler,所有的ResultHandler都包含在此包中。不同的xxxResultHandler還提供了掃描結果頁面要展示幾個button,每個button的文本以及需要綁定的事件等等。

  • AddressBookResultHandler 處理地址簿條目

  • CalendarResultHandler 處理日曆條目 QR碼的編碼

  • EmailAddressResultHandler 處理電子郵件地址

  • GeoResultHandler 處理地理座標(地理編碼:url)

  • ProductResultHandler 處理不是書的產品

  • ResultButtonListener 處理條形碼解碼的結果在Android平臺的背景下,通過intent打開GMail等其他Activity,地圖等

  • ResultHandler 針對android的條形碼的基類處理程序。這允許應用程序使用多態的方式

建議適當的行動爲每個數據類型。
這個類還包含一些實用方法採取共同行動就像打開一個URL。
他們可以很容易地進入一個輔助對象,但它不能是靜態的,因爲Activity實例需要啓動一個意圖。

  • ResultHandleFactory (Result包的核心類)

基於條碼內容的類型,生產針對android的處理程序解析掃描二維碼結果,返回對應類型的xxxHandler

這個類的makeResultHandler會調用parseResult方法,parseResult會
調用core類的核心方法,parseResult這個方法是用來解析掃描二維碼得到的結果是屬於那 種類型的數據,調用後返回ParsedResult類,
makeResultHandler方法就用到了getType()來判斷掃描的結果是那一種類型的數據, 類型數據解析完成之後又回到CaptureActivity的handleDecode方法完成對數據的處理。

調用:
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult); ZXing在CaptureActivity的handleDecode(..)

  • SMSResultHandle 處理短信地址,提供一個選擇的組合一個新的SMS或MMS消息。

  • TelResultHandler 提供了電話號碼的相關行爲。

  • TextResultHandler 這個類處理TextParsedResult以及未知格式。這是回退處理程序。

  • URIResultHandler 提供了URLS的相關行爲

  • WifiResultHandler 處理wifi訪問信息


com.google.zxing.client.android.result.supplement 包

對已經掃描並解碼的結果做額外處理的工具集

  • BookResultInfoRetriever 網頁搜索圖書

  • ProductResultInfoRetriever 從谷歌產品搜索檢索產品信息

  • TitleRetriever 檢索一個web頁面的標題作爲補充信息。

  • URIResultInfoRetriever 網頁跳轉,重定向用的

  • SupplementalInfoRetriever 這個包中爲其他類的父類


com.google.zxing.client.android.share 包

分享二維碼功能,亦是編碼功能的入口所在

  • AppInfo 獲取安裝在設備上app相關信息的bean類

  • AppPickerActivity 獲取安裝在設備上app相關信息的類

  • BookmarkAdapter 獲取瀏覽器書籤的適配器

  • BookmarkPickerActivity 獲取瀏覽器書籤 方法類

  • LoadPackagesAsyncTask: 異步加載在設備上安裝包的列表

  • ShareActivity 分享功能 界面類


com.google.zxing.client.android.wifi 包

是WifiResultHandler的輔助類集合。如果掃描到的二維碼是對wifi信息的編碼,那麼最終掃描結果頁會展示一個“連接到網絡”的按鈕,點擊此按鈕就會自動嘗試連接。該包中所包含的類則是鏈接網絡所需的工具類。

  • NetworkType wifi網絡類型類型枚舉(WEP,WPA,NO_PASSWORD)

  • WifiConfigManager

幾個方法:
1. changeNetworkCommon 用來處理沒有密碼的 wifi連接
2. changeNetworkWEP 用來處理WEP的 wifi連接
3. changeNetworkWPA 用來處理WPA的 wifi連接
4. theWifiResult.getNetworkEncryption(); 得到wifi的類型


判斷wifi連接狀態,解析得到相應的wifi類型,然後連接

  相關類:
  1.WifiParsedResult  解析wifi類型的掃描結果
  2.WifiResultHandler  用來存儲解析後的結果

  調用:

      WifiParsedResult wifiResult = (WifiParsedResult) getResult();

      WifiManager wifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE);
     ...

      new WifiConfigManager(wifiManager).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, wifiResult);

掃碼流程:

  1. 配置Camera並啓動Camera

  2. 構建preview與掃描窗口

    • 掃描窗口是在CaptureActivityHandler.restartPreviewAndDecode中,通過調用activity.drawViewfinder()來實現的。
    • 這裏有個畫掃描窗口的類叫ViewfinderView,該類也是想要改變掃描窗口風格所必須重構的一個類
  3. 捕捉畫面並解碼

    • Camera.PreviewCallback監聽preView界面是否已經顯示
    • PreviewCallback.onPreviewFrame做的事便是當preview界面展示出來的時候向DecodeHandler發送一個decode消息
    • DecodeHandler收到該消息後會執行decode方法來解碼。
    • Camera.setOneShotPreviewCallback() 檢測並觸發捕獲畫面動作的,該函數被調用後,如果預覽界面已經打開,就會將包含當前preview frame的byte數組傳給回調函數,此時再向DecodeHandler發送decode消息。
  4. 將解碼結果交給不同ResultHandler去處理

    • DecodeHandler.decode完成解碼後會向CaptureActivityHandler發消息。如果編碼成功則調用CaptureActivity.handleDecode方法對掃描到的結果進行分類處理
    • 獲取ResultHandle,
// 解析rawResult,根據不同類型result生成對應的ResultHandler
ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(this, rawResult);
  • 調用handleDecodeInternally和handleDecodeExternally對ResultHandler進行處理

總結

這篇文章僅僅是簡閱,可能存在許多不足地方,也研究的不夠深入(如.ZXingTestActivity 一邊測試,一邊研究沒做0.0 …),如果有錯誤的地方歡迎評論指出,一起共同進步…!

精簡版的ZXing網上有很多,這裏就不提供了,後續有時間自己再封裝一個適合自己項目吧…0.0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章