Skip to content

Tasks scheduled through 'SchedulerBinding.instance.scheduleTask' were not executed #82016

@Nayuta403

Description

@Nayuta403

Issue

example :https://dartpad.dev/8944b568287269991e5b943accf16861?null_safety=true

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

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

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: animationAnimation APIsfound in release: 2.10Found to occur in 2.10found in release: 2.13Found to occur in 2.13frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions