Android二次启动扫码Activity时条码扫描功能失效问题
Android CameraX 二次启动扫码页无法识别QR码问题
问题现象
- 基于CameraX实现安卓应用QR扫码功能,项目分为主Activity、扫码Activity两个页面:主Activity负责启动扫码页,扫码页检测到符合自定义规则(匹配指定scheme、host、path)的URI时,自动销毁页面返回主Activity,弹出对应业务对话框。
- 功能首次运行完全正常,但第二次及后续启动扫码Activity时,相机预览画面正常显示,但始终无法识别QR码,
onQRCodeFound回调不会被触发;杀死应用重启后可恢复正常,仅能完成1次扫码,再次打开扫码页问题复现。 - 问题复现时,日志持续打印错误:
W/System.err: com.google.zxing.NotFoundException
排查进展
- 定位到直接诱因:二次及后续启动扫码Activity时,
previewView控件的宽高取值均为0(首次启动时可正常获取1080x2280的实际尺寸),为ImageAnalysis分析用例设置0x0的无效目标分辨率,直接导致条码识别失效。 - 验证可行的临时方案1:放弃动态获取
previewView宽高的逻辑,直接硬编码分辨率数值,每次启动扫码功能均可正常运行。 - 验证可行的临时方案2:将
bindCameraPreview(cameraProvider)的调用修改为previewView.post(()->bindCameraPreview(cameraProvider)),通过post延迟绑定操作,功能也可正常运行。 - 目前不确定post延迟绑定的方案是否为最优/标准实现,仅确认可解决当前问题;尚未明确根因:为何
previewView首次启动时可正常获取尺寸,二次启动时宽高取值为0,欢迎知晓原因的开发者解答。
相关实现代码
ScanQRActivity 代码
public class ScanQRActivity extends AppCompatActivity { private static final int PERMISSION_REQUEST_CAMERA = 0; private PreviewView previewView; private ListenableFuture<ProcessCameraProvider> cameraProviderFuture; private Button qrCodeFoundButton; private String qrCode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qr_scan); previewView = findViewById(R.id.activity_main_previewView); qrCodeFoundButton = findViewById(R.id.activity_main_qrCodeFoundButton); qrCodeFoundButton.setVisibility(View.INVISIBLE); cameraProviderFuture = ProcessCameraProvider.getInstance(this); requestCamera(); } private void requestCamera() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { startCamera(); } else { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { ActivityCompat.requestPermissions(ScanQRActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_CAMERA) { if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startCamera(); } else { // Toast.makeText(this, "Camera Permission Denied", Toast.LENGTH_SHORT).show(); } } } private void startCamera() { cameraProviderFuture.addListener(() -> { try { ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); bindCameraPreview(cameraProvider); } catch (ExecutionException | InterruptedException e) { Toast.makeText(this, "Error starting camera " + e.getMessage(), Toast.LENGTH_SHORT).show(); } }, ContextCompat.getMainExecutor(this)); } private void bindCameraPreview(@NonNull ProcessCameraProvider cameraProvider) { previewView.setImplementationMode(PreviewView.ImplementationMode.COMPATIBLE); Preview preview = new Preview.Builder() .build(); CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); preview.setSurfaceProvider(previewView.getSurfaceProvider()); ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(previewView.getWidth(), previewView.getHeight() )) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build(); imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), new QRCodeImageAnalyzer(new QRCodeImageAnalyzer.QRCodeFoundListener() { @Override public void onQRCodeFound(String _qrCode) { qrCode = _qrCode; qrCodeFoundButton.setVisibility(View.VISIBLE); Uri code = Uri.parse(qrCode); if(code.getScheme().equals("myCustomScheme") && code.getHost().equals("app")){ String path = code.getPath(); String host = code.getHost() ; String query = code.getQuery(); List<String> params = code.getQueryParameters("a"); if(path.equals("/voucher")){ Intent intent = new Intent(); intent.putExtra("type", "voucher"); intent.putExtra("voucherCode", code.getQueryParameter("c")); intent.putExtra("timestamp", code.getQueryParameter("t")); setResult(Activity.RESULT_OK, intent); finish(); } } } @Override public void qrCodeNotFound() { } })); Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector,imageAnalysis, preview); } }
页面返回处理代码
ActivityResultLauncher<Intent> startQRActivity = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == Activity.RESULT_OK) { Intent data = result.getData(); String code = data.getStringExtra("voucherCode"); String time = data.getStringExtra("timestamp"); voucherDetailBusinessDialog dia = new voucherDetailBusinessDialog(getColor(R.color.appThemeColor), getColor(R.color.orange), code); dia.show(getSupportFragmentManager(),null); } } });
内容的提问来源于stack exchange,提问作者Charlie Walker
相关产品推荐
相关产品推荐

