Flutter開發犯蠢日誌 – 訂閱後資料卻不會更新

有三種可能原因

  1. Provider 的範圍
  2. 狀態更新通知
  3. 畫面重建

Provider 的範圍:確保 Provider 的範圍覆蓋了所有需要共享狀態的畫面。如果 Provider 的範圍僅限於某個特定的畫面,那麼其他畫面將無法看到狀態的變化。

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => AppProvider(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}
class AppProvider extends ChangeNotifier {
  List<TaskModel> _tasks = [];

  List<TaskModel> get tasks => _tasks;

  void addTask(TaskModel task) {
    _tasks.add(task);
    notifyListeners();
  }

  void updateTask(TaskModel updatedTask) {
    int index = _tasks.indexWhere((task) => task.taskId == updatedTask.taskId);
    if (index != -1) {
      _tasks[index] = updatedTask;
      notifyListeners();
    }
  }

  void removeTask(String taskId) {
    _tasks.removeWhere((task) => task.taskId == taskId);
    notifyListeners();
  }
}

狀態更新通知:確保在更新 tasks 列表後,調用了 notifyListeners() 方法來通知所有訂閱者狀態已經改變。

畫面重建:確保畫面在 Provider 的狀態變化時正確地重建。如果畫面沒有重建,則無法看到狀態的變化。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class WorkModeHomePage extends StatefulWidget {
  @override
  _WorkModeHomePageState createState() => _WorkModeHomePageState();
}

class _WorkModeHomePageState extends State<WorkModeHomePage> {
  @override
  void initState() {
    super.initState();
    // tasks = Provider.of<AppProvider>().initailLoading();
    //   ..sort((a, b) => (a.priority ?? 0).compareTo(b.priority ?? 0));
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: SingleChildScrollView(
        child: Container(
          padding: EdgeInsets.fromLTRB(12, 12, 12, 0),
          width: double.maxFinite,
          decoration: BoxDecoration(
            borderRadius: BorderRadiusStyle.roundedBorder10,
          ),
          child: Column(
            children: [
              Consumer<AppProvider>(
                builder: (context, provider, child) {
                  List<TaskModel> tasks = provider.tasks
                    ..sort((a, b) {
                      int aPriority = a.priority ?? double.maxFinite.toInt();
                      int bPriority = b.priority ?? double.maxFinite.toInt();
                      return aPriority.compareTo(bPriority);
                    });
                  return Column(
                    children: List.generate(tasks.length, (index) {
                      DateTime nowDate = DateTime.now().getDate();
                      DateTime? taskDate = tasks[index].doDate?.getDate();
                      final taskExecutesWhereTaskId = provider.taskExcutes
                          .where((execute) => execute.taskId == tasks[index].taskId)
                          .toList();
                      taskExecutesWhereTaskId.sort((a, b) => b.createdAt!.compareTo(a.createdAt!));
                      List<TaskExecuteViewmodel> taskExecuteViewmodels = [];
                      for (int i = 0; i < taskExecutesWhereTaskId.length; i++) {
                        taskExecuteViewmodels.add(toTaskExecuteViewmodel(taskExecutesWhereTaskId[i]));
                      }
                      if (taskDate == nowDate && tasks[index].taskStatus == TaskStatusEnum.todo.index) {
                        return ListTile(
                          title: Text(tasks[index].title),
                          subtitle: Text('Priority: ${tasks[index].priority}'),
                        );
                      }
                      return Container();
                    }),
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}