Android集成zxing扫码框架功能

作者:Legned24 时间:2021-09-27 02:37:17 

       我们知道zxing是一个强大的处理二维码和条形码等的开源库,本篇文章记录一下自己在项目中集成zxing开源库的过程。

导入依赖


implementation 'com.google.zxing:core:3.3.3'

申请权限

       在AndroidManifest中申请相应权限:


<!--相机-->
<uses-permission android:name="android.permission.CAMERA" />
<!--震动-->
<uses-permission android:name="android.permission.VIBRATE" />
<!--存储-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

导入相关代码和资源文件

       导入的代码文件如下(源码在末尾):

Android集成zxing扫码框架功能

      相关的资源文件:

      1、在res/values下新建ids.xml文件,引入下面id:


<!--二维码/条形码扫描相关-->
<item name="auto_focus" type="id" />
<item name="decode" type="id" />
<item name="decode_failed" type="id" />
<item name="decode_succeeded" type="id" />
<item name="encode_failed" type="id" />
<item name="encode_succeeded" type="id" />
<item name="launch_product_query" type="id" />
<item name="quit" type="id" />
<item name="restart_preview" type="id" />
<item name="return_scan_result" type="id" />
<item name="search_book_contents_failed" type="id" />
<item name="search_book_contents_succeeded" type="id" />

      2、在res/values下新建attrs.xml文件,加入扫码框的属性,主要是ViewfinderView在使用:


<!--扫码框属性-->
<declare-styleable name="ViewfinderView">
<attr name="corner_color" format="color" />
<attr name="corner_size" format="dimension" />
<attr name="corner_stroke_width" format="dimension" />
<attr name="corner_position" format="enum">
 <enum name="inside" value="1" />
 <enum name="outside" value="2" />
</attr>
<attr name="line_color" format="color" />
<attr name="line_height" format="dimension" />
<attr name="line_move_distance" format="dimension" />
<attr name="frame_width" format="dimension" />
<attr name="frame_height" format="dimension" />
<attr name="frame_centerX" format="dimension" />
<attr name="frame_centerY" format="dimension" />
<attr name="frame_color" format="color" />
<attr name="frame_stroke_width" format="dimension" />
<attr name="mask_color" format="color" />
<attr name="result_point_color" format="color" />
<attr name="label_text" format="string" />
<attr name="label_text_color" format="color" />
<attr name="label_text_size" format="dimension" />
<attr name="label_text_margin" format="dimension" />
</declare-styleable>

       3、在res下新建raw目录,导入beep.mp3,实现扫码成功的滴滴音效,BeepManager在使用

       上面是一些比较重要的资源。

       然后介绍一下几个主要的类:

       1、ViewfinderView:自定义扫描框,代码如下,因为有注释,就不多说明了。


public final class ViewfinderView extends View {
private static final long ANIMATION_DELAY = 10L;
private static final int OPAQUE = 1;
private static final int CORNER_INSIDE = 1; //四个边角在扫描区内
private static final int CORNER_OUTSIDE = 2; //四个边角在扫描区外
private Paint paint;
//扫描区四个边角的颜色
private int cornerColor;
//扫描区边角的大小
private float cornerSize;
//扫描区边角的宽度
private float cornerStrokeWidth;
//边角的方向,在扫描区域内还是扫描区域外
private int cornerPosition;
//扫描线颜色
private int lineColor;
//扫描线高度
private float lineHeight;
//扫描线移动距离
private float lineMoveDistance;
//扫描区域宽度度
private float frameWidth;
//扫描区域高度
private float frameHeight;
//扫描区域中心位置的X坐标,默认正中间,在onLayout中设置
private float frameCenterX;
//扫描区域中心位置的Y坐标,默认正中间,在onLayout中设置
private float frameCenterY;
//扫描区域边框颜色
private int frameColor;
//扫描区域边框宽度
private float frameStrokeWidth;
//模糊区域颜色
private int maskColor;
//扫描点的颜色
private int resultPointColor;
//扫描区域提示文本
private String labelText;
//扫描区域提示文本颜色
private int labelTextColor;
//扫描区域提示文本字体大小
private float labelTextSize;
//扫描区域提示文本的边距
private float labelTextMargin;
public static int scannerStart = 0;
public static int scannerEnd = 0;
private Collection<ResultPoint> possibleResultPoints;
private Collection<ResultPoint> lastPossibleResultPoints;
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
 super(context, attrs);
 //初始化自定义属性信息
 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
 cornerColor = ta.getColor(R.styleable.ViewfinderView_corner_color, getResources().getColor(R.color.colorPrimary));
 cornerSize = ta.getDimension(R.styleable.ViewfinderView_corner_size, dp2px(context, 28));
 cornerStrokeWidth = ta.getDimension(R.styleable.ViewfinderView_corner_stroke_width, dp2px(context, 4));
 cornerPosition = ta.getInt(R.styleable.ViewfinderView_corner_position, CORNER_INSIDE);
 lineColor = ta.getColor(R.styleable.ViewfinderView_line_color, getResources().getColor(R.color.colorPrimary));
 lineHeight = ta.getDimension(R.styleable.ViewfinderView_line_height, dp2px(context, 3));
 lineMoveDistance = ta.getDimension(R.styleable.ViewfinderView_line_move_distance, dp2px(context, 2));
 frameWidth = ta.getDimension(R.styleable.ViewfinderView_frame_width, dp2px(context, 220));
 frameHeight = ta.getDimension(R.styleable.ViewfinderView_frame_height, dp2px(context, 220));
 frameCenterX = ta.getDimension(R.styleable.ViewfinderView_frame_centerX, -1);
 frameCenterY = ta.getDimension(R.styleable.ViewfinderView_frame_centerY, -1);
 frameColor = ta.getColor(R.styleable.ViewfinderView_frame_color, Color.parseColor("#90FFFFFF"));
 frameStrokeWidth = ta.getDimension(R.styleable.ViewfinderView_frame_stroke_width, dp2px(context, 0.2f));
 maskColor = ta.getColor(R.styleable.ViewfinderView_mask_color, Color.parseColor("#60000000"));
 resultPointColor = ta.getColor(R.styleable.ViewfinderView_result_point_color, Color.TRANSPARENT);
 labelText = ta.getString(R.styleable.ViewfinderView_label_text);
 labelTextColor = ta.getColor(R.styleable.ViewfinderView_label_text_color, Color.WHITE);
 labelTextSize = ta.getDimension(R.styleable.ViewfinderView_label_text_size, sp2px(context, 15));
 labelTextMargin = ta.getDimension(R.styleable.ViewfinderView_label_text_margin, dp2px(context, 18));
 ta.recycle();
 paint = new Paint();
 paint.setAntiAlias(true);
 possibleResultPoints = new HashSet<ResultPoint>(5);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
 super.onLayout(changed, left, top, right, bottom);
 //如果没有设置frameCenterX和frameCenterY默认布局正中间的X、Y坐标
 frameCenterX = (frameCenterX == -1) ? getWidth() / 2f : frameCenterX;
 frameCenterY = (frameCenterY == -1) ? getHeight() / 2f : frameCenterY;
 //设置扫描区域位置
 int leftOffset = (int) (frameCenterX - frameWidth / 2f);
 int topOffset = (int) (frameCenterY - frameHeight / 2f);
 //设置扫描区不超过屏幕
 leftOffset = leftOffset > 0 ? leftOffset : 0;
 topOffset = topOffset > 0 ? topOffset : 0;
 Rect rect = new Rect();
 rect.left = leftOffset;
 rect.top = topOffset;
 rect.right = (int) (leftOffset + frameWidth);
 rect.bottom = (int) (topOffset + frameHeight);
 CameraManager.get().setFramingRect(rect);
}
@Override
public void onDraw(Canvas canvas) {
 Rect frame = CameraManager.get().getFramingRect();
 if (frame == null) {
  return;
 }
 if (scannerStart == 0 || scannerEnd == 0) {
  scannerStart = frame.top;
  scannerEnd = frame.bottom;
 }
 int width = canvas.getWidth();
 int height = canvas.getHeight();
 //绘制模糊区域
 drawExterior(canvas, frame, width, height);
 //绘制扫描区边框
 drawFrame(canvas, frame);
 //绘制边角
 drawCorner(canvas, frame);
 //绘制提示信息
 drawTextInfo(canvas, frame);
 //绘制扫描线
 drawScanLine(canvas, frame);
 //绘制闪烁点
 drawResultPoint(canvas, frame);
 // Request another update at the animation interval, but only repaint the laser line,
 // not the entire viewfinder mask.
 //指定重绘区域,该方法会在子线程中执行
 postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
}
// 绘制模糊区域 Draw the exterior (i.e. outside the framing rect) darkened
private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
 paint.setColor(maskColor);
 canvas.drawRect(0, 0, width, frame.top, paint);
 canvas.drawRect(0, frame.top, frame.left, frame.bottom, paint);
 canvas.drawRect(frame.right, frame.top, width, frame.bottom, paint);
 canvas.drawRect(0, frame.bottom, width, height, paint);
}
// 绘制扫描区边框 Draw a two pixel solid black border inside the framing rect
private void drawFrame(Canvas canvas, Rect frame) {
 if (frameStrokeWidth > 0) {
  paint.setColor(frameColor);
  if (cornerPosition == CORNER_INSIDE) { //边角在扫描区内
   //左边
   canvas.drawRect(frame.left, frame.top, frame.left + frameStrokeWidth, frame.bottom, paint);
   //上边
   canvas.drawRect(frame.left, frame.top, frame.right, frame.top + frameStrokeWidth, paint);
   //右边
   canvas.drawRect(frame.right - frameStrokeWidth, frame.top, frame.right, frame.bottom, paint);
   //下边
   canvas.drawRect(frame.left, frame.bottom - frameStrokeWidth, frame.right, frame.bottom, paint);
  } else { //边角在扫描区外
   //左边
   canvas.drawRect(frame.left - frameStrokeWidth, frame.top - frameStrokeWidth,
     frame.left, frame.bottom + frameStrokeWidth, paint);
   //上边
   canvas.drawRect(frame.left - frameStrokeWidth, frame.top - frameStrokeWidth,
     frame.right + frameStrokeWidth, frame.top, paint);
   //右边
   canvas.drawRect(frame.right, frame.top - frameStrokeWidth, frame.right + frameStrokeWidth,
     frame.bottom + frameStrokeWidth, paint);
   //下边
   canvas.drawRect(frame.left - frameStrokeWidth, frame.bottom, frame.right + frameStrokeWidth,
     frame.bottom + frameStrokeWidth, paint);
  }
 }
}
//绘制边角
private void drawCorner(Canvas canvas, Rect frame) {
 if (cornerSize > 0 && cornerStrokeWidth > 0) {
  paint.setColor(cornerColor);
  if (cornerPosition == CORNER_INSIDE) { //绘制在扫描区域内区
   //左上
   canvas.drawRect(frame.left, frame.top, frame.left + cornerSize, frame.top + cornerStrokeWidth, paint);
   canvas.drawRect(frame.left, frame.top, frame.left + cornerStrokeWidth, frame.top + cornerSize, paint);
   //右上
   canvas.drawRect(frame.right - cornerSize, frame.top, frame.right, frame.top + cornerStrokeWidth, paint);
   canvas.drawRect(frame.right - cornerStrokeWidth, frame.top, frame.right, frame.top + cornerSize, paint);
   //左下
   canvas.drawRect(frame.left, frame.bottom - cornerSize, frame.left + cornerStrokeWidth, frame.bottom, paint);
   canvas.drawRect(frame.left, frame.bottom - cornerStrokeWidth, frame.left + cornerSize, frame.bottom, paint);
   //右下
   canvas.drawRect(frame.right - cornerSize, frame.bottom - cornerStrokeWidth, frame.right, frame.bottom, paint);
   canvas.drawRect(frame.right - cornerStrokeWidth, frame.bottom - cornerSize, frame.right, frame.bottom, paint);
  } else { //绘制在扫描区域外区
   //左上
   canvas.drawRect(frame.left - cornerStrokeWidth, frame.top - cornerStrokeWidth,
     frame.left - cornerStrokeWidth + cornerSize, frame.top, paint);
   canvas.drawRect(frame.left - cornerStrokeWidth, frame.top - cornerStrokeWidth,
     frame.left, frame.top - cornerStrokeWidth + cornerSize, paint);
   //右上
   canvas.drawRect(frame.right + cornerStrokeWidth - cornerSize, frame.top - cornerStrokeWidth,
     frame.right + cornerStrokeWidth, frame.top, paint);
   canvas.drawRect(frame.right, frame.top - cornerStrokeWidth,
     frame.right + cornerStrokeWidth, frame.top - cornerStrokeWidth + cornerSize, paint);
   //左下
   canvas.drawRect(frame.left - cornerStrokeWidth, frame.bottom, frame.left - cornerStrokeWidth + cornerSize,
     frame.bottom + cornerStrokeWidth, paint);
   canvas.drawRect(frame.left - cornerStrokeWidth, frame.bottom + cornerStrokeWidth - cornerSize,
     frame.left, frame.bottom + cornerStrokeWidth, paint);
   //右下
   canvas.drawRect(frame.right + cornerStrokeWidth - cornerSize, frame.bottom,
     frame.right + cornerStrokeWidth, frame.bottom + cornerStrokeWidth, paint);
   canvas.drawRect(frame.right, frame.bottom + cornerStrokeWidth - cornerSize,
     frame.right + cornerStrokeWidth, frame.bottom + cornerStrokeWidth, paint);
  }
 }
}
//绘制文本
private void drawTextInfo(Canvas canvas, Rect frame) {
 if (!TextUtils.isEmpty(labelText)) {
  paint.setColor(labelTextColor);
  paint.setTextSize(labelTextSize);
  paint.setTextAlign(Paint.Align.CENTER);
  Paint.FontMetrics fm = paint.getFontMetrics();
  float baseY = frame.bottom + labelTextMargin - fm.ascent;
  canvas.drawText(labelText, frame.left + frame.width() / 2, baseY, paint);
 }
}
//绘制扫描线
private void drawScanLine(Canvas canvas, Rect frame) {
 if (lineHeight > 0) {
  paint.setColor(lineColor);
  RadialGradient radialGradient = new RadialGradient(
    (float) (frame.left + frame.width() / 2),
    (float) (scannerStart + lineHeight / 2),
    360f,
    lineColor,
    shadeColor(lineColor),
    Shader.TileMode.MIRROR);
  paint.setShader(radialGradient);
  if (scannerStart <= scannerEnd) {
   //椭圆
   RectF rectF = new RectF(frame.left + 2 * lineHeight, scannerStart, frame.right - 2 * lineHeight,
     scannerStart + lineHeight);
   canvas.drawOval(rectF, paint);
   scannerStart += lineMoveDistance;
  } else {
   scannerStart = frame.top;
  }
  paint.setShader(null);
 }
}
private void drawResultPoint(Canvas canvas, Rect frame) {
 if (resultPointColor != Color.TRANSPARENT) {
  Collection<ResultPoint> currentPossible = possibleResultPoints;
  Collection<ResultPoint> currentLast = lastPossibleResultPoints;
  if (currentPossible.isEmpty()) {
   lastPossibleResultPoints = null;
  } else {
   possibleResultPoints = new HashSet<ResultPoint>(5);
   lastPossibleResultPoints = currentPossible;
   paint.setAlpha(OPAQUE);
   paint.setColor(resultPointColor);
   for (ResultPoint point : currentPossible) {
    canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
   }
  }
  if (currentLast != null) {
   paint.setAlpha(OPAQUE / 2);
   paint.setColor(resultPointColor);
   for (ResultPoint point : currentLast) {
    canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
   }
  }
 }
}
//处理颜色模糊
public int shadeColor(int color) {
 String hax = Integer.toHexString(color);
 String result = "20" + hax.substring(2);
 return Integer.valueOf(result, 16);
}
public void drawViewfinder() {
 invalidate();
}
public void addPossibleResultPoint(ResultPoint point) {
 possibleResultPoints.add(point);
}
private int dp2px(Context context, float dpValue) {
 float density = context.getApplicationContext().getResources().getDisplayMetrics().density;
 return (int) (dpValue * density + 0.5f);
}
private int sp2px(Context context, float spValue) {
 float scaleDensity = context.getApplicationContext().getResources().getDisplayMetrics().scaledDensity;
 return (int) (spValue * scaleDensity + 0.5f);
}
}

       2、CaptureActivity:扫码的Activity基类,代码如下;


/**
* Created by xuzhb on 2019/11/16
* Desc:扫码的Activity类
* 整个Activity最重要的两个控件是一个SurfaceView(摄像头)和一个ViewfinderView(扫描区)
* 对于继承CaptureActivity的Activity子类来说,
* 可以选择在自己的布局中定义和CaptureActivity的布局文件id相同的控件,
* 这样即使它们在两个布局中表现不同也能执行相同的逻辑,包括其他控件
* 或者选择重写getSurfaceView()和getViewfinderView()返回对应的两个控件,
* 扫码最终是在handleDecode(Result result, Bitmap bitmap)处理扫描后的结果
*/
public class CaptureActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private static final String TAG = "CaptureActivity";
private static final int IMAGE_PICKER = 1999;
private BeepManager mBeepManager;
private CaptureActivityHandler mHandler;
private Vector<BarcodeFormat> mDecodeFormats;
private String mCharacterSet;
private InactivityTimer mInactivityTimer;
private boolean hasSurface = false;
private boolean isLightOn = false; //是否打开闪光灯
private boolean isPlayBeep = true; //是否开启扫描后的滴滴声
private boolean isVibrate = true; //是否震动
private String mPhotoPath;   //选中的图片路径
private TitleBar mTitleBar;
private SurfaceView mSurfaceView;
private ViewfinderView mViewfinderView;
private LinearLayout mLightLl;
private ImageView mLightIv;
private TextView mLightTv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(getLayoutId());
 CameraManager.init(getApplicationContext());
 mBeepManager = new BeepManager(this);
 hasSurface = false;
 mInactivityTimer = new InactivityTimer(this);
 handleView(savedInstanceState);
 initView();
 initListener();
}
protected int getLayoutId() {
 return R.layout.activity_capture;
}
protected void handleView(@Nullable Bundle savedInstanceState) {
}
private void initView() {
 mTitleBar = findViewById(R.id.title_bar);
 mSurfaceView = findViewById(R.id.surfaceView);
 mViewfinderView = findViewById(R.id.viewfinderView);
 mLightLl = findViewById(R.id.light_ll);
 mLightIv = findViewById(R.id.light_iv);
 mLightTv = findViewById(R.id.light_tv);
}
protected void initListener() {
 //因为继承CaptureActivity的Activity子类的布局不一定包含id为title_bar和light_ll的控件,
 //没有的话如果子类通过super.initListener()覆写时会因为找不到而报异常,所以这里加了一个判空;
 //如果子类的布局中包含id相同的控件,则不需要在子类中再重写相同的逻辑
 if (mTitleBar != null) {
  StatusBarUtil.INSTANCE.darkModeAndPadding(this, mTitleBar, Color.BLACK, 0, false);
  mTitleBar.setOnLeftClickListener(v -> {
   finish();
   return null;
  });
  mTitleBar.setOnRightClickListener(v -> {
   openAlbum(); //打开相册选取图片扫描
   return null;
  });
 }
 if (mLightLl != null) {
  mLightLl.setOnClickListener(v -> switchLight()); //打开或关闭闪光灯
 }
}
//打开相册
protected void openAlbum() {
 Intent intent = new Intent(Intent.ACTION_PICK, null);
 intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
 startActivityForResult(intent, IMAGE_PICKER);
}
//开启/关闭闪光灯
private void switchLight() {
 if (CameraManager.get() != null) {
  if (isLightOn) {
   mLightTv.setText("轻触点亮");
   CameraManager.get().turnLightOffFlashLight();
  } else {
   mLightTv.setText("轻触关闭");
   CameraManager.get().turnOnFlashLight();
  }
  isLightOn = !isLightOn;
  mLightIv.setSelected(isLightOn);
 }
}
@Override
protected void onResume() {
 super.onResume();
 SurfaceHolder holder = getSurfaceView().getHolder();
 if (hasSurface) {
  initCamera(holder);
 } else {
  holder.addCallback(this);
  holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 }
 mDecodeFormats = null;
 mCharacterSet = null;
}
@Override
protected void onPause() {
 super.onPause();
 if (mHandler != null) {
  mHandler.quitSynchronously();
  mHandler = null;
 }
 CameraManager.get().closeDriver();
}
@Override
protected void onDestroy() {
 mInactivityTimer.shutdown();
 mBeepManager.releaseRing();
 super.onDestroy();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
 if (!hasSurface) {
  hasSurface = true;
  initCamera(holder);
 }
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
 hasSurface = false;
}
private void initCamera(SurfaceHolder holder) {
 try {
  CameraManager.get().openDriver(holder);
 } catch (Exception e) {
  e.printStackTrace();
 }
 if (mHandler == null) {
  mHandler = new CaptureActivityHandler(this, mDecodeFormats, mCharacterSet);
 }
}
//继承CaptureActivity的Activity类,如果SurfaceView的id和CaptureActivity布局中SurfaceView的id不同
//需要重写这个方法,返回自己布局中的SurfaceView
public SurfaceView getSurfaceView() {
 return mSurfaceView;
}
//继承CaptureActivity的Activity类,如果ViewfinderView的id和CaptureActivity布局中ViewfinderView的id不同
//需要重写这个方法,返回自己布局中的ViewfinderView
public ViewfinderView getViewfinderView() {
 return mViewfinderView;
}
public Handler getHandler() {
 return mHandler;
}
public void drawViewfinder() {
 getViewfinderView().drawViewfinder();
}
//处理扫描后的结果
public void handleDecode(Result result, Bitmap bitmap) {
 mInactivityTimer.onActivity();
 if (result != null) {
  String text = result.getText();
  Log.i(TAG, "识别的结果:" + text);
  if (!TextUtils.isEmpty(text)) { //识别成功
   playBeepSoundAndVibrate();
   returnQRCodeResult(text);
  } else {
   showToast("很抱歉,识别二维码失败!");
  }
 } else {
  showToast("未发现二维码!");
 }
}
private void playBeepSoundAndVibrate() {
 if (isPlayBeep) {
  mBeepManager.startRing(); //播放扫码的滴滴声
 }
 if (isVibrate) {
  Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
  if (vibrator != null) {
   vibrator.vibrate(200); //震动200毫秒
  }
 }
}
//返回扫描结果
private void returnQRCodeResult(String result) {
 Intent intent = new Intent();
 intent.putExtra(QRConstant.SCAN_QRCODE_RESULT, result);
 setResult(Activity.RESULT_OK, intent);
 finish();
}
private void showToast(CharSequence text) {
 runOnUiThread(() -> {
  ToastUtil.INSTANCE.showToast(text, true, false, getApplicationContext());
 });
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
 super.onActivityResult(requestCode, resultCode, data);
 if (requestCode == IMAGE_PICKER && resultCode == Activity.RESULT_OK) {
  if (data != null) {
   Uri uri = data.getData();
   if (uri != null) {
    Cursor cursor = getContentResolver().query(uri, null, null, null, null);
    if (cursor != null) {
     if (cursor.moveToFirst()) {
      mPhotoPath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
     }
     cursor.close();
     if (!TextUtils.isEmpty(mPhotoPath)) {
      //可以加个提示正在扫描的加载框,如showLoadingDialog("正在扫描...")
      new Thread(() -> {
       handleDecode(QRCodeUtil.decodeImage(mPhotoPath), null);
       //取消加载框,dismissLoadingDialog()
      }).start();
     } else {
      Log.e(TAG, "未找到图片");
     }
    }
   }
  }
 }
}
}

 看一下使用的例子

Android集成zxing扫码框架功能      Android集成zxing扫码框架功能

最后,附上整个项目的github地址,注:项目使用了视图绑定ViewBinding,所以需要使用AndroidStudio 3.6.x版本。

来源:https://blog.csdn.net/xuzhb_blog/article/details/105749962

标签:android,zxing,扫码
0
投稿

猜你喜欢

  • SQLite在C#中的安装与操作技巧

    2023-04-19 08:31:12
  • Android编程实现WebView添加进度条的方法

    2023-07-06 03:16:46
  • Java代码实现循环队列的示例代码

    2023-11-23 23:51:25
  • intellij idea创建第一个动态web项目的步骤方法

    2023-04-16 15:47:20
  • 详解Springboot配置文件的使用

    2022-02-26 09:02:26
  • 利用maven引入第三方jar包以及打包

    2023-11-15 04:23:17
  • Java中去除字符串中所有空格的几种方法

    2023-11-24 04:59:24
  • C++实现简易反弹小球游戏的示例代码

    2023-06-15 08:18:50
  • java代码规范review异常事故记录

    2023-08-03 07:23:24
  • 基于java集合中的一些易混淆的知识点(详解)

    2023-08-29 03:06:26
  • Java用栈实现综合计算器

    2021-08-16 02:01:36
  • spring boot mybatis枚举映射示例代码

    2023-03-01 11:45:51
  • springboot 多数据源的实现(最简单的整合方式)

    2022-08-20 02:30:11
  • tomcat部署java web项目遇到的问题及解决方法

    2023-08-04 23:44:27
  • 对WPF中的TreeView实现右键选定

    2022-01-21 00:25:55
  • Flutter简洁实用的图片编辑器的实现

    2021-10-31 08:30:44
  • SpringBoot中的Thymeleaf用法

    2023-10-30 17:30:39
  • Java中的静态内部类详解及代码示例

    2021-11-25 08:50:00
  • Eclipse下Javassist正确使用方法代码解析

    2021-07-24 18:43:57
  • IDEA集成JProfiler11可视化工具的详细流程(安装、集成、测试)

    2021-12-12 04:05:35
  • asp之家 软件编程 m.aspxhome.com