在Flutter
中,異步任務主要是經過Timer
及微任務來實現。在Flutter之Timer原理解析一文中,講述了經過Timer
來實現異步任務的原理,那麼本文就來看異步任務的另外一種實現,微任務的使用及其實現原理。java
先來看微任務的使用,代碼很簡單,以下。android
//用法一
Future.microtask(() {
print("microtask1");
});
//用法二
scheduleMicrotask(() {
print("microtask2");
});
//用法三
Zone.current.scheduleMicrotask((){
print("microtask3");
});
//用法四
Zone.root.scheduleMicrotask((){
print("microtask4");
});
複製代碼
以上就是微任務的全部用法。基本上都是前兩種使用方式比較多,但前面兩種用法僅是對後面兩種用法的封裝而已。下面就來看微任務的實現原理,不過在分析微任務的實現原理以前須要先了解一下UI線程是如何建立的。c++
在Flutter之Engine啓動流程一文中,提過在Engine
建立過程當中會建立UI線程、IO線程及GPU線程,但未深刻。因此這裏就以Android平臺爲例來深刻的來了解Flutter
中UI線程是如何建立的(IO線程、GPU線程與UI線程都是同一類型的對象,但命名不一樣)。git
[-> flutter/shell/platform/android/android_shell_holder.cc]shell
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_
是一個結構體,因此直接來看該結構體中的具體實現。app
[-> 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線程的具體實現。async
[-> flutter/fml/thread.cc]ide
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
來實現的。
再回到微任務的實現中。以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());
}
複製代碼
來看_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
。
通過前面的準備,下面就能夠在合適的時機來執行_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
中微任務的執行時機。也主要分爲如下幾種狀況。
event handler
任務或異步任務執行完畢後,都會執行全部的微任務。Isolate
中消息類型是kDrainServiceExtensionsMsg
且消息優先級是kImmediateAction
,則也會執行全部微任務以上就是微任務的使用及使用原理。仍是有必定難度的。結合Flutter之Timer原理解析一文,基本上就能夠了解Flutter
中的消息機制,這樣在使用微任務及其餘異步任務時也能作到了然於胸。
【參考資料】