HTML页面Observable数据不更新:NFC标签读取适配问题
NativeScript NFC UI更新延迟问题(HTML页面适配)
问题描述
我正在开发一款具备NFC功能的NativeScript应用,将原XML页面改为HTML页面后遇到了UI更新延迟的问题:
- 设置了启动Ndef监听器的按钮,预期检测到NFC标签时,页面Label会从“Listening...”变为“Read: TagMessage”
- 实际情况是标签检测完成后,Label内容不会即时更新,只有按下其他按钮时才会显示最新内容
- 使用
nativescript-nfc插件的演示程序在XML页面中可正常运行,但HTML页面适配后出现该问题
原始代码片段
HTML代码
<StackLayout> <Button text="Available?" (tap)="this.doCheckAvailable()"></Button> <Button text="Enabled?" (tap)="this.doCheckEnabled()"></Button> <Button text="Start listening" (tap)="this.doStartNdefListener()"></Button> <Button text="Stop listening" (tap)="this.doStopNdefListener()"></Button> <Label text="{{this.lastNdefDiscovered}}" textWrap="true"></Label> </StackLayout>
TypeScript代码
import { observable } from '@nativescript/core'; import { ActivatedRoute, RouterExtensions } from '@nativescript/angular'; import { Nfc, NfcNdefData } from 'nativescript-nfc'; import { application } from '@nativescript/core'; export class NFCReaderComponent extends observable.Observable { public lastNdefDiscovered: string = "Press a button..."; private nfc: Nfc; constructor( private route: ActivatedRoute, private router: RouterExtensions, ) { super(); this.nfc = new Nfc(); } public ngOnInit() { application.android.on( application.AndroidApplication.activityBackPressedEvent, (args:any) => { args.cancel = true; this.router.navigate(['/home'], { transition: { name: 'slideTop' }, clearHistory: true }) } ); } public doCheckAvailable() { this.nfc.available().then((avail) => { console.log("Available? " + avail); alert("" + avail); }, (err) => { alert(err); }); } public doCheckEnabled() { this.nfc.enabled().then((on) => { console.log("Enabled? " + on); alert("" + on); }, (err) => { alert(err); }); } public doStartNdefListener() { this.lastNdefDiscovered= ""; this.nfc.setOnNdefDiscoveredListener((data: NfcNdefData) => { if (data.message) { let tagMessages = []; data.message.forEach(record => { console.log("Read record: " + JSON.stringify(record)); tagMessages.push(record.payloadAsString); }); this.set("lastNdefDiscovered", "Read: " + tagMessages.join(", ")); } }, { stopAfterFirstRead: true, scanHint: "Scan a tag, baby!" }) .then( ()=>this.set("lastNdefDiscovered","Listening...") ) .catch(err => alert(err)); } public doStopNdefListener() { this.nfc.setOnNdefDiscoveredListener(null).then(() => { this.set("lastNdefDiscovered", "Stopped listening."); }, (err) => { alert(err); }); } }
问题原因
在NativeScript Angular环境中,nativescript-nfc插件的回调函数运行在Angular变更检测上下文之外。这意味着当你在回调中更新lastNdefDiscovered时,Angular不会自动触发UI更新,只有当其他用户交互(比如点击按钮)触发变更检测时,UI才会同步最新值。
解决方案:使用NgZone触发变更检测
通过NgZone将UI更新逻辑拉回Angular的变更检测上下文即可解决问题,具体修改如下:
修改后的TypeScript关键代码
import { NgZone } from '@angular/core'; // 引入NgZone export class NFCReaderComponent extends observable.Observable { public lastNdefDiscovered: string = "Press a button..."; private nfc: Nfc; constructor( private route: ActivatedRoute, private router: RouterExtensions, private _ngZone: NgZone, // 注入NgZone服务 ) { super(); this.nfc = new Nfc(); } public doStartNdefListener() { this.lastNdefDiscovered= "Listening..."; // 把监听器放在Angular上下文外,避免不必要的变更检测 this._ngZone.runOutsideAngular(()=> { this.nfc.setOnNdefDiscoveredListener((data: NfcNdefData) => { if (data.message) { let tagMessages = []; data.message.forEach(record => { console.log("Read record: " + JSON.stringify(record)); tagMessages.push(record.payloadAsString); }); // 仅在需要更新UI时,回到Angular上下文触发变更检测 this._ngZone.run(() => { this.set("lastNdefDiscovered", "Read: " + tagMessages.join(", ")); console.log("lastNdef updated..."); }); } }, { stopAfterFirstRead: true, scanHint: "Scan a tag, baby!" }) }); } }
效果验证
修改后,当检测到NFC标签时,Label内容会即时更新为读取到的标签信息,无需再点击其他按钮触发UI同步。
内容的提问来源于stack exchange,提问作者Jander Friebe
相关产品推荐
相关产品推荐

