Android 基於zxing的二維碼掃描功能的簡單實現及優化
由於專案中需要接入一下簡單的二維碼掃描功能,最終使用 zxing 來實現,把官方例子中的部分程式碼摘除出來做了簡單的封裝,並進行了一些優化。這裡簡單做一個記錄。
掃描二維碼
Android 中關於二維碼掃描的庫有很多,但是歸根到底無外乎下面這幾種實現方案:
其中基於以上兩者實現的比較知名的庫有:
後面這兩個開源庫做的都挺好,可定製化也挺高。不過什麼事情都要根據需求來定,就目前的需求而言用不到這麼複雜的功能,所以就自己來對官方的專案做一些改造。
整合 zxing
因為之前做二維碼掃描都是直接整合別人做好的開源方案,也沒有看過官方的專案,所以第一眼看到 zxing 官方的專案是懵逼的,不知道從哪下手。不過官方很人性化的寫了wiki——Getting Started Developing,仔細閱讀以下也挺簡單,在 Android 中使用主要有以下兩步:
- 將需要的東西(例如 core)編譯成 jar 包或者直接從 maven 中下載
- 編譯 android 這個模組
不過官方文件中使用的是 mvn 命令,由於沒有使用過 mvn,所以也不用按照官方的文件來做了,不過步驟大同小異。
- 方法一
首先 clone 下需要的模組:
然後將 core 編譯成 jar 包,將 android 作為工程或者module匯入到 Android stuido 中,然後引入 jar 包就可以了。
- 方法二
這裡還有一個更省力的辦法,只 clone android 模組,然後作為工程或者 modlue 匯入到 Android stuido 中,然後再 gradle 中新增 zxing 的依賴就行了
compile group: ‘com.google.zxing’, name: ‘core’, version: ‘3.3.2’
這個執行會提示缺少 CameraConfigurationUtils
類,這個類在 android-core 這個模組中,我的做法是直接把這個類拷貝到工程中。
然後執行專案即可,執行成功以後是一個 Android 二維碼掃描器,apk 下載。
優化
官方的 demo 中功能挺多,開啟http、分享、生成二維碼等等。不過專案中用不了這麼多功能。梳理一下官方的程式碼:
- CaptureActivity 掃描二維碼的 activity;
- ViewfinderView 掃描框 view;
- CameraManager 相機管理;
- OpenCameraInterface 開啟相機的具體操作類;
- CaptureActivityHandler 是 CaptureActivity 類中使用的 handler,主要通過他來完成訊息傳遞;
- DecodeThread 圖片解碼執行緒;
其他的因為沒有使用到暫時沒有去管。然後根據需要把一些不必要的程式碼和邏輯刪除剩下的就是一些優化工作。
在使用中主要對他做了兩個地方的優化:
- 增加了許可權檢查
- 把相機的關閉和開啟放在了子執行緒中
把相機的關閉和開啟放在子執行緒中
因為相機的開啟和關閉是耗時操作,會造成主執行緒阻塞,然後開啟頁面卡頓,參考支付寶和微信在開啟的時候有一個短暫的載入框,所以這裡把相機的開啟關閉放在了子執行緒中來做。主要程式碼有下面這這些:
開啟相機
public final class OpenCameraInterface extends Thread {
private static final String TAG = OpenCameraInterface.class.getName();
private OpenCamera openCamera;
private CaptureActivityHandler handler;
// handler 用來和主執行緒通訊
public void setHandler(CaptureActivityHandler handler) {
this.handler = handler;
}
// 由於 camera 物件不能通過 handler 來傳遞,所以放在這裡通過 get 的方式來獲取。
public OpenCamera getOpenCamera() {
return openCamera;
}
private OpenCamera open() {
int numCameras = Camera.getNumberOfCameras();
if (numCameras == 0) {
Log.w(TAG, "No cameras!");
return null;
}
int cameraId = 0;
while (cameraId < numCameras) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
if (CameraFacing.values()[cameraInfo.facing] == CameraFacing.BACK) {
break;
}
cameraId++;
}
if (cameraId == numCameras) {
Log.i(TAG, "No camera facing " + CameraFacing.BACK + "; returning camera #0");
cameraId = 0;
}
Log.i(TAG, "Opening camera #" + cameraId);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
Camera camera = Camera.open(cameraId);
if (camera == null) {
return null;
}
return new OpenCamera(cameraId,
camera,
CameraFacing.values()[cameraInfo.facing],
cameraInfo.orientation);
}
@Override
public void run() {
try {
openCamera = open();
} catch (Exception e) {
openCamera = null;
}
handler.sendEmptyMessage(R.id.open_camera_complete);
}
}
在 CameraManager 中增加一個方法。
public void openCamera(CaptureActivityHandler handler) {
// 這裡把開啟相機放在子執行緒中
if (camera != null) {
return;
}
threadOpen = new OpenCameraInterface();
threadOpen.setHandler(handler);
threadOpen.start();
}
在 CaptureActivity 中增加一個方法在接到子執行緒發來的訊息後再初始化預覽等。這裡通過標誌位來判斷是直接進行初始化還是等待 SurfaceView 建立完成以後再進行初始化。
public void openCameraComplete() {
// 如果已有 SurfaceView 就可以繼續建立 否則就等待SurfaceView 建立完以後自動執行
isCameraComplete = true;
if (hasSurface) {
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
initCamera(surfaceHolder);
}
}
關閉相機
在關閉相機的時候需要增加必要的執行緒同步,否則可能造成相機未被關閉。
public synchronized void closeDriver() {
// 結束也是耗時操作 方在子執行緒中
new Thread(new Runnable() {
@Override
public void run() {
try {
// 為了防止在快速切換時出現問題,這裡等待開啟操作完成後再結束
threadOpen.join();
if (camera == null) {
camera = threadOpen.getOpenCamera();
}
} catch (InterruptedException e) {
Log.e(TAG, e.toString());
}
camera.getCamera().release();
camera = null;
}
}).start();
}
然後就是許可權檢查這一塊了,沒什麼好說的在開啟相機之前做必要的許可權檢查就行了。需要注意的是根據官方文件,在 activity onPause 的時候需要關閉相機,然後在 onResume() 中重新開啟。而申請的彈出框會導致 activity 的 onResume 重複呼叫,針對這種情況需要做好處理。
以上就是關於 zxing 的簡單整合的所有內容,原始碼已經放在了 GitHub 上,僅供參考。commonTest-zxing
參考
版權宣告:本文為博主原創文章,轉載請宣告出處,請尊重別人的勞動成果,謝謝!
相關文章
- 基於ZXing Android實現生成二維碼圖片和相機掃描二維碼圖片即時解碼的功能Android
- zxing第三方框架實現二維碼掃描以及生成框架
- 基於ZXingAndroid實現生成二維碼圖片和相機掃描二維碼圖片即時解碼的功能Android
- 簡單易用的二維碼掃描工具:QR Capture for MacAPTMac
- Android | 教你如何開發掃二維碼功能Android
- Android----二維碼掃描、生成、相簿識別(16號)Android
- iOS 掃描二維碼/條形碼iOS
- 掃描二維碼登入思路
- 基於python編寫一個簡單的多執行緒埠掃描指令碼Python執行緒指令碼
- 使用HTML5實現掃描PC二維碼且觸發WAP端上傳資源功能HTML
- XQRCode 一個非常方便實用的二維碼掃描、解析、生成庫
- 一對一直播系統開發如何在頁面內實現掃描二維碼功能
- 基於Netty的Android系統IM簡單實現原理NettyAndroid
- 聊天室原始碼開發,如何簡單的實現掃碼登入功能?原始碼
- 基於XDanmuku的Android效能優化實戰Android優化
- 基於ARouter的Android元件化實現Android元件化
- 實現一個簡單版本的vue及原始碼解析(二)Vue原始碼
- Android應用加固的簡單實現方案(二)Android
- 基於CC的Android MVVM 元件化實現AndroidMVVM元件化
- 微信小程式掃描普通二維碼開啟小程式的方法微信小程式
- 簡單的Java二維碼應用Java
- 全棧工程師之路-React Native之掃描二維碼全棧工程師React Native
- 對一條基於分割槽的簡單SQL的優化SQL優化
- android 簡單實現指紋識別功能Android
- 【MISC】一道假的二維碼題目學習zxing庫[python解讀二維碼]Python
- 簡單介紹基於Redis的List實現特價商品列表功能Redis
- 基於vue實現一個簡單的MVVM框架(原始碼分析)VueMVVM框架原始碼
- 超簡單的,掃描PDF轉換成Word的方法
- 條碼列印軟體是否可以製作只能掃描一次的二維碼?
- 一種基於Android、iOS系統的手機掃描車牌識別技術,本地掃描識別車牌AndroidiOS
- mybatis-plus原始碼解析(二)----基於@MapperScan註解掃描載入MapperMyBatis原始碼APP
- Android中SharePreferences的簡單實現Android
- PHP掃描圖片轉點陣 二維碼轉點陣PHP
- Swift4如何掃描二維碼瞭解一下Swift
- 基於Socket.IO實現Android聊天功能Android
- 簡單介紹recorder.js 基於Html5錄音功能的實現JSHTML
- Win10怎麼使用掃描器功能 win10使用掃描功能的方法Win10
- 使用 ABAP 程式碼製作手機能夠掃描的二維碼(QRCode)試讀版