You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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读写操作,再返回结果。

  1. 主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());
}
  1. 后台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操作。

  1. 后台函数中保存操作日志:
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');
  }
}
  1. 应用启动时读取并处理日志:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:40:31