-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Issue
I start the animation during initialization and then execute the task . After the animation ends, the task is not executed.
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this, duration: Duration(milliseconds: 3000));
animation = Tween(begin: 1.0, end: 0.0).animate(animationController);
// start an animation
animationController.forward();
// These task will be blocked even if the animation ends
SchedulerBinding.instance!.scheduleTask(task1, Priority.idle);
SchedulerBinding.instance!.scheduleTask(task2, Priority.idle);
}Expected results:
Task1 and Task2 are executed after the animation ends
Actual results:
After the animation ends, the task is not executed.
My point of view:
I notice that task1 and task2 are added to _taskQueue for scheduling here
flutter/packages/flutter/lib/src/scheduler/binding.dart
Lines 427 to 441 in 3ab799b
| void _ensureEventLoopCallback() { | |
| assert(!locked); | |
| assert(_taskQueue.isNotEmpty); | |
| if (_hasRequestedAnEventLoopCallback) | |
| return; | |
| _hasRequestedAnEventLoopCallback = true; | |
| Timer.run(_runTasks); | |
| } | |
| // Scheduled by _ensureEventLoopCallback. | |
| void _runTasks() { | |
| _hasRequestedAnEventLoopCallback = false; | |
| if (handleEventLoopCallback()) | |
| _ensureEventLoopCallback(); // runs next task when there's time | |
| } |
The problem is that once the handleEventLoopCallback() returns false, the _TaskQueue will not be scheduled again until the next scheduleTask.
In this case, because the Priority of the two tasks is Priority.idle, the schedulingStrategy returns false
flutter/packages/flutter/lib/src/scheduler/binding.dart
Lines 455 to 463 in 3ab799b
| bool handleEventLoopCallback() { | |
| if (_taskQueue.isEmpty || locked) | |
| return false; | |
| final _TaskEntry<dynamic> entry = _taskQueue.first; | |
| if (schedulingStrategy(priority: entry.priority, scheduler: this)) { | |
| try { | |
| _taskQueue.removeFirst(); | |
| entry.run(); | |
| } catch (exception, exceptionStack) { |
So task1 and task2 are still blocked after the animation ends
I try to modify these method like this :
void _ensureEventLoopCallback() {
assert(!locked);
assert(_taskQueue.isNotEmpty);
if (_hasRequestedAnEventLoopCallback)
return;
_hasRequestedAnEventLoopCallback = true;
print('_ensureEventLoopCallback execute');
Timer.run(_runTasks);
}
// Scheduled by _ensureEventLoopCallback.
void _runTasks() {
_hasRequestedAnEventLoopCallback = false;
if (handleEventLoopCallback())
_ensureEventLoopCallback();
else{
// When the execution fails, determines if the queue is empty
if(_taskQueue.isNotEmpty){
// When the task queue is not empty, the judgment is made again
_ensureEventLoopCallback();
}
} // runs next task when there's time
}When the task queue is not empty, the judgment is made again, just like Event loop
In the above example, tasks 1 and 2 were successfully executed after the animation ended
However, through logging, I found that _ensureEventLoopCallback() was called too frequently. Because the Timer.run will continue to add tasks to the isolate while the _taskQueue is not empty
However, I don't think this is necessary, because the result of the schedulingStrategy will not change until the next frame is drawn
So i modify _ensureEventLoopCallback() like this:
// Ensures that the scheduler services a task scheduled by [scheduleTask].
void _ensureEventLoopCallback() async{
assert(!locked);
assert(_taskQueue.isNotEmpty);
if (_hasRequestedAnEventLoopCallback)
return;
_hasRequestedAnEventLoopCallback = true;
print('_ensureEventLoopCallback execute');
// Executes after each frame is rendered
await endOfFrame;
_runTasks();
}At the end of each frame, the _taskQueue is scheduled .
And tasks 1 and 2 were also successfully executed after the animation ended
What do you think, if this change is necessary, I can PR to fix it
[✓] Flutter (Channel stable, 2.0.6, on macOS 11.2.2 20D80 darwin-x64, locale zh-Hans-CN)
• Flutter version 2.0.6 at /Users/nayuta/Desktop/fsdk/flutter2.0
• Framework revision 1d9032c7e1 (7 days ago), 2021-04-29 17:37:58 -0700
• Engine revision 05e680e202
• Dart version 2.12.3
• Pub download mirror http://pub.ke.com
• Flutter download mirror https://storage.flutter-io.cn