Android 連續掃描多個 QR code 的實作

使用 GitHub 上 LivotovLabs/zxscanlibv0.9.0 版,目前上面有更新的版本,不過我那時候用的時候最新的就到這版

假如直接使用這個 library ,手機在掃到 QR code 的時候會震動,然後離開掃描的相機畫面回到前一個畫面,另外,它開相機的時候會把畫面變成橫的(landscape)。所以要達到我的要求的話就需要改一下裡面的 code,這邊分享一下把這個 library 應用到可以連續掃描多個 QR code 的經驗 (使用eclipse),可以搭配該 project 的 GitHub 頁面說明一起看

目標:可以連續掃描多個 QR code,當掃到目標 QR code 的時候跳回原畫面,並使用取得的資料做下一步應用

Dependency Issue
把 project clone 下來之後,照著 GitHub 頁面上的說明,將它當作一個 library project 使用,此時假如原本的 project 有用到 android-support-v4.jar,就會產生衝突(因為此 library project 也有用),我的解決方式是把原本 project 的 android-support-v4.jar 從 libs 裡刪掉

此 library 的運作模式
在想要掃 QR code 的時候使用 ZXScanHelper.scan() 方法,此時 DecodeHandler.handleMessage() 會不斷地被呼叫,decode成功了之後會呼叫 CaptureActivity.handleDecode(),可以在這邊對 decode 之後的結果做篩選,最後可以在我們自己 override 的 onActivityResult() 裡取得解碼後的結果

解決問題:掃描時相機畫面會變成橫的
第一步:刪掉強制轉為 landscape 的 code

CaptureActivity.java
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
@Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
// 註解(或刪)掉下面這段就不會強迫在掃QR code時用landscape了

// if (android.os.Build.VERSION.SDK_INT < 8 || ZXScanHelper.isBlockCameraRotation())

// {

// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

// }


Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(ZXScanHelper.getCustomScanLayout() > 0 ? ZXScanHelper.getCustomScanLayout() : R.layout.capture);

hasSurface = false;
inactivityTimer = new InactivityTimer(this);
beepManager = new BeepManager(this);

if (ZXScanHelper.getUserCallback() != null)
{
ZXScanHelper.getUserCallback().onScannerActivityCreated(this);
}
}

第二步:設定 camera 的 orientation,不然在 CaptureActivity 為 portrait 的情況下 camera 會是 landscape

CameraManager.java - 加上 forceSetCameraOrientation()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Opens the camera driver and initializes the hardware parameters.
*
* @param holder The surface object which the camera will draw preview frames into.
* @throws IOException Indicates the camera driver failed to open.
*/
public synchronized void openDriver(SurfaceHolder holder) throws IOException
{
// ...省略

try
{
configManager.setDesiredCameraParameters(theCamera);
forceSetCameraOrientation(); // 把相機畫面的 orientation 設為跟 CaptureActivity 一樣

} catch (RuntimeException re)
{
// ...省略

}
}

小提醒:GitHub上的說明在 android:configChanges 少了 screenSize,記得加上 (target API level >= 13的話要加,所以應該幾乎都需要加吧)

AndroidManifest.xml
1
2
3
4
5
6
7
<activity android:name="com.google.zxing.client.android.CaptureActivity"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:windowSoftInputMode="stateAlwaysHidden">
</activity>

解決問題:改為可以連續掃描多個 QR code
第一步:設定 ZXUserCallback,實作 onCodeRead() 方法
如 GitHub 頁面所說,呼叫 ZXScanHelper.scan() 之前先呼叫ZXScanHelper.setUserCallback(ZXUserCallback cb),把過濾邏輯寫在 onCodeRead()

第二步:在 CaptureActivity.handleDecode() 裡增加判斷邏輯,掃到不合格的 QR code 之後要 callrestartPreviewAfterDelay(long delayMS) 重新掃描

CaptureActivity.java
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
/**
* A valid barcode has been found, so give an indication of success and show the results.
*
* @param rawResult The contents of the barcode.
* @param barcode A greyscale bitmap of the camera data which was decoded.
*/
public void handleDecode(Result rawResult, Bitmap barcode)
{
// ...省略

boolean accept = rawResult != null;

if (accept && ZXScanHelper.getUserCallback() != null)
{
accept = ZXScanHelper.getUserCallback().onCodeRead(rawResult.getText());
}

if (accept)
{
handleDecodeExternally(rawResult, barcode);
} else { // 掃到不符合條件的 QR code

// do something you want, ex: show a toast

restartPreviewAfterDelay(300L);
}
}

這樣就大功告成囉!

評論

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×