如何通过WorkManager修改TaskProvider中的任务列表?
问题分析
WorkManager的回调运行在独立的后台隔离进程,和主APP进程完全分离:你在后台新建的TaskProvider实例,和UI层依赖的实例不是同一个对象,后台修改的只是独立内存中的数据,自然无法同步到主进程的UI。
可行解决方案
核心思路是通过持久化存储共享任务数据,后台直接修改磁盘数据,主进程监听数据变化或在合适时机同步更新。
步骤1:给TaskProvider添加持久化逻辑
用shared_preferences(或Hive、SQLite)将任务列表持久化到磁盘,确保前后台数据一致。首先给TaskModel实现序列化/反序列化:
enum TaskStatus { pending, completed } class TaskModel { final String task; final DateTime limitDateTime; final TaskStatus status; TaskModel({ required this.task, required this.limitDateTime, required this.status, }); // 转JSON用于存储 Map<String, dynamic> toJson() => { 'task': task, 'limitDateTime': limitDateTime.toIso8601String(), 'status': status.name, }; // 从JSON解析 factory TaskModel.fromJson(Map<String, dynamic> json) => TaskModel( task: json['task'], limitDateTime: DateTime.parse(json['limitDateTime']), status: TaskStatus.values.byName(json['status']), ); }
修改TaskProvider,整合持久化逻辑:
import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class TaskProvider extends ChangeNotifier { final List<TaskModel> _tasks = []; final String _tasksKey = "tasks"; final SharedPreferences _prefs; // 构造函数注入SharedPreferences TaskProvider(this._prefs) { _loadTasks(); } List<TaskModel> get tasks => _tasks; // 从磁盘加载任务 Future<void> _loadTasks() async { final String? tasksJson = _prefs.getString(_tasksKey); if (tasksJson != null) { final List<dynamic> decoded = jsonDecode(tasksJson); _tasks.clear(); _tasks.addAll(decoded.map((e) => TaskModel.fromJson(e)).toList()); notifyListeners(); } } // 保存任务到磁盘 Future<void> _saveTasks() async { final String tasksJson = jsonEncode(_tasks.map((e) => e.toJson()).toList()); await _prefs.setString(_tasksKey, tasksJson); } Future<void> addTask({ required String task, required DateTime scheduledTime, required TaskStatus status, }) async { scheduleTaskManager(task, scheduledTime); _tasks.add(TaskModel(task: task, limitDateTime: scheduledTime, status: status)); await _saveTasks(); notifyListeners(); } Future<void> clearTasks() async { dev.log("Tasks deleted!"); _tasks.clear(); await _saveTasks(); notifyListeners(); } }
步骤2:修改WorkManager回调,直接操作持久化存储
后台不需要实例化TaskProvider,直接修改磁盘上的任务数据:
import 'package:shared_preferences/shared_preferences.dart'; @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { dev.log("Native called background task: $task"); dev.log("Time limit, clearing all tasks!"); // 直接清除磁盘中的任务数据 final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.remove("tasks"); return Future.value(true); }); }
步骤3:主进程同步数据更新
有两种方式让主进程感知后台的数据变化:
方式1:APP回到前台时自动刷新
通过监听APP生命周期,在回到前台时重新加载任务:
class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> with WidgetsBindingObserver { late TaskProvider _taskProvider; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _taskProvider = Provider.of<TaskProvider>(context, listen: false); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); // APP回到前台时重新加载任务 if (state == AppLifecycleState.resumed) { _taskProvider._loadTasks(); } } @override Widget build(BuildContext context) { // 你的UI代码... } }
方式2:跨进程通信实时更新
如果需要后台修改后立刻更新UI,用MethodChannel实现前后台通信:
- 主进程初始化MethodChannel并监听消息:
import 'package:flutter/services.dart'; class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { static const platform = MethodChannel('com.yourpackage/task_updates'); late TaskProvider _taskProvider; @override void initState() { super.initState(); _taskProvider = Provider.of<TaskProvider>(context, listen: false); // 监听后台发送的更新消息 platform.setMethodCallHandler((call) async { if (call.method == 'tasksCleared') { await _taskProvider._loadTasks(); } }); } @override Widget build(BuildContext context) { return MaterialApp(/* ... */); } }
- 后台任务完成后发送消息:
import 'package:flutter/services.dart'; @pragma('vm:entry-point') void callbackDispatcher() { Workmanager().executeTask((task, inputData) async { dev.log("Native called background task: $task"); dev.log("Time limit, clearing all tasks!"); final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.remove("tasks"); // 发送消息通知主进程更新 const platform = MethodChannel('com.yourpackage/task_updates'); try { await platform.invokeMethod('tasksCleared'); } on PlatformException catch (e) { dev.log("Failed to send update: ${e.message}"); } return Future.value(true); }); }
内容的提问来源于stack exchange,提问作者Yasuki
相关产品推荐
相关产品推荐

