zxing源碼分析

基本使用

添加依賴
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):

    1. resume() 初始化相機(jī)并開始預(yù)覽。 從Activity的onResume()調(diào)用杂腰。
    1. 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é)果點诅妹。
沒啥說的啊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毅人,一起剝皮案震驚了整個濱河市吭狡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌丈莺,老刑警劉巖划煮,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缔俄,居然都是意外死亡弛秋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門俐载,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟹略,“玉大人,你說我怎么就攤上這事遏佣⊥诰妫” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵贼急,是天一觀的道長茅茂。 經(jīng)常有香客問我,道長太抓,這世上最難降的妖魔是什么空闲? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮走敌,結(jié)果婚禮上碴倾,老公的妹妹穿的比我還像新娘。我一直安慰自己掉丽,他們只是感情好跌榔,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捶障,像睡著了一般僧须。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上项炼,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天担平,我揣著相機(jī)與錄音,去河邊找鬼锭部。 笑死暂论,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拌禾。 我是一名探鬼主播取胎,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼湃窍!你這毒婦竟也來了闻蛀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤您市,失蹤者是張志新(化名)和其女友劉穎循榆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墨坚,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡秧饮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了泽篮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盗尸。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帽撑,靈堂內(nèi)的尸體忽然破棺而出泼各,到底是詐尸還是另有隱情,我是刑警寧澤亏拉,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布扣蜻,位于F島的核電站逆巍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏莽使。R本人自食惡果不足惜锐极,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芳肌。 院中可真熱鬧灵再,春花似錦、人聲如沸亿笤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽净薛。三九已至汪榔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肃拜,已是汗流浹背揍异。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留爆班,地道東北人衷掷。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像柿菩,于是被迫代替她去往敵國和親戚嗅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容