基本使用
添加依賴
compile 'com.journeyapps:zxing-android-embedded:3.5.0'
掃描二維碼:
new IntentIntegrator(this).initiateScan();
僅僅添加這一行就可以開啟掃描二維碼了,非常簡單狼忱。
看看內(nèi)部做了什么操作把膨疏,initiateScan()這個方法就一行代碼,咱瞅瞅
startActivityForResult(createScanIntent(), REQUEST_CODE);
這個就很熟悉了啊钻弄,傳入Intent和requestcode佃却,開啟一個可以但會結(jié)果的界面。在瞅瞅createScanIntent這個方法斧蜕。
public Intent createScanIntent() {
Intent intentScan = new Intent(activity, getCaptureActivity());
intentScan.setAction(Intents.Scan.ACTION);
// check which types of codes to scan for
//檢查要掃碼的二維碼類型
if (desiredBarcodeFormats != null) {
// set the desired barcode types
StringBuilder joinedByComma = new StringBuilder();
for (String format : desiredBarcodeFormats) {
if (joinedByComma.length() > 0) {
joinedByComma.append(',');
}
joinedByComma.append(format);
}
intentScan.putExtra(Intents.Scan.FORMATS, joinedByComma.toString());
}
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
attachMoreExtras(intentScan);
return intentScan;
}
這個Intent需要傳入一個activity双霍,getCaptureActivity(),如果你設(shè)置了activity就是用你傳遞進(jìn)來的activity批销,如果你沒有設(shè)置就使用默認(rèn)的activity洒闸,這個activity是CaptureActivity.class,那么在哪里設(shè)置自己的Activity呢均芽。
new IntentIntegrator(this).setCaptureActivity(ToolbarCaptureActivity.class).initiateScan();
在開啟掃描的時候設(shè)置咱自己的Activity丘逸,就可以修改咱們自己想要的界面了。
接著上面的intent說掀宋,desiredBarcodeFormats直接檢查支持二維碼支的格式有那些深纲。
public static final Collection<String> PRODUCT_CODE_TYPES = list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "RSS_14");
public static final Collection<String> ONE_D_CODE_TYPES =
list("UPC_A", "UPC_E", "EAN_8", "EAN_13", "CODE_39", "CODE_93", "CODE_128",
"ITF", "RSS_14", "RSS_EXPANDED");
public static final Collection<String> QR_CODE_TYPES = Collections.singleton("QR_CODE");
public static final Collection<String> DATA_MATRIX_TYPES = Collections.singleton("DATA_MATRIX");
把設(shè)置的參數(shù)存入的Intent中。見方法
**private void attachMoreExtras(Intent intent) **
這時候就已經(jīng)開啟了二維碼掃描界面了劲妙。
看看可以設(shè)置那些參數(shù)
IntentIntegrator integrator = new IntentIntegrator(this);
integrator.setCaptureActivity(AnyOrientationCaptureActivity.class);
integrator.setDesiredBarcodeFormats(IntentIntegrator.ONE_D_CODE_TYPES);
integrator.setPrompt("Scan something");
integrator.setOrientationLocked(false);
integrator.setBeepEnabled(false);
integrator.setBarcodeImageEnabled(true)
integrator.initiateScan();
- setCaptureActivity
設(shè)置自定義的Activity - setDesiredBarcodeFormats
設(shè)置要掃描的所需條形碼格式湃鹊。 - setPrompt
設(shè)置掃面界面的提示語 - setOrientationLocked
- setBeepEnabled
設(shè)置掃描完成聲音提示 false 表示沒有提示音 - setBarcodeImageEnabled
表示二維碼圖片是否保存,true表示保存镣奋。 - setCameraId
設(shè)置前后攝像頭滴 - setOrientationLocked()
是否旋轉(zhuǎn)鎖定
如果你的androidManifest文件掃描界面的屏幕旋轉(zhuǎn)方向改成
<activity
android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="fullSensor"
tools:replace="screenOrientation" />
然后
integrator.setOrientationLocked(false);
結(jié)果就是:調(diào)整手機(jī)方向時币呵,掃描布局也會重新布置
獲取返回的結(jié)果
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if(result != null) {
if(result.getContents() == null) {
Log.d("MainActivity", "Cancelled scan");
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Log.d("MainActivity", "Scanned");
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
} else {
// This is important, otherwise the result will not be passed to the fragment
super.onActivityResult(requestCode, resultCode, data);
}
來看看這個是怎么解析的:
IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
上代碼:
public static IntentResult parseActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
String contents = intent.getStringExtra(Intents.Scan.RESULT);
String formatName = intent.getStringExtra(Intents.Scan.RESULT_FORMAT);
byte[] rawBytes = intent.getByteArrayExtra(Intents.Scan.RESULT_BYTES);
int intentOrientation = intent.getIntExtra(Intents.Scan.RESULT_ORIENTATION, Integer.MIN_VALUE);
Integer orientation = intentOrientation == Integer.MIN_VALUE ? null : intentOrientation;
String errorCorrectionLevel = intent.getStringExtra(Intents.Scan.RESULT_ERROR_CORRECTION_LEVEL);
String barcodeImagePath = intent.getStringExtra(Intents.Scan.RESULT_BARCODE_IMAGE_PATH);
return new IntentResult(contents,
formatName,
rawBytes,
orientation,
errorCorrectionLevel,
barcodeImagePath);
}
return new IntentResult();
}
return null;
}
其實就是獲取Intent中的信息,二維碼的信息結(jié)果就在Intent中侨颈,當(dāng)然IntentResult中有許多信息余赢。
public final class IntentResult {
private final String contents;
private final String formatName;
private final byte[] rawBytes;
private final Integer orientation;
private final String errorCorrectionLevel;
private final String barcodeImagePath;
......
}
- contents
二維碼掃描的信息 - formatName
掃描類型 - rawBytes
條形碼內(nèi)容的原始字節(jié) - orientation
圖片的旋轉(zhuǎn)度數(shù) - errorCorrectionLevel
糾錯級別 - barcodeImagePath
二維碼圖片路徑(我的是在緩存中)
/data/user/0/cn.projects.com.projectsdemo/cache/barcodeimage371491556.jpg
CaptureActivity
這個類加載自定義布局 :
xml文件
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!--
This Activity is typically full-screen. Therefore we can safely use centerCrop scaling with
a SurfaceView, without fear of weird artifacts. -->
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_barcode_scanner"
app:zxing_preview_scaling_strategy="centerCrop"
app:zxing_use_texture_view="false"/>
</merge>
xml文件使用merge標(biāo)簽來減少布局的層次結(jié)果,不明白的自行度娘哈垢。
這里最重要的就是這個DecoratedBarcodeView自定義控件了妻柒,封裝BarcodeView,ViewfinderView和狀態(tài)文本耘分。創(chuàng)建CaptureManger 管理CaptureActivity條形碼掃描举塔,從Intent初始化(通過IntentIntegrator)并開始解碼capture.decode();(并不是真正意義上的解碼)真正解碼的事BarcodeView绑警。
- BarcodeView
繼承CameraPreview繼承ViewGroup,用于掃描條形碼的視圖 - ViewfinderView
此view覆蓋在相機(jī)預(yù)覽的頂部央渣。 它添加取景器矩形和部分透明度以外待秃,以及激光掃描儀的動畫和結(jié)果點(一條橫線的那個玩意) - 狀態(tài)文本
掃描時的提示信息
如果想要自定義界面,有兩種方法:
- 創(chuàng)建一個類痹屹,復(fù)制CaptureActivity類的內(nèi)容章郁,修改initializeContent方法中的布局。
- 繼承CaptureActivity類重寫initializeContent方法志衍。
例如:
public class SmallCaptureActivity extends CaptureActivity {
@Override
protected DecoratedBarcodeView initializeContent() {
setContentView(R.layout.capture_small);
return (DecoratedBarcodeView)findViewById(R.id.zxing_barcode_scanner);
}
}
xml文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_barcode_scanner"
app:zxing_preview_scaling_strategy="centerCrop"
app:zxing_scanner_layout = "@layout/custom_layout_zxing"
app:zxing_framing_rect_height = "200dp"
app:zxing_framing_rect_width = "200dp"
app:zxing_use_texture_view="false"/>
</LinearLayout>
DecoratedBarcodeView
自定義的Fragment暖庄,封裝BarcodeView,ViewfinderView和狀態(tài)文本楼肪。要自定義UI培廓,請直接使用BarcodeView和ViewfinderView。
- initialize()
從xml中加載自定義屬性春叫,定義BarcodeView肩钠,ViewfinderView和statusView。
private void initialize(AttributeSet attrs) {
// Get attributes set on view
TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.zxing_view);
int scannerLayout = attributes.getResourceId(
R.styleable.zxing_view_zxing_scanner_layout, R.layout.zxing_barcode_scanner);
attributes.recycle();
inflate(getContext(), scannerLayout, this);
barcodeView = (BarcodeView) findViewById(R.id.zxing_barcode_surface);
if (barcodeView == null) {
throw new IllegalArgumentException(
"There is no a com.journeyapps.barcodescanner.BarcodeView on provided layout " +
"with the id \"zxing_barcode_surface\".");
}
// Pass on any preview-related attributes
barcodeView.initializeAttributes(attrs);
viewFinder = (ViewfinderView) findViewById(R.id.zxing_viewfinder_view);
if (viewFinder == null) {
throw new IllegalArgumentException(
"There is no a com.journeyapps.barcodescanner.ViewfinderView on provided layout " +
"with the id \"zxing_viewfinder_view\".");
}
viewFinder.setCameraPreview(barcodeView);
// statusView is optional
statusView = (TextView) findViewById(R.id.zxing_status_view);
}
如果想要自定義BarcodeView暂殖,ViewfinderView价匠。在自定義的
xml文件中
com.journeyapps.barcodescanner.DecoratedBarcodeView
加入一行
app:zxing_scanner_layout = "@layout/custom_layout_zxing"
來添加你自己的layout布局。
例如:
我自己定義的布局custom_layout_zxing
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.journeyapps.barcodescanner.BarcodeView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_barcode_surface"/>
<cn.projects.com.projectsdemo.zxing.CustomViewFindView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/zxing_viewfinder_view"/>
<TextView android:id="@+id/zxing_status_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="120dp"
android:background="@color/zxing_transparent"
android:text="@string/zxing_msg_default_status"
android:textColor="@color/zxing_status_text"/>
</FrameLayout>
這里我自己定義了ViewFindView呛每,簡單的繪制掃描先了四個角踩窖。
initializeFromIntent(Intent intent)
從Intent去除消息,初始化攝像機(jī)ID晨横,解碼格式和是否反轉(zhuǎn)洋腮。onKeyDown
重寫onKeyDown主要兩個功能,1.按音量+開啟閃光燈手形。2.按音量-關(guān)閉閃光燈啥供。decodeSingle(BarcodeCallback callback)
解碼單個的(就是一次)條碼,然后停止解碼库糠』锖回調(diào)在住線程decodeContinuous(BarcodeCallback callback)
連續(xù)解碼條形碼。 相同的條形碼可以每秒返回多次曼玩×壑瑁回調(diào)在住線程pause
停止預(yù)覽和解碼pauseAndWait
暫停掃描和預(yù)覽; 等待相機(jī)關(guān)閉窒百。會阻塞住線程WrappedCallback
private class WrappedCallback implements BarcodeCallback {
private BarcodeCallback delegate;
public WrappedCallback(BarcodeCallback delegate) {
this.delegate = delegate;
}
@Override
public void barcodeResult(BarcodeResult result) {
delegate.barcodeResult(result);
}
@Override
public void possibleResultPoints(List<ResultPoint> resultPoints) {
for (ResultPoint point : resultPoints) {
viewFinder.addPossibleResultPoint(point);
}
delegate.possibleResultPoints(resultPoints);
}
WrappedCallback實現(xiàn)了BarcodeCallback黍判,對解碼的結(jié)果進(jìn)行包裝,實際上把結(jié)果傳遞到了BarcodeView的resultCallback中篙梢。這里只是對
possibleResultPoints進(jìn)行處理顷帖,這個東西到底是啥呢,官方解釋:
檢測到結(jié)果點。 無論掃描是否成功贬墩,都可以進(jìn)行調(diào)用榴嗅。 這對于在掃描時向用戶給出一些反饋主要是有用的。 不要依賴于在解碼周期的任何特定點被調(diào)用陶舞。 @param resultPoints可能會識別條形碼
這是啥意思呢嗽测,看看誰用到他了吧!
for (ResultPoint point : resultPoints) {
viewFinder.addPossibleResultPoint(point);
}
除了viewFinder沒人使用它肿孵,看看viewFinder是怎么用的吧
if (!lastPossibleResultPoints.isEmpty()) {
paint.setAlpha(CURRENT_POINT_OPACITY / 2);
paint.setColor(resultPointColor);
float radius = POINT_SIZE / 2.0f;
for (final ResultPoint point : lastPossibleResultPoints) {
canvas.drawCircle(
frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
radius, paint
);
}
lastPossibleResultPoints.clear();
哦哦哦唠粥,原來激光線旁邊的小點點就是可能的結(jié)果點啊停做!原來乳此晤愧!
CaptureManager
管理CaptureActivity條形碼掃描。 這是針對專門用于捕獲單個條形碼并返回結(jié)果通過setResult()蛉腌。以下由類程管理:
- 方向鎖
- 靜止計時器
- BeepManager
- 從Intent初始化(通過IntentIntegrator)
- 設(shè)置結(jié)果并完成掃描條形碼的Activity
- 顯示相機(jī)錯誤
initializeFromIntent(Intent intent, Bundle savedInstanceState)
根據(jù)Intent初始化參數(shù)
這里只主要是調(diào)用DecoratedBarcodeView的decodeSingle開始解碼官份,
/**
* Start decoding.
*/
public void decode() {
barcodeView.decodeSingle(callback);
}
這個callback就是解碼的結(jié)果的回調(diào)。
private BarcodeCallback callback = new BarcodeCallback() {
@Override
public void barcodeResult(final BarcodeResult result) {
barcodeView.pause();
beepManager.playBeepSoundAndVibrate();
handler.post(new Runnable() {
@Override
public void run() {
returnResult(result);
}
});
}
@Override
public void possibleResultPoints(List<ResultPoint> resultPoints) {
}
};
暫停預(yù)覽并播放聲音烙丛。
handler發(fā)送結(jié)果到 returnResult(result);
protected void returnResult(BarcodeResult rawResult) {
Intent intent = resultIntent(rawResult, getBarcodeImagePath(rawResult));
activity.setResult(Activity.RESULT_OK, intent);
closeAndFinish();
}
把結(jié)果返回到Activity并關(guān)閉舅巷,這個Activity,就是CaptureActivity或者自定義的Activity河咽,就可以拿到結(jié)果了悄谐。
- InactivityTimer是對電池的狀態(tài)進(jìn)行監(jiān)聽,
final boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0;
這里應(yīng)該是使用電池本身的電量(沒有USB库北,或者充電)5分鐘就關(guān)閉了Activity爬舰。
BarcodeView
BarcodeView是用于掃描條形碼的視圖。
使用decodeSingle()或decodeContinuous()開始解碼寒瓦。
停止使用stopDecoding()解碼情屹。
調(diào)用兩個方法來管理狀態(tài):
- resume() 初始化相機(jī)并開始預(yù)覽。 從Activity的onResume()調(diào)用杂腰。
- pause() 停止預(yù)覽并釋放任何資源垃你。 從Activity的onPause()調(diào)用。
對外開放的開始解碼代碼
public void decodeSingle(BarcodeCallback callback) {
this.decodeMode = DecodeMode.SINGLE;
this.callback = callback;
startDecoderThread();
}
開啟連續(xù)解碼喂很,相同的條形碼可以每秒返回多次
public void decodeContinuous(BarcodeCallback callback) {
this.decodeMode = DecodeMode.CONTINUOUS;
this.callback = callback;
startDecoderThread();
}
開啟解碼
private void startDecoderThread() {
stopDecoderThread(); // To be safe
if (decodeMode != DecodeMode.NONE && isPreviewActive()) {
//啟動線程條件:
// 1.請求解碼
// 2.預(yù)覽處于活動狀態(tài)
decoderThread = new DecoderThread(getCameraInstance(), createDecoder(), resultHandler);
decoderThread.setCropRect(getPreviewFramingRect());
decoderThread.start();
}
}
保證線程安全惜颇,設(shè)置矩形區(qū)域,然后開啟解碼少辣。
這里的handler(resultHandler)就是返回解碼結(jié)果的回調(diào)凌摄。這個回調(diào)是在DecoderThread類發(fā)出的.
private final Handler.Callback resultCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
if (message.what == R.id.zxing_decode_succeeded) {
BarcodeResult result = (BarcodeResult) message.obj;
if (result != null) {
if (callback != null && decodeMode != DecodeMode.NONE) {
callback.barcodeResult(result);
if (decodeMode == DecodeMode.SINGLE) {
stopDecoding();
}
}
}
return true;
} else if (message.what == R.id.zxing_decode_failed) {
// Failed. Next preview is automatically tried.
//失敗 下一個預(yù)覽會自動嘗試。
return true;
} else if (message.what == R.id.zxing_possible_result_points) {
//noinspection unchecked
List<ResultPoint> resultPoints = (List<ResultPoint>) message.obj;
if (callback != null && decodeMode != DecodeMode.NONE) {
callback.possibleResultPoints(resultPoints);
}
return true;
}
return false;
}
};
callback.barcodeResult(result);這一行代碼中漓帅,Callback是CaptureManager類中callback锨亏。結(jié)果是一層一層向上傳遞的痴怨。
跟蹤這個resultHandler。進(jìn)入DecoderThread類器予。
DecoderThread
構(gòu)造
public DecoderThread(CameraInstance cameraInstance, Decoder decoder, Handler resultHandler) {
Util.validateMainThread();
this.cameraInstance = cameraInstance;
this.decoder = decoder;
this.resultHandler = resultHandler;
}
直接解碼唄
/**
* Start decoding.
*
* This must be called from the UI thread.
*/
public void start() {
Util.validateMainThread();
thread = new HandlerThread(TAG);
thread.start();
handler = new Handler(thread.getLooper(), callback);
running = true;
requestNextPreview();
}
這個callback返回的是圖像信息浪藻,然后根據(jù)圖像信息進(jìn)行解碼
private final Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
if (message.what == R.id.zxing_decode) {
decode((SourceData) message.obj);
} else if(message.what == R.id.zxing_preview_failed) {
// Error already logged. Try again.
requestNextPreview();
}
return true;
}
};
最關(guān)鍵的是
requestNextPreview();
這個方法.
private void requestNextPreview() {
if (cameraInstance.isOpen()) {
cameraInstance.requestPreview(previewCallback);
}
}
這里有個CameraInstance類,這個類使用后臺線程管理Camera實例乾翔,必須調(diào)用在主線程爱葵。
public void requestPreview(final PreviewCallback callback) {
validateOpen();
cameraThread.enqueue(new Runnable() {
@Override
public void run() {
cameraManager.requestPreviewFrame(callback);
}
});
}
這里cameraThread.enqueue()其實就是handler.post發(fā)送調(diào)用在主線程。
public void requestPreviewFrame(PreviewCallback callback) {
Camera theCamera = camera;
if (theCamera != null && previewing) {
cameraPreviewCallback.setCallback(callback);
theCamera.setOneShotPreviewCallback(cameraPreviewCallback);
}
}
單次預(yù)覽框?qū)D像返回到回調(diào)反浓。
private final class CameraPreviewCallback implements Camera.PreviewCallback {
private PreviewCallback callback;
private Size resolution;
public CameraPreviewCallback() {
}
public void setResolution(Size resolution) {
this.resolution = resolution;
}
public void setCallback(PreviewCallback callback) {
this.callback = callback;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Size cameraResolution = resolution;
PreviewCallback callback = this.callback;
if (cameraResolution != null && callback != null) {
try {
if(data == null) {
throw new NullPointerException("No preview data received");
}
int format = camera.getParameters().getPreviewFormat();
SourceData source = new SourceData(data, cameraResolution.width, cameraResolution.height, format, getCameraRotation());
callback.onPreview(source);
} catch (RuntimeException e) {
// Could be:
// java.lang.RuntimeException: getParameters failed (empty parameters)
// IllegalArgumentException: Image data does not match the resolution
Log.e(TAG, "Camera preview failed", e);
callback.onPreviewError(e);
}
} else {
Log.d(TAG, "Got preview callback, but no handler or resolution available");
if(callback != null) {
// Should generally not happen
callback.onPreviewError(new Exception("No resolution available"));
}
}
}
}
callback.onPreview(source);
圖像給回調(diào)了钧惧。
回調(diào)是在DecoderThread中實現(xiàn)的
private final PreviewCallback previewCallback = new PreviewCallback() {
@Override
public void onPreview(SourceData sourceData) {
// Only post if running, to prevent a warning like this:
// java.lang.RuntimeException: Handler (android.os.Handler) sending message to a Handler on a dead thread
// synchronize to handle cases where this is called concurrently with stop()
synchronized (LOCK) {
if (running) {
// Post to our thread.
handler.obtainMessage(R.id.zxing_decode, sourceData).sendToTarget();
}
}
}
@Override
public void onPreviewError(Exception e) {
synchronized (LOCK) {
if (running) {
// Post to our thread.
handler.obtainMessage(R.id.zxing_preview_failed).sendToTarget();
}
}
}
};
數(shù)據(jù)發(fā)送給了handler,在handler的Callback中
private final Handler.Callback callback = new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
if (message.what == R.id.zxing_decode) {
decode((SourceData) message.obj);
} else if(message.what == R.id.zxing_preview_failed) {
// Error already logged. Try again.
requestNextPreview();
}
return true;
}
};
看看decoder()方法勾习。
private void decode(SourceData sourceData) {
long start = System.currentTimeMillis();
Result rawResult = null;
sourceData.setCropRect(cropRect);
LuminanceSource source = createSource(sourceData);
if(source != null) {
rawResult = decoder.decode(source);
}
if (rawResult != null) {
// Don't log the barcode contents for security.
long end = System.currentTimeMillis();
Log.d(TAG, "Found barcode in " + (end - start) + " ms");
if (resultHandler != null) {
BarcodeResult barcodeResult = new BarcodeResult(rawResult, sourceData);
Message message = Message.obtain(resultHandler, R.id.zxing_decode_succeeded, barcodeResult);
Bundle bundle = new Bundle();
message.setData(bundle);
message.sendToTarget();
}
} else {
if (resultHandler != null) {
Message message = Message.obtain(resultHandler, R.id.zxing_decode_failed);
message.sendToTarget();
}
}
if (resultHandler != null) {
List<ResultPoint> resultPoints = decoder.getPossibleResultPoints();
Message message = Message.obtain(resultHandler, R.id.zxing_possible_result_points, resultPoints);
message.sendToTarget();
}
requestNextPreview();
}
在decoder.decode(source)這里解碼圖像浓瞪,并且把結(jié)果都分發(fā)出來,
現(xiàn)在比較清晰了巧婶,resultHandler就是結(jié)果的回調(diào)乾颁,網(wǎng)上跟蹤就可以了。
最后又開啟了下一次預(yù)覽艺栈。解碼二進(jìn)制圖像是在Decode類中英岭,可以自己去看看
ViewfinderView
此視圖覆蓋在相機(jī)預(yù)覽的頂部。 它添加取景器矩形和部分透明度以外湿右,以及激光掃描儀的動畫和結(jié)果點诅妹。
沒啥說的啊。