Andriod Zxing 二维码扫描 实现连续扫描

做公司项目的时候需要实现类似于超市扫描枪一样的,连续扫描。下面说说我的实现方法。
既然要修改Zxing的源码,就要找到Zxing里面的CaptureActivity这个类,这里面内容是点击扫描按钮跳转到扫描界面和一些扫描完以后获取条形码(二维码)数据的方法。大部分大同小异,我把这个类贴出来 :

public final class CaptureActivity extends Activity implements
SurfaceHolder.Callback {

private static final String TAG = CaptureActivity.class.getSimpleName();

private CameraManager cameraManager;
private CaptureActivityHandler handler;
private InactivityTimer inactivityTimer;
private BeepManager beepManager;

private SurfaceView scanPreview = null;
private RelativeLayout scanContainer;
private RelativeLayout scanCropView;
private ImageView scanLine;

private Rect mCropRect = null;

public Handler getHandler() {
    return handler;
}

public CameraManager getCameraManager() {
    return cameraManager;
}

private boolean isHasSurface = false;

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);

    Window window = getWindow();
    window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.activity_capture);

    scanPreview = (SurfaceView) findViewById(R.id.capture_preview);
    scanContainer = (RelativeLayout) findViewById(R.id.capture_container);
    scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view);
    scanLine = (ImageView) findViewById(R.id.capture_scan_line);

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

    TranslateAnimation animation = new TranslateAnimation(
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.0f,
            Animation.RELATIVE_TO_PARENT, 0.9f);
    animation.setDuration(4500);
    animation.setRepeatCount(-1);
    animation.setRepeatMode(Animation.RESTART);
    scanLine.startAnimation(animation);
}

@Override
protected void onResume() {
    super.onResume();

    // CameraManager must be initialized here, not in onCreate(). This is
    // necessary because we don't
    // want to open the camera driver and measure the screen size if we're
    // going to show the help on
    // first launch. That led to bugs where the scanning rectangle was the
    // wrong size and partially
    // off screen.
    cameraManager = new CameraManager(getApplication());

    handler = null;

    if (isHasSurface) {
        // The activity was paused but not stopped, so the surface still
        // exists. Therefore
        // surfaceCreated() won't be called, so init the camera here.
        initCamera(scanPreview.getHolder());
    } else {
        // Install the callback and wait for surfaceCreated() to init the
        // camera.
        scanPreview.getHolder().addCallback(this);
    }

    inactivityTimer.onResume();
}

@Override
protected void onPause() {
    if (handler != null) {
        handler.quitSynchronously();
        handler = null;
    }
    inactivityTimer.onPause();
    beepManager.close();
    cameraManager.closeDriver();
    if (!isHasSurface) {
        scanPreview.getHolder().removeCallback(this);
    }
    super.onPause();
}

@Override
protected void onDestroy() {
    inactivityTimer.shutdown();
    super.onDestroy();
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    if (holder == null) {
        Log.e(TAG,
                "*** WARNING *** surfaceCreated() gave us a null surface!");
    }
    if (!isHasSurface) {
        isHasSurface = true;
        initCamera(holder);
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    isHasSurface = false;
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {

}

/**
 * A valid barcode has been found, so give an indication of success and show
 * the results.
 * 
 * @param rawResult
 *            The contents of the barcode.
 * 
 * @param bundle
 *            The extras
 */
public void handleDecode(Result rawResult, Bundle bundle) {
    inactivityTimer.onActivity();
    beepManager.playBeepSoundAndVibrate();
    if (rawResult != null && !rawResult.getText().equalsIgnoreCase("")) {
         Intent intent = new Intent();
         intent.putExtra("scan_result", rawResult.getText());
         setResult(RESULT_OK, intent);
    } else {
        setResult(RESULT_CANCELED);
    }
        CaptureActivity.this.finish();
}

private void initCamera(SurfaceHolder surfaceHolder) {
    if (surfaceHolder == null) {
        throw new IllegalStateException("No SurfaceHolder provided");
    }
    if (cameraManager.isOpen()) {
        Log.w(TAG,
                "initCamera() while already open -- late SurfaceView callback?");
        return;
    }
    try {
        cameraManager.openDriver(surfaceHolder);
        // Creating the handler starts the preview, which can also throw a
        // RuntimeException.
        if (handler == null) {
            handler = new CaptureActivityHandler(this, cameraManager,
                    DecodeThread.ALL_MODE);
        }

        initCrop();
    } catch (IOException ioe) {
        Log.w(TAG, ioe);
        displayFrameworkBugMessageAndExit();
    } catch (RuntimeException e) {
        // Barcode Scanner has seen crashes in the wild of this variety:
        // java.?lang.?RuntimeException: Fail to connect to camera service
        Log.w(TAG, "Unexpected error initializing camera", e);
        displayFrameworkBugMessageAndExit();
    }
}

private void displayFrameworkBugMessageAndExit() {
    // camera error
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(getString(R.string.app_name));
    builder.setMessage("相机打开出错,请稍后重试");
    builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            finish();
        }

    });
    builder.setOnCancelListener(new DialogInterface.OnCancelListener() {

        @Override
        public void onCancel(DialogInterface dialog) {
            finish();
        }
    });
    builder.show();
}

public void restartPreviewAfterDelay(long delayMS) {
    if (handler != null) {
        handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS);
    }
}

public Rect getCropRect() {
    return mCropRect;
}

/**
 * 初始化截取的矩形区域
 */
private void initCrop() {
    int cameraWidth = cameraManager.getCameraResolution().y;
    int cameraHeight = cameraManager.getCameraResolution().x;

    /** 获取布局中扫描框的位置信息 */
    int[] location = new int[2];
    scanCropView.getLocationInWindow(location);

    int cropLeft = location[0];
    int cropTop = location[1] - getStatusBarHeight();

    int cropWidth = scanCropView.getWidth();
    int cropHeight = scanCropView.getHeight();

    /** 获取布局容器的宽高 */
    int containerWidth = scanContainer.getWidth();
    int containerHeight = scanContainer.getHeight();

    /** 计算最终截取的矩形的左上角顶点x坐标 */
    int x = cropLeft * cameraWidth / containerWidth;
    /** 计算最终截取的矩形的左上角顶点y坐标 */
    int y = cropTop * cameraHeight / containerHeight;

    /** 计算最终截取的矩形的宽度 */
    int width = cropWidth * cameraWidth / containerWidth;
    /** 计算最终截取的矩形的高度 */
    int height = cropHeight * cameraHeight / containerHeight;

    /** 生成最终的截取的矩形 */
    mCropRect = new Rect(x, y, width + x, height + y);
}

private int getStatusBarHeight() {
    try {
        Class<?> c = Class.forName("com.android.internal.R$dimen");
        Object obj = c.newInstance();
        Field field = c.getField("status_bar_height");
        int x = Integer.parseInt(field.get(obj).toString());
        return getResources().getDimensionPixelSize(x);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return 0;
}

}

才开始实现的时候用的下面这个方法。在handleDecode()里面调用,然后在CaptureActivityHandler这个类里面把restartPreviewAndDecode这个方法private 改成public。发现也是可以用的,但是速度太快,操作起来不怎么方便。
private void continuePreview() {
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.capture_preview);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
initCamera(surfaceHolder);
if (handler != null) {
handler.restartPreviewAndDecode();
}
}

最后,最后,最后自己直接用定时器来实现,很完美了。在handleDecode()这个方法里面,获取到数据以后直接添上这句代码 mHandler.postDelayed(runnable, 3000); 。下面是方法。

Handler mHandler = new Handler();
Runnable runnable = new Runnable() {

    @Override
    public void run() {
        // handler自带方法实现定时器
        try {
            if (handler != null)
                mHandler.postDelayed(runnable, 3000);
            handler.restartPreviewAndDecode(); // 实现多次扫描
            System.out.println("do...");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("exception...");
        }
    }
};
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android 是一种操作系统,而 Google 的 ZXing 是一个开源的二维码扫描库。通过使用 ZXing 库,我们可以轻松地在 Android 应用程序中实现二维码扫描功能。 要在 Android 应用中使用 ZXing,首先需要在项目的 build.gradle 文件中添加以下依赖: ``` implementation 'com.google.zxing:core:3.3.3' implementation 'com.journeyapps:zxing-android-embedded:4.0.0' ``` 接下来,在布局文件中添加一个 SurfaceView 控件,用于显示相机预览画面。 然后,在 Activity 或 Fragment 中添加以下代码: ``` private IntentIntegrator integrator; @Override protected void onCreate(Bundle savedInstanceState) { // ... integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE); integrator.setPrompt("请将二维码放入扫描框中"); integrator.setCameraId(0); // 后置摄像头 integrator.setBeepEnabled(false); // 关闭扫描提示音 integrator.setBarcodeImageEnabled(false); // 保存扫描的图片 integrator.initiateScan(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (result != null) { if (result.getContents() == null) { // 用户取消了扫描 } else { String scanResult = result.getContents(); // 在这里处理扫描得到的二维码数据 } } } ``` 在上述代码中,通过 `IntentIntegrator` 类来发起扫描,并在 `onActivityResult` 方法中处理扫描结果。 以上是使用 ZXing实现 Android 中的二维码扫描的简要介绍。使用 ZXing 库可以方便地实现二维码扫描功能,并且还提供了许多其他定制选项和扩展功能,可以根据需要进行使用和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值