在Flutter中,异步任务主要是通过Timer及微任务来实现。在Flutter之Timer原理解析一文中,讲述了通过Timer来实现异步任务的原理,那么本文就来看异步任务的另一种实现,微任务的使用及其实现原理。
1、微任务的使用
先来看微任务的使用,代码很简单,如下。
//用法一
Future.microtask(() {
print("microtask1");
});
//用法二
scheduleMicrotask(() {
print("microtask2");
});
//用法三
Zone.current.scheduleMicrotask((){
print("microtask3");
});
//用法四
Zone.root.scheduleMicrotask((){
print("microtask4");
});
以上就是微任务的所有用法。基本上都是前两种使用方式比较多,但前面两种用法仅是对后面两种用法的封装而已。下面就来看微任务的实现原理,不过在分析微任务的实现原理之前需要先了解一下UI线程是如何创建的。
2、UI线程的创建
在Flutter之Engine启动流程一文中,提过在Engine创建过程中会创建UI线程、IO线程及GPU线程,但未深入。所以这里就以Android平台为例来深入的来了解Flutter中UI线程是如何创建的(IO线程、GPU线程与UI线程都是同一类型的对象,但命名不同)。
[-> flutter/shell/platform/android/android_shell_holder.cc]
AndroidShellHolder::AndroidShellHolder(
flutter::Settings settings,
fml::jni::JavaObjectWeakGlobalRef java_object,
bool is_background_view)
: settings_(std::move(settings)), java_object_(java_object) {
static size_t shell_count = 1;
auto thread_label = std::to_string(shell_count++);
//创建目标线程
if (is_background_view) {
//仅创建UI线程
thread_host_ = {thread_label, ThreadHost::Type::UI};
} else {
//创建UI线程、GPU线程及IO线程
thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU |
ThreadHost::Type::IO};
}
...
}
这里的thread_host_是一个结构体,所以直接来看该结构体中的具体实现。
[-> flutter/shell/common/thread_host.cc]
#include "flutter/shell/common/thread_host.h"
namespace flutter {
...
ThreadHost::ThreadHost(std::string name_prefix, uint64_t mask) {
if (mask & ThreadHost::Type::Platform) {
//Platform线程的创建,在Android中,由于Platform线程是Android中的主线程,所以名称为xxxx.platform的platform_thread不会创建
platform_thread = std::make_unique<fml::Thread>(name_prefix + ".platform");
}
if (mask & ThreadHost::Type::UI) {
//ui线程的创建
ui_thread = std::make_unique<fml::Thread>(name_prefix + ".ui");
}
if (mask & ThreadHost::Type::GPU) {
//gpu线程的创建
gpu_thread = std::make_unique<fml::Thread>(name_prefix + ".gpu");
}
if (mask & ThreadHost::Type::IO) {
//io线程的创建
io_thread = std::make_unique<fml::Thread>(name_prefix + ".io");
}
}
...
}
从上面就可以看出ui线程、io线程及GPU线程是同一类型的对象,但命名不同。那么再来看UI线程的具体实现。
[-> flutter/fml/thread.cc]
Thread::Thread(const std::string& name) : joined_(false) {
fml::AutoResetWaitableEvent latch;
fml::RefPtr<fml::TaskRunner> runner;
//创建一个thread对象
thread_ = std::make_unique<std::thread>([&latch, &runner, name]() -> void {
//设置当前线程名称,由于这里是UI线程的创建,所以name是xxx.ui
SetCurrentThreadName(name);
//创建一个MessageLoop对象
fml::MessageLoop::EnsureInitializedForCurrentThread();
//获取MessageLoop对应的loop
auto& loop = MessageLoop::GetCurrent();
runner = loop.GetTaskRunner();
//唤醒
latch.Signal();
//运行loop
loop.Run();
});
//等待
latch.Wait();
task_runner_ = runner;
}
在Thread的构造函数中,会创建一个新线程。在该线程创建成功后,会给线程设置名称,如xxxxx.ui、xxxxx.gpu、xxxxx.io等。还会给该线程设置一个MessageLoop对象,最后再来执行MessageLoop的run函数,即使MessageLoop跑起来。
这里重点来看MessageLoop对象的创建,它的实现如下。
[-> flutter/fml/message_loop.cc]
//tls_message_loop类似Java中的ThreadLocal,用来保证MessageLoop仅属于某个线程,其他线程不可访问该MessageLoop
FML_THREAD_LOCAL ThreadLocalUniquePtr<MessageLoop> tls_message_loop;
void MessageLoop::EnsureInitializedForCurrentThread() {
//保证每个进行仅有一个MessageLoop对象
if (tls_message_loop.get() != nullptr) {
// Already initialized.
return;
}
tls_message_loop.reset(new MessageLoop());
}
//创建MessageLoop对象
MessageLoop::MessageLoop()
//MessageLoopImpl对象的创建
: loop_(MessageLoopImpl::Create()),
//TaskRunner对象的创建
task_runner_(fml::MakeRefCounted<fml::TaskRunner>(loop_)) {}
这里重点在loop_。它是一个MessageLoopImpl对象,由于各个平台不同,所以MessageLoopImpl的具体实现也不一样。这里以Android为例,当调用create方法时会创建一个继承自MessageLoopImpl的MessageLoopAndroid对象。
[-> flutter/fml/platform/android/message_loop_android.cc]
static constexpr int kClockType = CLOCK_MONOTONIC;
static ALooper* AcquireLooperForThread() {
ALooper* looper = ALooper_forThread();
if (looper == nullptr) {
//如果当前线程不存在looper,则创建一个新的looper
looper = ALooper_prepare(0);
}
//如果当前线程存在looper,则获取其引用并返回
ALooper_acquire(looper);
return looper;
}
//构造函数
MessageLoopAndroid::MessageLoopAndroid()
//创建一个looper对象
: looper_(AcquireLooperForThread()),
timer_fd_(::timerfd_create(kClockType, TFD_NONBLOCK | TFD_CLOEXEC)),
running_(false) {
static const int kWakeEvents = ALOOPER_EVENT_INPUT;
//执行回调方法
ALooper_callbackFunc read_event_fd = [](int, int events, void* data) -> int {
if (events & kWakeEvents) {
reinterpret_cast<MessageLoopAndroid*>(data)->OnEventFired();
}
return 1; // continue receiving callbacks
};
int add_result = ::ALooper_addFd(looper_.get(), // looper
timer_fd_.get(), // fd
ALOOPER_POLL_CALLBACK, // ident
kWakeEvents, // events
read_event_fd, // callback
this // baton
);
}
MessageLoopAndroid::~MessageLoopAndroid() {
int remove_result = ::ALooper_removeFd(looper_.get(), timer_fd_.get());
FML_CHECK(remove_result == 1);
}
//looper的运行
void MessageLoopAndroid::Run() {
FML_DCHECK(looper_.get() == ALooper_forThread());
running_ = true;
while (running_) {
//等待事件执行
int result = ::ALooper_pollOnce(-1, // infinite timeout
nullptr, // out fd,
nullptr, // out events,
nullptr // out data
);
if (result == ALOOPER_POLL_TIMEOUT || result == ALOOPER_POLL_ERROR) {
// This handles the case where the loop is terminated using ALooper APIs.
running_ = false;
}
}
}
//终止事件执行
void MessageLoopAndroid::Terminate() {
running_ = false;
ALooper_wake(looper_.get());
}
//唤醒事件的执行
void MessageLoopAndroid::WakeUp(fml::TimePoint time_point) {
bool result = TimerRearm(timer_fd_.get(), time_point);
FML_DCHECK(result);
}
//监听Loop的回调函数
void MessageLoopAndroid::OnEventFired() {
if (TimerDrain(timer_fd_.get())) {
RunExpiredTasksNow();
}
}
上面代码其实就是通过ALooper来实现一个异步IO。在Android中,ALooper可以认为是一个对Looper的包装,也就是通过ALooper来操作Looper。
注意:这里所说的ALooper来操作Looper指的是Native层中的Looper,而不是framework层的Looper。
当MessageLoopAndroid对象创建成功后,再调用该对象的run函数使UI线程中的任务处理跑起来。这时候UI线程就成功创建完毕并做了相应的初始化。
以上就是在Android平台中UI线程的创建,而在其他平台,UI线程的创建也与Android平台类似,唯一的不同之处就在于异步IO的实现。比如在iOS中,异步IO是采用CFRunLoop来实现的。
3、微任务实现原理
再回到微任务的实现中。以scheduleMicrotask方法为例,来看其代码实现。
void scheduleMicrotask(void callback()) {
_Zone currentZone = Zone.current;
//当前Zone与_rootZone是否是同一个Zone对象。
if (identical(_rootZone, currentZone)) {
// No need to bind the callback. We know that the root's scheduleMicrotask
// will be invoked in the root zone.
_rootScheduleMicrotask(null, null, _rootZone, callback);
return;
}
...
}
基本上自定义Zone都不会来自定义scheduleMicrotask方法的实现,所以自定义Zone的scheduleMicrotask方法最终都是调用_rootScheduleMicrotask方法。下面就来看该方法的实现。
void _rootScheduleMicrotask(
Zone self, ZoneDelegate parent, Zone zone, void f()) {
...
_scheduleAsyncCallback(f);
}
上面代码很简单,就是调用_scheduleAsyncCallback方法,再来看该方法的实现。
//节点为_AsyncCallbackEntry对象的单链表的头节点
_AsyncCallbackEntry _nextCallback;
//节点为_AsyncCallbackEntry对象的单链表的尾节点
_AsyncCallbackEntry _lastCallback;
//优先级回调方法放在链表的头部,如果存在多个,则按照添加顺序排列
_AsyncCallbackEntry _lastPriorityCallback;
//当前是否在执行回调方法
bool _isInCallbackLoop = false;
//遍历链表并执行相应的回调方法
void _microtaskLoop() {
while (_nextCallback != null) {
_lastPriorityCallback = null;
_AsyncCallbackEntry entry = _nextCallback;
_nextCallback = entry.next;
if (_nextCallback == null) _lastCallback = null;
(entry.callback)();
}
}
//开始执行回调方法
void _startMicrotaskLoop() {
_isInCallbackLoop = true;
try {
// Moved to separate function because try-finally prevents
// good optimization.
_microtaskLoop();
} finally {
_lastPriorityCallback = null;
_isInCallbackLoop = false;
if (_nextCallback != null) {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
}
}
//将回调方法添加到链表中
void _scheduleAsyncCallback(_AsyncCallback callback) {
_AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
if (_nextCallback == null) {
_nextCallback = _lastCallback = newEntry;
//如果当前还未处理回调方法
if (!_isInCallbackLoop) {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
} else {
_lastCallback.next = newEntry;
_lastCallback = newEntry;
}
}
void _schedulePriorityAsyncCallback(_AsyncCallback callback) {
if (_nextCallback == null) {
_scheduleAsyncCallback(callback);
_lastPriorityCallback = _lastCallback;
return;
}
_AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback);
if (_lastPriorityCallback == null) {
entry.next = _nextCallback;
_nextCallback = _lastPriorityCallback = entry;
} else {
entry.next = _lastPriorityCallback.next;
_lastPriorityCallback.next = entry;
_lastPriorityCallback = entry;
if (entry.next == null) {
_lastCallback = entry;
}
}
}
上面代码很简单,在_scheduleAsyncCallback方法中,就是将要执行的微任务包装成一个_AsyncCallbackEntry对象,并将该对象添加到链表中,也就是所有微任务都是链表中的一个节点,当遍历该链表并执行节点中的回调方法即是微任务的执行。
这里要注意一下_schedulePriorityAsyncCallback方法,它也是将微任务包装成一个_AsyncCallbackEntry对象并添加到链表中。但这里的微任务优先级高,是直接将微任务添加到链表的头部。目前仅有当前Zone对象的handleUncaughtError方法中才会调用_schedulePriorityAsyncCallback,也就是捕获错误的优先级比普通微任务的优先级都要高。
链表创建成功后,就需要能够在合适的时机来遍历该链表,这时候就来看_scheduleImmediate方法的执行。
class _AsyncRun {
//这里的callback对应的就是_startMicrotaskLoop方法
external static void _scheduleImmediate(void callback());
}
3.1、微任务集合
来看_scheduleImmediate方法的实现,实现代码很简单,如下。
@patch
class _AsyncRun {
@patch
static void _scheduleImmediate(void callback()) {
if (_ScheduleImmediate._closure == null) {
throw new UnsupportedError("Microtasks are not supported");
}
_ScheduleImmediate._closure(callback);
}
}
typedef void _ScheduleImmediateClosure(void callback());
class _ScheduleImmediate {
static _ScheduleImmediateClosure _closure;
}
//在Engine初始化时调用
@pragma("vm:entry-point", "call")
void _setScheduleImmediateClosure(_ScheduleImmediateClosure closure) {
_ScheduleImmediate._closure = closure;
}
@pragma("vm:entry-point", "call")
void _ensureScheduleImmediate() {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
由于_setScheduleImmediateClosure是在RootIsolate创建成功后的InitDartAsync函数中调用的,所以来看InitDartAsync函数的实现。
[-> flutter/lib/ui/dart_runtime_hooks.cc]
static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate) {
Dart_Handle schedule_microtask;
if (is_ui_isolate) {
schedule_microtask =
GetFunction(builtin_library, "_getScheduleMicrotaskClosure");
} else {
Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
Dart_Handle method_name =
Dart_NewStringFromCString("_getIsolateScheduleImmediateClosure");
schedule_microtask = Dart_Invoke(isolate_lib, method_name, 0, NULL);
}
Dart_Handle async_library = Dart_LookupLibrary(ToDart("dart:async"));
Dart_Handle set_schedule_microtask = ToDart("_setScheduleImmediateClosure");
Dart_Handle result = Dart_Invoke(async_library, set_schedule_microtask, 1,
&schedule_microtask);
PropagateIfError(result);
}
代码很简单,根据不同isolate有不同实现。先来看ui_isolate,也就是RootIsolate,在RootIsolate中,赋给_ScheduleImmediate._closure的值是_getScheduleMicrotaskClosure方法,所以来看该方法的实现。
void _scheduleMicrotask(void callback()) native 'ScheduleMicrotask';
@pragma('vm:entry-point')
Function _getScheduleMicrotaskClosure() => _scheduleMicrotask;
上面代码很简单,就是对应着ScheduleMicrotask函数。
[-> flutter/lib/ui/dart_runtime_hooks.cc]
void ScheduleMicrotask(Dart_NativeArguments args) {
Dart_Handle closure = Dart_GetNativeArgument(args, 0);
UIDartState::Current()->ScheduleMicrotask(closure);
}
在ScheduleMicrotask函数中解析传递的参数,然后在调用当前UIDartState对象的ScheduleMicrotask函数。
[-> flutter/lib/ui/ui_dart_state.cc]
void UIDartState::ScheduleMicrotask(Dart_Handle closure) {
if (tonic::LogIfError(closure) || !Dart_IsClosure(closure)) {
return;
}
microtask_queue_.ScheduleMicrotask(closure);
}
在UIDartState对象的ScheduleMicrotask函数中,又会调用DartMicrotaskQueue对象的ScheduleMicrotask函数。
[-> tonic/dart_microtask_queue.cc]
void DartMicrotaskQueue::ScheduleMicrotask(Dart_Handle callback) {
queue_.emplace_back(DartState::Current(), callback);
}
最终来到DartMicrotaskQueue对象,在该对象中存在一个集合queue_,而ScheduleMicrotask函数中就是把callback添加到该集合中。也就是在RootIsolate中,最终是把_startMicrotaskLoop方法作为参数添加到集合queue_中。
再来看非ui_isolate中的处理情况,在非ui_isolate中,赋给_ScheduleImmediate._closure的值就变成了_getIsolateScheduleImmediateClosure方法。该方法的实现就简单多了,来看下面代码。
_ImmediateCallback _pendingImmediateCallback;
void _isolateScheduleImmediate(void callback()) {
_pendingImmediateCallback = callback;
}
@pragma("vm:entry-point", "call")
Function _getIsolateScheduleImmediateClosure() {
return _isolateScheduleImmediate;
}
在上面代码中,仅是把赋给了_pendingImmediateCallback,也就是把_startMicrotaskLoop方法作为值赋给了_pendingImmediateCallback。
3.2、微任务的执行
经过前面的准备,下面就可以在合适的时机来执行_startMicrotaskLoop方法,从而来处理所有微任务。
这里也分为ui_isolate及非ui_isolate两种情况,先来看当前isolate是ui_isolate的情况。
再来看UIDartState对象的实现,除了将_startMicrotaskLoop添加到集合中,也会在该对象中通过FlushMicrotasksNow函数来执行_startMicrotaskLoop方法,代码如下。
[-> flutter/lib/ui/ui_dart_state.cc]
void UIDartState::FlushMicrotasksNow() {
microtask_queue_.RunMicrotasks();
}
再来看RunMicrotasks的实现,代码如下。
[-> tonic/dart_microtask_queue.cc]
void DartMicrotaskQueue::RunMicrotasks() {
while (!queue_.empty()) {
MicrotaskQueue local;
std::swap(queue_, local);
//遍历集合中的所有元素
for (const auto& callback : local) {
if (auto dart_state = callback.dart_state().lock()) {
DartState::Scope dart_scope(dart_state.get());
//调用_startMicrotaskLoop方法,callback.value()对应是_startMicrotaskLoop
Dart_Handle result = Dart_InvokeClosure(callback.value(), 0, nullptr);
...
}
}
}
}
至此,知道了在ui_isolate中,微任务是如何添加到集合中、如何执行的。那么再来想一个问题,微任务的执行时机是在什么时候尼?这就需要来看调用FlushMicrotasksNow函数的时机。
经过查看Flutter源码。可以发现,Flutter中仅在Window对象的BeginFrame函数及UIDartState对象的AddOrRemoveTaskObserver函数中调用了调用了FlushMicrotasksNow函数。因此先来看BeginFrame的实现。
[-> flutter/lib/ui/window/window.cc]
void Window::BeginFrame(fml::TimePoint frameTime) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds();
//调用_beginFrame方法来开始绘制
tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame",
{
Dart_NewInteger(microseconds),
}));
//执行所有微任务
UIDartState::Current()->FlushMicrotasksNow();
//调用_drawFrame来绘制UI
tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {}));
}
代码很简单,但也说明了,在Flutter中的window调用_beginFrame与_drawFrame方法之间会把所有微任务处理掉。也就注定了不能在微任务中做耗时操作,否则影响UI的绘制。
再来看AddOrRemoveTaskObserver函数。
[-> flutter/lib/ui/ui_dart_state.cc]
UIDartState::UIDartState(
TaskRunners task_runners,
TaskObserverAdd add_callback,
TaskObserverRemove remove_callback,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
std::string logger_prefix,
UnhandledExceptionCallback unhandled_exception_callback,
std::shared_ptr<IsolateNameServer> isolate_name_server)
: task_runners_(std::move(task_runners)),
//给add_callback_赋值
add_callback_(std::move(add_callback)),
...
isolate_name_server_(std::move(isolate_name_server)) {
AddOrRemoveTaskObserver(true /* add */);
}
void UIDartState::AddOrRemoveTaskObserver(bool add) {
auto task_runner = task_runners_.GetUITaskRunner();
if (!task_runner) {
// This may happen in case the isolate has no thread affinity (for example,
// the service isolate).
return;
}
FML_DCHECK(add_callback_ && remove_callback_);
if (add) {
//这里是一个lambda表达式,传递给add_callback_一个函数
add_callback_(reinterpret_cast<intptr_t>(this),
[this]() { this->FlushMicrotasksNow(); });//执行所有微任务
} else {
remove_callback_(reinterpret_cast<intptr_t>(this));
}
}
这里重点来看add_callback_,它是在UIDartState对象初始化的时候赋值的。由于DartIsolate继承自UIDartState,所以来看DartIsolate对象的创建。
[-> flutter/runtime/dart_isolate.cc]
DartIsolate::DartIsolate(const Settings& settings,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
bool is_root_isolate)
: UIDartState(std::move(task_runners),
//add_callback_对应的值
settings.task_observer_add,
settings.task_observer_remove,
std::move(snapshot_delegate),
std::move(io_manager),
std::move(unref_queue),
std::move(image_decoder),
advisory_script_uri,
advisory_script_entrypoint,
settings.log_tag,
settings.unhandled_exception_callback,
DartVMRef::GetIsolateNameServer()),
is_root_isolate_(is_root_isolate) {
phase_ = Phase::Uninitialized;
}
在上面代码中,把settings对象的task_observer_add赋给了add_callback_。而settings是在FlutterMain的Init函数中创建并初始化的,所以在FlutterMain初始化时,就会给settings对象的task_observer_add赋值。
[-> flutter/shell/platform/android/flutter_main.cc]
void FlutterMain::Init(JNIEnv* env,
jclass clazz,
jobject context,
jobjectArray jargs,
jstring kernelPath,
jstring appStoragePath,
jstring engineCachesPath) {
std::vector<std::string> args;
args.push_back("flutter");
for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
args.push_back(std::move(arg));
}
auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());
auto settings = SettingsFromCommandLine(command_line);
...
//add_callback_对应的函数
settings.task_observer_add = [](intptr_t key, fml::closure callback) {
fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
};
settings.task_observer_remove = [](intptr_t key) {
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
};
...
}
再来看线程所对应的MessageLoopImpl对象,前面说过MessageLoopAndroid继承自MessageLoopImpl。所以来看AddTaskObserver函数的实现。
[-> flutter/fml/message_loop_impl.cc]
void MessageLoopImpl::AddTaskObserver(intptr_t key,
const fml::closure& callback) {
if (callback != nullptr) {
//每个MessageLoopImpl对象拥有唯一的queue_id_
task_queue_->AddTaskObserver(queue_id_, key, callback);
} else {...}
}
这里的task_queue_是一个MessageLoopTaskQueues对象,它的AddTaskObserver函数实现如下。
[-> flutter/fml/message_loop_task_queues.cc]
void MessageLoopTaskQueues::AddTaskObserver(TaskQueueId queue_id,
intptr_t key,
const fml::closure& callback) {
std::scoped_lock queue_lock(GetMutex(queue_id));
//UIDartState为key。包含FlushMicrotasksNow函数调用的callback为value
queue_entries_[queue_id]->task_observers[key] = std::move(callback);
}
代码中的queue_entries_是一个以TaskQueueId为key、TaskQueueEntry对象为value的map,而TaskQueueEntry中的task_observers也是一个map。所以AddTaskObserver函数就是把包含FlushMicrotasksNow函数调用的callback以UIDartState对象为key存入map中。
在Flutter之Timer原理解析一文中,如果在ui_isolate中,最终是通过DartMessageHandler的OnMessage函数来处理event handler消息及普通消息,代码如下。
[->third_party/tonic/dart_message_handler.cc]
void DartMessageHandler::Initialize(TaskDispatcher dispatcher) {
// Only can be called once.
TONIC_CHECK(!task_dispatcher_ && dispatcher);
task_dispatcher_ = dispatcher;
Dart_SetMessageNotifyCallback(MessageNotifyCallback);
}
void DartMessageHandler::OnMessage(DartState* dart_state) {
auto task_dispatcher_ = dart_state->message_handler().task_dispatcher_;
auto weak_dart_state = dart_state->GetWeakPtr();
//在Android中,任务交给UI线程中的loop来执行。
//在iOS中,也是通过类似loop的消息处理器来执行
task_dispatcher_([weak_dart_state]() {
if (auto dart_state = weak_dart_state.lock()) {
dart_state->message_handler().OnHandleMessage(dart_state.get());
}
});
}
代码中的task_dispatcher_是在DartMessageHandler对象调用Initialize函数时设置的。根据Flutter之Engine启动流程,知道是在Initialize函数是在RootIsolate初始化时调用的,那么就来看一下Initialize函数的实现。
[-> flutter/runtime/dart_isolate.cc]
bool DartIsolate::InitializeIsolate(
std::shared_ptr<DartIsolate> embedder_isolate,
Dart_Isolate isolate,
char** error) {
...
//设置UI线程的消息处理器
SetMessageHandlingTaskRunner(GetTaskRunners().GetUITaskRunner());
...
return true;
}
void DartIsolate::SetMessageHandlingTaskRunner(
fml::RefPtr<fml::TaskRunner> runner) {
if (!IsRootIsolate() || !runner) {
return;
}
message_handling_task_runner_ = runner;
//设置消息处理器
message_handler().Initialize(
[runner](std::function<void()> task) { runner->PostTask(task); });
}
根据上面代码,可以知道task_dispatcher_中其实就是将任务task通过PostTask函数添加到looper中。
[-> flutter/fml/task_runner.cc]
TaskRunner::TaskRunner(fml::RefPtr<MessageLoopImpl> loop)
: loop_(std::move(loop)) {}
void TaskRunner::PostTask(const fml::closure& task) {
loop_->PostTask(task, fml::TimePoint::Now());
}
以Android平台为例,这里的loop_就是一个MessageLoopAndroid对象。所以再来看MessageLoopAndroid中PostTask的实现。
[-> flutter/fml/message_loop_impl.cc]
void MessageLoopImpl::PostTask(const fml::closure& task,
fml::TimePoint target_time) {
...
task_queue_->RegisterTask(queue_id_, task, target_time);
}
在PostTask函数中最终还是调用的task_queue_的RegisterTask函数,再来看该函数的实现。
[-> flutter/fml/message_loop_task_queues.cc]
void MessageLoopTaskQueues::RegisterTask(TaskQueueId queue_id,
const fml::closure& task,
fml::TimePoint target_time) {
std::scoped_lock queue_lock(GetMutex(queue_id));
size_t order = order_++;
const auto& queue_entry = queue_entries_[queue_id];
queue_entry->delayed_tasks.push({order, task, target_time});
TaskQueueId loop_to_wake = queue_id;
if (queue_entry->subsumed_by != _kUnmerged) {
loop_to_wake = queue_entry->subsumed_by;
}
WakeUpUnlocked(loop_to_wake,
queue_entry->delayed_tasks.top().GetTargetTime());
}
void MessageLoopTaskQueues::WakeUpUnlocked(TaskQueueId queue_id,
fml::TimePoint time) const {
if (queue_entries_.at(queue_id)->wakeable) {
queue_entries_.at(queue_id)->wakeable->WakeUp(time);
}
}
在RegisterTask函数中,把任务task添加到优先级队列delayed_tasks中。然后再调用MessageLoopAndroid对象的WakeUp函数。
[-> flutter/fml/platform/android/message_loop_android.cc]
void MessageLoopAndroid::WakeUp(fml::TimePoint time_point) {
bool result = TimerRearm(timer_fd_.get(), time_point);
FML_DCHECK(result);
}
WakeUp函数就是通过TimerRearm函数来在合适的时机唤醒looper。根据前面UI线程的创建过程,可得知在looper唤醒后的回调函数read_event_fd中是执行MessageLoopAndroid对象的OnEventFired函数,而在该函数中又直接调用MessageLoopAndroid对象的FlushTasks函数,下面就来看FlushTasks函数的实现。
[-> flutter/fml/message_loop_impl.cc]
void MessageLoopImpl::FlushTasks(FlushType type) {
TRACE_EVENT0("fml", "MessageLoop::FlushTasks");
std::vector<fml::closure> invocations;
task_queue_->GetTasksToRunNow(queue_id_, type, invocations);
for (const auto& invocation : invocations) {
//执行普通回调方法
invocation();
std::vector<fml::closure> observers =
task_queue_->GetObserversToNotify(queue_id_);
for (const auto& observer : observers) {
//observer对应着UIDartState对象的FlushMicrotasksNow函数,这里也就是执行所有的微任务
observer();
}
}
}
void MessageLoopImpl::RunExpiredTasksNow() {
FlushTasks(FlushType::kAll);
}
在FlushTasks函数中,每一个已到期的event handler任务或异步任务执行完毕后,都会执行所有的微任务。
到此,在ui_isolate中,最终在以下两种时机来执行微任务。
- 在调用
window的_beginFrame与_drawFrame方法之间会把所有微任务处理掉。也就注定了不能在微任务中做耗时操作,否则影响UI的绘制。 - 在每一个已到期的
event handler任务或异步任务执行完毕后,都会执行所有的微任务。
再来看在非ui_isolate中微任务的执行时机。也主要分为以下几种情况。
- 根据Flutter之Timer原理解析一文可得知,在每一个
event handler任务或异步任务执行完毕后,都会执行所有的微任务。 - 如果当前是生产环境,
Isolate中消息类型是kDrainServiceExtensionsMsg且消息优先级是kImmediateAction,则也会执行所有微任务
4、总结
以上就是微任务的使用及使用原理。还是有一定难度的。结合Flutter之Timer原理解析一文,基本上就可以了解Flutter中的消息机制,这样在使用微任务及其他异步任务时也能做到了然于胸。
【参考资料】