Flutter:解决Awesome Notifications按钮点击时SharedPreferences读写失败问题
问题分析与解决方案
问题原因
@pragma("vm:entry-point")标记的函数并非不能使用第三方包,但它运行在Flutter的独立后台Isolate中。SharedPreferences插件在每个Isolate内会初始化独立的实例,后台Isolate的实例无法同步前台Isolate存储的数据,因此直接调用SharedPreferences.getInstance()会读取到一个空的、未同步的实例,导致拿不到之前存储的数据。
解决方案
方案一:通过Isolate通信在主Isolate中处理SharedPreferences操作
利用Isolate间的SendPort/ReceivePort通信,让后台Isolate请求主Isolate执行SharedPreferences读写操作,再返回结果。
- 主Isolate中建立通信通道:
import 'dart:isolate'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; SendPort? _mainIsolateSendPort; void main() async { WidgetsFlutterBinding.ensureInitialized(); // 创建ReceivePort监听后台Isolate请求 final receivePort = ReceivePort(); _mainIsolateSendPort = receivePort.sendPort; receivePort.listen((message) async { if (message is Map && message['type'] == 'get_pinned_data') { // 在主Isolate中执行SharedPreferences读取 final prefs = await SharedPreferences.getInstance(); final pinnedString = prefs.getString('pinnedKey'); // 将结果返回给后台Isolate (message['sendPort'] as SendPort).send(pinnedString); } }); runApp(const MyApp()); }
- 后台entry-point函数中发起请求:
import 'dart:isolate'; import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:flutter/foundation.dart'; @pragma("vm:entry-point") static Future<void> onActionReceivedMethod(ReceivedAction action) async { print('It works'); print(action.toMap()); if (_mainIsolateSendPort != null) { final receivePort = ReceivePort(); // 向主Isolate发送读取请求 _mainIsolateSendPort!.send({ 'type': 'get_pinned_data', 'sendPort': receivePort.sendPort, }); // 等待主Isolate返回结果 final result = await receivePort.first; if (result is String) { try { final pinnedList = PinnedFolder.decode(result); print('PinnedList got from memory, length: ${pinnedList.first.pinnedList.length}'); } catch (error) { debugPrint('Error: couldnt get pinned folders: $error'); } } receivePort.close(); } else { debugPrint('Main Isolate communication port not initialized'); } }
方案二:延迟到应用下次前台启动时处理(更简单)
如果不需要立即执行操作,可以将通知操作信息保存到本地文件,等应用启动后再读取并处理SharedPreferences操作。
- 后台函数中保存操作日志:
import 'dart:io'; import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:path_provider/path_provider.dart'; import 'dart:convert'; @pragma("vm:entry-point") static Future<void> onActionReceivedMethod(ReceivedAction action) async { print('It works'); print(action.toMap()); try { // 获取应用文档目录 final dir = await getApplicationDocumentsDirectory(); final logFile = File('${dir.path}/notification_actions.log'); // 将操作信息转为JSON追加写入文件 final actionJson = jsonEncode(action.toMap()); await logFile.writeAsString('${DateTime.now().toIso8601String()}:$actionJson\n', mode: FileMode.append); } catch (error) { debugPrint('Failed to save action log: $error'); } }
- 应用启动时读取并处理日志:
import 'dart:io'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // 处理之前保存的通知操作 await processNotificationActions(); runApp(const MyApp()); } Future<void> processNotificationActions() async { try { final dir = await getApplicationDocumentsDirectory(); final logFile = File('${dir.path}/notification_actions.log'); if (await logFile.exists()) { final content = await logFile.readAsString(); final lines = content.split('\n').where((line) => line.isNotEmpty).toList(); for (final line in lines) { final parts = line.split(':'); if (parts.length >=2) { final actionMap = jsonDecode(parts.sublist(1).join(':')); final action = ReceivedAction.fromMap(actionMap); // 执行SharedPreferences操作逻辑 final prefs = await SharedPreferences.getInstance(); final pinnedString = prefs.getString('pinnedKey'); if (pinnedString != null) { final pinnedList = PinnedFolder.decode(pinnedString); print('Processed action: PinnedList length ${pinnedList.first.pinnedList.length}'); } } } // 处理完成后清空日志文件 await logFile.writeAsString(''); } } catch (error) { debugPrint('Failed to process action log: $error'); } }
内容的提问来源于stack exchange,提问作者pulle
相关产品推荐
相关产品推荐

