React Native中frameProcessor内调用API致App崩溃求助
React Native vision-camera-code-scanner 扫描后调用API崩溃问题解决
问题分析
- Worklet线程冲突:
frameProcessor运行在Worklet线程(非JS主线程),直接在其中调用Redux的dispatch(主线程操作)会触发跨线程调用冲突,导致应用崩溃。 - 无JSON解析错误处理:
JSON.parse(detectedBarcodes[0].rawValue)未做异常捕获,若二维码内容不是合法JSON,会直接抛出错误引发崩溃。 - 重复触发API:摄像头帧处理器每秒执行多次,扫描到二维码时会重复调用API,可能引发请求堆积或状态异常。
- useCallback依赖缺失:
validate函数的useCallback未添加依赖项,虽Redux dispatch本身稳定,但不符合Hooks规范,可能导致意外行为。
解决方案
- 用
runOnJS执行主线程代码:通过Vision Camera提供的runOnJS方法,将主线程函数(如dispatch调用)包装后在Worklet中执行,避免跨线程冲突。 - 添加JSON解析异常捕获:用try-catch包裹
JSON.parse,处理非法二维码内容的情况。 - 控制扫描触发频率:增加状态标记是否已处理过当前二维码,避免重复调用API。
- 完善Hooks依赖:为
validate的useCallback添加dispatch依赖,符合Hooks规则。
修改后的完整代码
import React, { useState, useCallback, useEffect } from "react"; import { StyleSheet, Text } from "react-native"; import { Camera, useCameraDevices, useFrameProcessor, runOnJS, } from "react-native-vision-camera"; import { useDispatch, useSelector } from "react-redux"; import * as appActions from "../../../redux/app/app.actions"; import { BarcodeFormat, scanBarcodes } from "vision-camera-code-scanner"; interface ScanScreenProps {} const Scan: React.FC<ScanScreenProps> = () => { const [hasPermission, setHasPermission] = useState(false); const [isScanned, setIsScanned] = useState(false); // 标记是否已处理当前扫描 const devices = useCameraDevices(); const device = devices.back; const dispatch = useDispatch(); const validateQRStatus = useSelector(validationQRSelector); // 修正useCallback依赖,确保函数稳定性 const validate = useCallback((param: string) => { dispatch(appActions.validateQR(param)); }, [dispatch]); const frameProcessor = useFrameProcessor((frame) => { "worklet"; if (isScanned) return; // 已处理过则直接返回,避免重复调用 const detectedBarcodes = scanBarcodes(frame, [BarcodeFormat.QR_CODE], { checkInverted: true, }); if (detectedBarcodes?.length !== 0) { try { const resultObj = JSON.parse(detectedBarcodes[0].rawValue); const paramData = `token:${Object.values(resultObj)[0]}`; // 切换到主线程执行validate函数 runOnJS(validate)(paramData); // 标记为已处理,防止重复扫描 runOnJS(setIsScanned)(true); // 可选:3秒后重置扫描状态,允许再次扫描其他二维码 setTimeout(() => { runOnJS(setIsScanned)(false); }, 3000); } catch (e) { // 处理JSON解析错误,可根据需求添加用户提示 console.log("二维码内容格式错误:", e); } } }, [isScanned, validate]); // 添加正确的依赖项 useEffect(() => { (async () => { const status = await Camera.requestCameraPermission(); setHasPermission(status === "authorized"); })(); }, []); return ( device != null && hasPermission && ( <> <Camera style={StyleSheet.absoluteFill} device={device} isActive={true} frameProcessor={frameProcessor} frameProcessorFps={5} /> <Text style={styles.barcodeTextURL}>camera</Text> </> ) ); }; export default Scan; const styles = StyleSheet.create({ barcodeTextURL: { fontSize: 20, color: "white", fontWeight: "bold", alignSelf: "center", }, });
关键修改说明
runOnJS的使用:将主线程的validate函数通过runOnJS包装后执行,彻底解决Worklet线程与主线程的调用冲突。- 扫描状态控制:
isScanned状态确保同一个二维码仅触发一次API调用,同时通过定时器重置状态,支持连续扫描不同二维码。 - 错误防护:try-catch捕获JSON解析异常,避免非法格式的二维码直接导致应用崩溃。
- 依赖规范:完善
useCallback和useFrameProcessor的依赖项,符合React Hooks的最佳实践。
内容的提问来源于stack exchange,提问作者Tanmoy Sarker
相关产品推荐
相关产品推荐

