如何在Java中使用CameraX与ML Kit实现条码扫描功能

来源:网站主作者:缅甸程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《如何在Java中使用CameraX与ML Kit实现条码扫描功能》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在Java中使用CameraX与ML Kit实现条码扫描功能》有用,将其分享出去将是对创作者最好的鼓励。

在Android应用开发中,条码扫描是很多场景下的必备功能,结合CameraX的相机管理能力和ML Kit的条码识别能力,可以在Java项目中快速实现稳定高效的扫描方案。CameraX简化了相机API的调用复杂度,ML Kit则提供了预训练的条码识别模型,无需开发者自行训练即可支持多种类型的条码识别。

如何在Java中使用CameraX与ML Kit实现条码扫描功能

环境配置与依赖添加

首先需要在项目的build.gradle文件中添加相关依赖,确保CameraX和ML Kit的库被正确引入。同时需要申请相机权限,保证应用可以正常调用设备相机。

添加Gradle依赖

在app模块的build.gradle的dependencies节点中添加以下依赖:

dependencies {
    // CameraX 核心依赖
    def camerax_version = "1.3.0"
    implementation "androidx.camera:camera-core:${camerax_version}"
    implementation "androidx.camera:camera-camera2:${camerax_version}"
    implementation "androidx.camera:camera-lifecycle:${camerax_version}"
    implementation "androidx.camera:camera-view:${camerax_version}"
    // ML Kit 条码扫描依赖
    implementation "com.google.mlkit:barcode-scanning:17.2.0"
}

申请权限

在AndroidManifest.xml中添加相机权限声明:

<uses-permission android:name="android.permission.CAMERA" />

如果应用需要适配Android 6.0及以上系统,还需要在运行时动态申请相机权限,避免权限缺失导致功能无法使用。

布局文件配置

布局中需要包含相机预览的容器和用于显示扫描结果的区域,核心是使用CameraX提供的PreviewView组件作为相机预览的载体。

<?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">

    <!-- 相机预览视图 -->
    <androidx.camera.view.PreviewView
        android:id="@+id/previewView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- 扫描结果展示 -->
    <TextView
        android:id="@+id/tvResult"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="#80000000"
        android:textColor="#FFFFFF"
        android:textSize="16sp"
        android:padding="16dp"
        android:text="扫描结果将显示在这里" />

</FrameLayout>

核心功能实现

初始化相机与ML Kit扫描器

在Activity中完成相机初始化和ML Kit条码扫描器的配置,绑定相机生命周期并启动预览。

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.*;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.mlkit.vision.barcode.Barcode;
import com.google.mlkit.vision.barcode.BarcodeScanner;
import com.google.mlkit.vision.barcode.BarcodeScannerOptions;
import com.google.mlkit.vision.barcode.BarcodeScanning;
import com.google.mlkit.vision.common.InputImage;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ScanActivity extends AppCompatActivity {
    private PreviewView previewView;
    private TextView tvResult;
    private ExecutorService cameraExecutor;
    private BarcodeScanner barcodeScanner;
    private static final int REQUEST_CAMERA_PERMISSION = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan);
        previewView = findViewById(R.id.previewView);
        tvResult = findViewById(R.id.tvResult);
        cameraExecutor = Executors.newSingleThreadExecutor();
        // 配置ML Kit扫描器,支持所有条码类型
        BarcodeScannerOptions options = new BarcodeScannerOptions.Builder()
                .setBarcodeFormats(Barcode.FORMAT_ALL_FORMATS)
                .build();
        barcodeScanner = BarcodeScanning.getClient(options);
        // 检查相机权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
        } else {
            startCamera();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startCamera();
            } else {
                Toast.makeText(this, "需要相机权限才能使用扫描功能", Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }

    private void startCamera() {
        ProcessCameraProvider.getInstance(this).addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = ProcessCameraProvider.getInstance(this).get();
                // 配置预览用例
                Preview preview = new Preview.Builder().build();
                preview.setSurfaceProvider(previewView.getSurfaceProvider());
                // 配置图像分析用例,用于获取相机帧进行条码识别
                ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                        .build();
                imageAnalysis.setAnalyzer(cameraExecutor, imageProxy -> {
                    // 将ImageProxy转换为ML Kit支持的InputImage
                    InputImage inputImage = InputImage.fromMediaImage(imageProxy.getImage(), imageProxy.getImageInfo().getRotationDegrees());
                    // 执行条码扫描
                    barcodeScanner.process(inputImage)
                            .addOnSuccessListener(barcodes -> {
                                if (!barcodes.isEmpty()) {
                                    // 取第一个识别到的条码结果
                                    Barcode barcode = barcodes.get(0);
                                    runOnUiThread(() -> tvResult.setText("扫描结果:" + barcode.getRawValue()));
                                }
                            })
                            .addOnFailureListener(e -> {
                                runOnUiThread(() -> tvResult.setText("扫描失败:" + e.getMessage()));
                            })
                            .addOnCompleteListener(task -> imageProxy.close());
                });
                // 选择后置摄像头
                CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
                // 绑定用例到相机生命周期
                cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
        }, ContextCompat.getMainExecutor(this));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        cameraExecutor.shutdown();
        barcodeScanner.close();
    }
}

功能优化与适配

上述基础实现已经可以完成条码扫描功能,实际使用中可以根据需求做进一步优化:

  • 添加扫描框UI,提示用户将条码对准扫描区域,提升用户体验
  • 对扫描结果做去重处理,避免同一条码短时间内重复回调
  • 根据实际场景调整图像分析的分辨率,平衡识别准确率和性能
  • 针对弱光环境添加补光提示,或者调整相机曝光参数提升识别成功率

常见问题说明

在实际开发中可能会遇到以下问题:

  • 相机预览黑屏:检查相机权限是否申请成功,或者PreviewView的布局参数是否正确
  • 条码识别率低:可以调整图像分析的分辨率,或者限制扫描的条码类型减少干扰
  • 内存泄漏:确保在Activity销毁时关闭相机执行器并释放ML Kit扫描器资源

通过CameraX和ML Kit的结合,开发者无需处理复杂的相机底层逻辑和条码识别算法,只需要少量代码即可实现稳定可用的条码扫描功能,适配大部分Android设备。

CameraXML_KitJava条码扫描修改时间:2026-06-14 21:57:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。