Flutter使用smswatcher时StreamBuilder不更新问题求助
Flutter SMS监听问题:StreamBuilder一直处于waiting状态
问题描述
使用smswatcher包监听短信,后台通过flutter_background_service能正常收到短信并打印,但前端的StreamBuilder始终停在connectionState.waiting状态,完全不响应流推送的数据。
相关代码
home_page.dart
import 'package:namer_app/sms_service.dart'; ... StreamBuilder( stream: SmsService().getSmsStream(), // 获取收到的短信 builder: (context, snap) { if (snap.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); // 显示加载指示器 } else if (snap.hasError) { return Text('Error: ${snap.error}'); // 处理错误 } else if (snap.hasData) { return ListTile( title: Text(snap.data?["sender"] ?? "NA"), subtitle: Text(snap.data?["body"] + dateTimeString ?? "NA"), ); } else { return Text("No SMS available"); // 处理无数据状态 } } ),
sms_service.dart
// 外部导入包 import 'dart:async'; import 'package:smswatcher/smswatcher.dart'; // SmsService类 class SmsService { final smsWatcher = Smswatcher(); // 初始化SmsWatcher late StreamSubscription smsSubscription; // 处理短信流 // 开始监听收到的短信 Stream<Map<String, dynamic>> getSmsStream() { return smsWatcher.getStreamOfSMS().map((sms) { return { "sender": sms["sender"] ?? "NA", "body": sms["body"] ?? "NA", "timestamp": sms["timestamp"] ?? DateTime.now().toString(), // 若不存在则添加时间戳 }; }); } }
background_services.dart
... @pragma('vm:entry-point') void onStart(ServiceInstance service) async { DartPluginRegistrant.ensureInitialized(); switch (service.runtimeType) { case AndroidServiceInstance: // 处理安卓特定服务 // 监听短信流 SmsService().getSmsStream().listen((smsData) async { sender = smsData['sender']; body = smsData['body']; print("$sender $body"); }); ...
问题原因
每次调用SmsService().getSmsStream()都会创建一个全新的SmsService实例,导致:
- 前端StreamBuilder订阅的是独立的流实例
- 后台监听的是另一个完全不同的流实例
两者无关联,后台收到短信时前端流根本没收到数据,一直处于等待状态。
解决方案
1. 将SmsService改为单例模式
确保全局只有一个SmsService实例,让UI和后台共享同一个流:
修改sms_service.dart:
import 'dart:async'; import 'package:smswatcher/smswatcher.dart'; class SmsService { // 全局唯一的单例实例 static final SmsService _instance = SmsService._internal(); factory SmsService() => _instance; SmsService._internal(); final smsWatcher = Smswatcher(); late StreamSubscription smsSubscription; Stream<Map<String, dynamic>> getSmsStream() { return smsWatcher.getStreamOfSMS().map((sms) { return { "sender": sms["sender"] ?? "NA", "body": sms["body"] ?? "NA", "timestamp": sms["timestamp"] ?? DateTime.now().toString(), }; }); } }
2. 调整前端StreamBuilder的调用方式
在页面中使用同一个单例实例的流,避免每次重建都创建新对象:
修改home_page.dart:
import 'package:namer_app/sms_service.dart'; // 页面内初始化单例实例 final smsService = SmsService(); ... StreamBuilder( stream: smsService.getSmsStream(), // 使用全局唯一的流 builder: (context, snap) { if (snap.connectionState == ConnectionState.waiting || !snap.hasData) { return Text("暂无短信"); // 替换加载指示器,避免一直转圈 } else if (snap.hasError) { return Text('错误: ${snap.error}'); } else { final dateTimeString = snap.data?["timestamp"] ?? ""; return ListTile( title: Text(snap.data?["sender"] ?? "NA"), subtitle: Text('${snap.data?["body"] ?? "NA"} $dateTimeString'), ); } } ),
3. 可选:优化流的初始状态
如果不想让StreamBuilder一直显示加载状态,可以给流添加初始数据(需依赖rxdart包):
在sms_service.dart中修改:
// 先添加依赖:dependencies: rxdart: ^0.27.7 import 'package:rxdart/rxdart.dart'; ... Stream<Map<String, dynamic>> getSmsStream() { return smsWatcher.getStreamOfSMS() .map((sms) => { "sender": sms["sender"] ?? "NA", "body": sms["body"] ?? "NA", "timestamp": sms["timestamp"] ?? DateTime.now().toString(), }) .startWith({"sender": "NA", "body": "暂无短信", "timestamp": ""}); }
这样StreamBuilder一开始就能收到初始数据,不会停在waiting状态。
内容的提问来源于stack exchange,提问作者Kiostz
相关产品推荐
相关产品推荐

