google扫码库barcode-scanning的使用

2023-11-09

一、加入barcode-scanning库

//捆绑模式扫码
implementation 'com.google.mlkit:barcode-scanning:17.1.0'

二、编写扫码分析类,用于分析扫码数据并回调方法返回结果

package com.gnetek.monitor.adapter

import android.util.Log
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage

/**
 * @Description 扫码分析器
 * @Author Darren Huang
 * @Date 2023-06-14 10:57
 */
class QRCodeAnalyzer(private val listener: (List<Barcode>) ->Unit) : ImageAnalysis.Analyzer {
    companion object {
        private const val TAG = "QRCodeAnalyzer"
    }

    @androidx.annotation.OptIn(androidx.camera.core.ExperimentalGetImage::class)
    override fun analyze(imageProxy: ImageProxy) {
        val image = imageProxy.image
        image?.let {
            val inputImage = InputImage.fromMediaImage(it, imageProxy.imageInfo.rotationDegrees)
            processImage(inputImage, imageProxy)
        }
    }

    //设置扫码类型,支持同时设置多个
    private val options = BarcodeScannerOptions.Builder()
        .setBarcodeFormats(Barcode.FORMAT_CODE_128)//条形码
//        .setBarcodeFormats(Barcode.FORMAT_QR_CODE)//二维码
        .build()
    private val scanner = BarcodeScanning.getClient(options)

    private fun processImage(image: InputImage, imageProxy: ImageProxy) {
        scanner.process(image)
            .addOnSuccessListener(listener)
            .addOnFailureListener {
                Log.e(TAG, "processImage: ${it.message}")
            }
            .addOnCompleteListener {
                imageProxy.close()
            }
    }
}

三、扫码的activity,调用相机

package com.gnetek.monitor.ui.activity

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.gnetek.monitor.R
import com.gnetek.monitor.adapter.QRCodeAnalyzer
import com.gnetek.monitor.databinding.ActivityScannerBinding
import com.gnetek.monitor.utils.StringUtil
import com.gnetek.monitor.base.BaseActivity
import java.util.concurrent.Executors

class ScannerActivity : BaseActivity() {

    companion object {
        private const val TAG = "ScannerActivity"
    }

    private val viewBinding: ActivityScannerBinding by lazy { ActivityScannerBinding.inflate(layoutInflater) }

    // 解析数据 Executor
    private val cameraExecutor by lazy { Executors.newSingleThreadExecutor() }

    private lateinit var requestPermissionLauncher: ActivityResultLauncher<Array<String>>
    override fun onCreate(savedInstanceState: Bundle?) {
        // 创建一个ActivityResultLauncher对象,用于请求权限
        requestPermissionLauncher = registerForActivityResult(
            ActivityResultContracts.RequestMultiplePermissions()
        ) { permissions ->
            if (permissions.containsValue(false)) {
                // 如果用户拒绝了权限,则需要向用户解释为什么需要该权限
                xToasts(R.string.setup_station_info_image_permission, 0)
            } else {
                // 已经授权,执行相关操作
                Log.e(TAG, "onCreate: 已经授权,执行相关操作")
                startCamera()
            }
        }
        super.onCreate(savedInstanceState)
    }

    override fun viewBinding() {
        setContentView(viewBinding.root)
    }

    override fun initView() {
        super.initView()
        //检查相机权限
        val bool = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
        if(bool) {
            startCamera()
        }else {//申请相机权限
            requestPermissionLauncher.launch(arrayOf(Manifest.permission.CAMERA))
        }
    }

    // 初始化相机和扫码
    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        cameraProviderFuture.addListener({
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
            // Preview
            val preview = Preview.Builder()
                .build()
                .also {
                    it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
                }

            // 默认选择后摄
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
            val imageAnalyzer = ImageAnalysis.Builder()
                .build()
                .also {
                    it.setAnalyzer(cameraExecutor, QRCodeAnalyzer { list ->
                        // 扫码结果,这里需根据项目做去重处理
                        val codes = list.filter { StringUtil.isNotBlank(it.rawValue.toString()) }.distinct().joinToString(separator=",") { it.rawValue.toString() }
                        Log.d(TAG, "startCamera barcode: $codes")
                        if(StringUtil.isNotBlank(codes)) {
                            val intent = Intent()
                            intent.putExtra("codes", codes)
                            setResult(RESULT_OK, intent)
                            finish()
                        }
                    })
                }

            try {
                // Unbind use cases before rebinding
                cameraProvider.unbindAll()
                // Bind use cases to camera
                cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalyzer)
            } catch (exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this))
    }
}

四、BaseActivity类

package com.gnetek.monitor.base
import android.os.Bundle
import android.view.Gravity
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import com.gnetek.monitor.R
import com.xuexiang.xui.utils.WidgetUtils
import com.xuexiang.xui.utils.XToastUtils
import com.xuexiang.xui.widget.dialog.LoadingDialog
import com.xuexiang.xui.widget.toast.XToast
import org.jetbrains.anko.*

/**
 * activity的基类
 * @author Darren
 * @date 2023/05/06
 * @constructor 创建[BaseActivity]
 */
abstract class BaseActivity : AppCompatActivity(), AnkoLogger {

    /**
     * 加载中
     */
    protected lateinit var baseLoadingDialog: LoadingDialog

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        XToast.Config.get() //位置设置为居中
            .setGravity(Gravity.CENTER)
        viewBinding()
        initView()
        initListener()
        initData()
        info { "onCreate" }
    }

    /**
     * 绑定布局
     */
    abstract fun viewBinding()

    /**
     * 初始化view
     */
    protected open fun initView(){
        baseLoadingDialog = WidgetUtils.getLoadingDialog(this)
            .setIconScale(0.4f)
            .setLoadingSpeed(8)
    }

    /**
     * 初始化监听
     */
    protected open fun initListener() {

    }

    /**
     * 初始化数据
     */
    protected open fun initData() {

    }

    /**
     * FragmentManager的扩展函数,它将一个带有接受者的Lambda函数作为传入的参数,而这个FragmentTransaction就是接收者对象
     */
    inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
        beginTransaction().func().commit()
    }

    fun FragmentActivity.addFragment(fragment: Fragment, frameId: Int){
        supportFragmentManager.inTransaction { add(frameId, fragment) }
    }


    fun FragmentActivity.replaceFragment(fragment: Fragment, frameId: Int) {
        supportFragmentManager.inTransaction{replace(frameId, fragment)}
    }

    /**
     * 线程安全的提示信息
     */
    fun toasts(message:String){
        runOnUiThread{longToast(message)}
    }

    /**
     * 线程安全的提示信息
     */
    fun toasts(messageRes:Int){
        runOnUiThread{longToast(messageRes)}
    }



    /**
     * 线程安全的提示信息
     * 0->error 1->success 2->info 3->warning 4->toast
     */
    fun xToasts(message: String, position: Int=4){
        try {
            runOnUiThread {
                when (position) {
                    0 -> XToastUtils.error(message)
                    1 -> XToastUtils.success(message)
                    2 -> XToastUtils.info(message)
                    3 -> XToastUtils.warning(message)
                    4 -> XToastUtils.toast(message)
                }
            }
        }catch (e: IllegalStateException){
            e.printStackTrace()
        }
    }

    /**
     * 线程安全的提示信息
     * 0->error 1->success 2->info 3->warning 4->toast
     */
    fun xToasts(messageRes: Int, position: Int=4){
        try {
            runOnUiThread {
                when (position) {
                    0 -> XToastUtils.error(messageRes)
                    1 -> XToastUtils.success(messageRes)
                    2 -> XToastUtils.info(messageRes)
                    3 -> XToastUtils.warning(messageRes)
                    4 -> XToastUtils.toast(messageRes)
                }
            }
        }catch (e: IllegalStateException){
            e.printStackTrace()
        }
    }

    /**
     * 开启activity并且关闭当前界面,在打开新的界面中返回不用显示当前界面时用
     */
    inline fun <reified T: BaseActivity> startActivityAndFinish(){
        startActivity<T>()
        finish()
    }

    /**
     * 从左开始活动
     */
    inline fun <reified T: BaseActivity> startActivityFromLeft(){
        startActivity<T>()
        //从左到右切入
        overridePendingTransition(R.anim.slide_in_from_left,R.anim.slide_out_to_right)
    }


    /**
     * 从右开始活动
     */
    inline fun <reified T: BaseActivity> startActivityFromRight(){
        startActivity<T>()
        //从右到左切入
        overridePendingTransition(R.anim.slide_in_from_right,R.anim.slide_out_to_left)
    }

    /**
     * 加载中
     */
    fun showLoading(){
        runOnUiThread {
            baseLoadingDialog.show()
        }
    }
    /**
     * 加载完成
     */
    fun hideLoading(){
        runOnUiThread {
            baseLoadingDialog.dismiss()
        }
    }

    /**
     * 获得焦点
     * @param [view] 视图
     */
    fun getFocus(view: View){
        runOnUiThread {
            view.requestFocus()
        }
    }

    /**
     * 销毁
     */
    override fun onDestroy() {
        XToast.Config.get() //位置还原
            .resetGravity()
        super.onDestroy()
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

google扫码库barcode-scanning的使用 的相关文章

随机推荐

  • pymysql的使用

    pymysql是从Python连接到MySQL数据库服务器的接口 其官方文档为 https pymysql readthedocs io en latest 安装 pip install pymysql 对于数据库的操作 我们一般是这样的操
  • 正在开发应用于Maxthon、TT等多页面浏览器的页面模式

    经过大量的用户调查 我们发现 有不少朋友使用了Maxthon 腾讯TT 世界之窗等基于IE的多页面浏览器使用WEBCHAT 而这种模式下弹出窗口将变成一个新页面 用起来不方便
  • 如何查看支付宝旗下的天弘基金一共有多少只?分别是什么?

    如何查看支付宝旗下的天弘基金一共有多少只 分别是什么 2020年 股市风格突变 相对股市个股的跌宕起伏 基金的收益可谓一枝独秀 下面我们将对基金进行研究 看看我们可以获取数据能否到什么程度 利用tushare的数据接口就可以获取基金的名称
  • 排序类算法

    文章目录 利用vector进行排序 数字类元素 字符串类元素 利用其他STL容器排序 map set priority queue 利用vector进行排序 数字类元素 每个元素一般包含多个条件 利用lambda编写特定排序条件 用sort
  • 转:Ogre TerrainGroup地形赏析

    转 Ogre TerrainGroup地形赏析 1 1 参考 http www ogre3d org tikiwiki tiki index php page Ogre Terrain System http www ogre3d org
  • VS2017找不到QT头文件

    一 我的电脑右键属性 高级系统设置 环境变量 增加环境变量Qt INCLUDEPATH 值为QT的头文件目录 二 重启VS 发现波纹线不见了 证明设置环境变量后VS能识别到QT头文件了 原理是 vs导入qt项目附加包含目录继承值有Qt IN
  • (202301)pytorch图像分类全流程实战Task6:可解释性分析、显著性分析

    Task6 可解释性分析 显著性分析 对B站up同济子豪兄的图像分类系列的学习 大佬的完整代码在GitHub开源 2022年人工智能依旧飞速发展 从传统机器学习模型到如今以 炼丹 为主的深度神经网络 代表着模型拟合度与模型可解释性各自的发展
  • MySQL学习(十六):数据类型之日期与时间类型

    数据类型之日期与时间类型 日期与时间是重要的信息 在我们的系统中 几乎所有的数据表都用得到 原因是客户需要知道数据的时间标签 从而进行数据查询 统计和处理 类型 名称 字节 日期格式 最小值 最大值 YEAR 年 1 YYYY或YY 190
  • Linux系统管理(六)高级存储管理

    目录 一 逻辑卷 二 lvm逻辑管理器 lvm建立 lvm拉伸 lvm缩减 lvm删除 lvm快照 三 vdo虚拟数据优化器 vdo建立 使用vdo设备 测试vdo性能 设置vdo开机自启动 vdo设备的删除 一 逻辑卷 pv 物理卷 被处
  • DRM——学习篇0:概念认识

    刚开始学习 记忆不是很好 容易忘 边学边记 阅读的速度会比较慢 看的会比较仔细 这边主要参考以下博客 前辈们水平很高 写的很详细 详细的知识学习可查看以下链接 详细请看 蜗窝科技 http www wowotech net graphic
  • wpf 怎么用代码连接sql server

    在WPF中 可以使用C 代码来连接SQL Server 以下是连接SQL Server的一般步骤 首先 在项目中添加对System Data SqlClient命名空间的引用 在代码中创建SqlConnection对象 该对象表示与SQL
  • 18.tf坐标系广播与监听的实现

    学习视频 https www bilibili com video BV1zt411G7Vn p 18 广播器代码 获取海龟位置 广播world与海龟坐标系之间的tf数据 监听器代码 监听tf数据 并计算 发布turtle2的速度指令 一
  • FAPI专题-2:5G nFAPI接口 - 中文规范-2- 消息交互流程

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https mp csdn net mp blog creation editor 117588884 目录 第1章 简介 第2章 nFAP
  • MySQL开启远程访问权限

    默认情况下 MySQL只允许本地登录 即只能在安装MySQL环境所在的主机下访问 但是在日常开发和使用中 我们经常需要访问远端服务器的数据库 此时就需要开启服务器端MySQL的远程连接权限 1 生成环境 连接MySQL 2 查看MySQL当
  • 最言简意赅的strftime和strptime区分方式

    最近时常处理金融数据 最绕不过的就是对各种日期格式进行处理 其中用得最多的就是striptime和striftime 之前每用一次都得查一下用法 这次干脆完全弄清楚然后记下来 以下是最言简意赅的区分方式 strptime 将字符串转换为日期
  • 某团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?

    转载 最近网上出现一个美团面试题 一个线程OOM后 其他线程还能运行吗 我看网上出现了很多不靠谱的答案 这道题其实很有难度 涉及的知识点有jvm内存分配 作用域 gc等 不是简单的是与否的问题 由于题目中给出的OOM java中OOM又分很
  • 谭铁牛院士:向生物学习 开启模式识别新突破

    人们在观察事物或现象的时候 常常要把各个相似的但又不完全相同的事物或现象组成一类 例如一个数字有不同的写法 对一个人来说 某一种写法虽然没有见过 但大脑却能自动将这个字识别出来 这种模式识别行为虽然人们早已司空见惯 在中国科学院院士谭铁牛看
  • 前端学习历程

    前言 还记得刚接触前端应该是两年前了吧 我就顺着回忆 慢慢写下我对前端的学习路程以及一些资源 初入坑 html css基础 这个是学习前端最基础的部分了 一开始看的是W3cschool 先看其中的html和css基础部分 一些常用标签 以及
  • Python常用的第三方库汇总【推荐】

    Python常用的第三方库汇总 pymysql 操作MySQL数据库 Flask 一个 Python 后端开发的微型框架 numpy 进行科学计算所需的基础包 pillow 非常好用的图像处理库 opencv python 图像处理库 Ma
  • google扫码库barcode-scanning的使用

    一 加入barcode scanning库 捆绑模式扫码 implementation com google mlkit barcode scanning 17 1 0 二 编写扫码分析类 用于分析扫码数据并回调方法返回结果 package