React Native多屏使用Zebra DataWedge Intent初始化耗时倍增问题
问题分析与解决方案
问题概述
我们开发了一款包含多个扫描组件页面的扫描APP。首次加载首页的扫描组件时初始化耗时正常,但在页面间切换时,每次初始化耗时都会比上一次翻倍。扫描功能可正常工作,仅存在页面切换时初始化时长倍增的问题。
设备与依赖信息
- 设备:Zebra ET40
- DataWedge版本:11.3
- 依赖包:
"react-native-datawedge-intents": "^0.1.8"
问题根源
查看你的ZebraScanner组件代码,发现组件卸载时没有清理注册的事件监听器和广播接收器:
- 在
constructor中通过DeviceEventEmitter.addListener添加了datawedge_broadcast_intent的监听器,但未在组件销毁时移除 - 调用
DataWedgeIntents.registerBroadcastReceiver注册了广播接收器,但未注销
每次页面切换,旧的ZebraScanner组件实例被销毁,但监听器和广播接收器依然留存;新实例创建时又会重复注册,导致监听器和广播接收器数量随页面切换次数递增。每次初始化时,DataWedge的广播会被多个监听器处理,最终导致初始化耗时翻倍增长。
修复方案
在ZebraScanner组件中添加componentWillUnmount生命周期方法,清理注册的监听器和广播接收器:
import React, { Component } from 'react'; import { DeviceEventEmitter } from 'react-native'; import DataWedgeIntents from 'react-native-datawedge-intents'; import { EventRegister } from 'react-native-event-listeners'; type Props = { onScanned: Function, }; type State = { ean8checked: boolean, ean13checked: boolean, code39checked: boolean, code128checked: boolean, lastApiVisible: boolean, lastApiText: string, checkBoxesDisabled: boolean, scanButtonVisible: boolean, dwVersionText: string, activeProfileText: string, enumeratedScannersText: string, scans: [], }; export default class ZebraScanner extends Component<Props, State> { sendCommandResult: string; broadcastReceiverHandler: (intent: any) => void; // 保存监听器引用,方便后续移除 datawedgeListener: any; constructor(props: Props) { super(props) this.state = { ean8checked: true, ean13checked: true, code39checked: true, code128checked: true, lastApiVisible: false, lastApiText: "Messages from DataWedge will go here", checkBoxesDisabled: true, scanButtonVisible: false, dwVersionText: "Pre 6.3. Please create and configure profile manually. See the ReadMe for more details", activeProfileText: "Requires DataWedge 6.3+", enumeratedScannersText: "Requires DataWedge 6.3+", scans: [], }; this.sendCommandResult = "false"; this.broadcastReceiverHandler = (intent) => { this.broadcastReceiver(intent); } // 保存监听器引用 this.datawedgeListener = DeviceEventEmitter.addListener('datawedge_broadcast_intent', this.broadcastReceiverHandler); this.registerBroadcastReceiver(); this.determineVersion(); } // 组件卸载时清理资源 componentWillUnmount() { // 移除DeviceEventEmitter监听器 if (this.datawedgeListener) { this.datawedgeListener.remove(); } // 注销广播接收器 DataWedgeIntents.unregisterBroadcastReceiver(); } _onPressScanButton() { this.sendCommand("com.symbol.datawedge.api.SOFT_SCAN_TRIGGER", 'TOGGLE_SCANNING'); } determineVersion() { this.sendCommand("com.symbol.datawedge.api.GET_VERSION_INFO", ""); } setDecoders() { var profileConfig = { "PROFILE_NAME": "ScannerDemo", "PROFILE_ENABLED": "true", "CONFIG_MODE": "UPDATE", "PLUGIN_CONFIG": { "PLUGIN_NAME": "BARCODE", "PARAM_LIST": { "scanner_selection": "auto", "decoder_ean8": "" + this.state.ean8checked, "decoder_ean13": "" + this.state.ean13checked, "decoder_code128": "" + this.state.code128checked, "decoder_code39": "" + this.state.code39checked } } }; this.sendCommand("com.symbol.datawedge.api.SET_CONFIG", profileConfig); } sendCommand(extraName: string, extraValue: any) { const broadcastExtras: any = {}; broadcastExtras[extraName] = extraValue; broadcastExtras["SEND_RESULT"] = this.sendCommandResult; DataWedgeIntents.sendBroadcastWithExtras({ action: "com.symbol.datawedge.api.ACTION", extras: broadcastExtras }); } registerBroadcastReceiver() { DataWedgeIntents.registerBroadcastReceiver({ filterActions: [ 'com.zebra.reactnativedemo.ACTION', 'com.symbol.datawedge.api.RESULT_ACTION' ], filterCategories: [ 'android.intent.category.DEFAULT' ] }); } broadcastReceiver(intent: any) { if (intent.hasOwnProperty('RESULT_INFO')) { const commandResult = intent.RESULT + " (" + intent.COMMAND.substring(intent.COMMAND.lastIndexOf('.') + 1, intent.COMMAND.length) + ")"; this.commandReceived(commandResult.toLowerCase()); } if (intent.hasOwnProperty('com.symbol.datawedge.api.RESULT_GET_VERSION_INFO')) { const versionInfo = intent['com.symbol.datawedge.api.RESULT_GET_VERSION_INFO']; const datawedgeVersion = versionInfo['DATAWEDGE']; if (datawedgeVersion >= "11.3") this.datawedge113(); this.setState(this.state); } else if (intent.hasOwnProperty('com.symbol.datawedge.api.RESULT_ENUMERATE_SCANNERS')) { const enumeratedScannersObj = intent['com.symbol.datawedge.api.RESULT_ENUMERATE_SCANNERS']; this.enumerateScanners(enumeratedScannersObj); } else if (intent.hasOwnProperty('com.symbol.datawedge.api.RESULT_GET_ACTIVE_PROFILE')) { const activeProfileObj = intent['com.symbol.datawedge.api.RESULT_GET_ACTIVE_PROFILE']; this.activeProfile(activeProfileObj); } else if (!intent.hasOwnProperty('RESULT_INFO')) { this.barcodeScanned(intent, new Date().toLocaleString()); } } datawedge113() { this.sendCommand("com.symbol.datawedge.api.CREATE_PROFILE", "ScannerDemo"); this.setState({ dwVersionText: "11.3", checkBoxesDisabled: false }); var profileConfig = { "PROFILE_NAME": "ScannerDemo", "PROFILE_ENABLED": "true", "CONFIG_MODE": "UPDATE", "PLUGIN_CONFIG": { "PLUGIN_NAME": "BARCODE", "RESET_CONFIG": "true", "PARAM_LIST": { "configure_all_scanners": 'true', "scanner_input_enabled": 'true', "aim_type": '3', "EXTRA_DATA": { "aim_type": '3', } } }, "APP_LIST": [{ "PACKAGE_NAME": "com.datawedgereactnative.demo", "ACTIVITY_LIST": ["*"] }, { "PACKAGE_NAME": "com.demo", "ACTIVITY_LIST": ["*"] }] }; this.sendCommand("com.symbol.datawedge.api.SET_CONFIG", profileConfig); var profileConfig2 = { "PROFILE_NAME": "ScannerDemo", "PROFILE_ENABLED": "true", "CONFIG_MODE": "UPDATE", "PLUGIN_CONFIG": { "PLUGIN_NAME": "INTENT", "RESET_CONFIG": "true", "PARAM_LIST": { "intent_output_enabled": "true", "intent_action": "com.zebra.reactnativedemo.ACTION", "intent_delivery": "2" } } }; this.sendCommand("com.symbol.datawedge.api.SET_CONFIG", profileConfig2); setTimeout(() => { this.sendCommand("com.symbol.datawedge.api.GET_ACTIVE_PROFILE", ""); this.sendCommand("com.symbol.datawedge.api.ENUMERATE_SCANNERS", ""); }, 1000); } commandReceived(commandText: string) { this.setState({ lastApiText: commandText }); this.setState(this.state); } enumerateScanners(enumeratedScanners: any) { let humanReadableScannerList: string = ""; for (let i = 0; i < enumeratedScanners.length; i++) { humanReadableScannerList += enumeratedScanners[i].SCANNER_NAME; if (i < enumeratedScanners.length - 1) humanReadableScannerList += ", "; } this.setState({ enumeratedScannersText: humanReadableScannerList, }) } activeProfile(theActiveProfile: any) { this.setState({ activeProfileText: theActiveProfile }); this.setState(this.state); } barcodeScanned(scanData: any, timeOfScan: any) { const scannedData = scanData["com.symbol.datawedge.data_string"]; EventRegister.emit('barcode_scanned', scannedData); } render() { return (<></>); } }
额外优化建议
- 避免重复创建DataWedge配置:当前
datawedge113方法每次组件初始化都会重新创建和配置ScannerDemoprofile,可添加判断逻辑,仅在profile不存在时执行创建配置操作,减少不必要的DataWedge交互 - 简化状态更新:代码中多处出现
this.setState(this.state)的无效更新,可直接移除,避免不必要的组件重渲染
内容的提问来源于stack exchange,提问作者Shailesh Daund
相关产品推荐
相关产品推荐

