關(guān)于Flutter你要知道的可能都在這里

先從一張架構(gòu)預(yù)覽圖說起吧:

Flutter架構(gòu)

Flutter架構(gòu)分Framework/Engine/Embedder三層:

Framework

Framework層是純dart語言寫的,它實現(xiàn)了一套用于處理Animation、Painting和Gestures的基礎(chǔ)功能,并基于Painting封裝了一套widget用來抹平跨平臺UI展示的差異
以及提供了一套減少由于UI改變控件重復(fù)創(chuàng)建銷毀帶來的性能消耗

Embedder層

什么是Embedder ?
個人理解是flutter想要在不同的平臺上運行就要在不同的平臺上創(chuàng)建容器詳情點擊這里
比如在Android上就要創(chuàng)建FlutterActivity/FlutterFragment/FlutterView
通過查看源碼可以發(fā)現(xiàn)Embedder層主要負(fù)責(zé) Engine的初始化 線程設(shè)置 渲染組件的設(shè)置 資源文件的初始化

Engine層

Engine層是由C++編寫是flutter的核心負(fù)責(zé)初始化,Dart虛擬機管理,F(xiàn)lutter底層的通信和事件機制

Flutter自提供widget和Sika渲染引擎抹平平臺差異

Embedder如何和Engine建立關(guān)系

跟蹤FlutterEmbedder層代碼中會發(fā)現(xiàn)不論是FlutterActivity還是FlutterFragment最終Flutter的容器還是FlutterView,而FlutterView只不過繼承了SurfaceView

/**
 * An Android view containing a Flutter app.
 */
public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry {
//...
        if (nativeView == null) {
            mNativeView = new FlutterNativeView(activity.getApplicationContext());
        } else {
            mNativeView = nativeView;
        }

        dartExecutor = mNativeView.getDartExecutor();
        flutterRenderer = new FlutterRenderer(mNativeView.getFlutterJNI());
       //...
        mNativeView.attachViewAndActivity(this, activity);

        mSurfaceCallback = new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                assertAttached();
                mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                assertAttached();
                mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                assertAttached();
                mNativeView.getFlutterJNI().onSurfaceDestroyed();
            }
        };
        getHolder().addCallback(mSurfaceCallback);
// ...   
}

surface的改變會通知nativeview,F(xiàn)lutterView好像就是nativeview的裝飾器,那么讓我們進(jìn)入FlutterNativeView看看:

public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
  //...
        mFlutterJNI = new FlutterJNI();
  //...構(gòu)造后直接調(diào)用attach方法調(diào)用和Engine層建立關(guān)系
         attach(this, isBackgroundView);
    }

FlutterJNI getFlutterJNI() {
        return mFlutterJNI;
    }

 private void attach(FlutterNativeView view, boolean isBackgroundView) {
        mFlutterJNI.attachToNative(isBackgroundView);
        dartExecutor.onAttachedToJNI();
    }

由此可以看出Navtive是通過FlutterJNI和JNI層關(guān)聯(lián)并初始化Engine

關(guān)聯(lián)并Engine初始化

attachToNative 的代碼位置在這里:/flutter/shell/platform/android/platform_view_android_jni.cc

static jlong AttachJNI(JNIEnv* env,
                       jclass clazz,
                       jobject flutterJNI,
                       jboolean is_background_view) {
  fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI);
  auto shell_holder = std::make_unique<AndroidShellHolder>(
      FlutterMain::Get().GetSettings(), java_object, is_background_view);
  if (shell_holder->IsValid()) {
    return reinterpret_cast<jlong>(shell_holder.release());
  } else {
    return 0;
  }
}

reinterpret_cast是C++里的強制類型轉(zhuǎn)換符。這里reinterpret_cast()方法將該AndroidShellHolder對象指針強制轉(zhuǎn)化為long類型的值并返回java層保存。
那就從AndroidShellHolder分析:/flutter/shell/platform/android/android_shell_holder.cc

step1: 創(chuàng)建四個線程 并把當(dāng)前線程設(shè)置platform thread
  // The current thread will be used as the platform thread. Ensure that the
  // message loop is initialized.
  fml::MessageLoop::EnsureInitializedForCurrentThread();
  fml::RefPtr<fml::TaskRunner> gpu_runner;
  fml::RefPtr<fml::TaskRunner> ui_runner;
  fml::RefPtr<fml::TaskRunner> io_runner;
  fml::RefPtr<fml::TaskRunner> platform_runner =
      fml::MessageLoop::GetCurrent().GetTaskRunner();
  if (is_background_view) {
    ...
  } else {
    gpu_runner = thread_host_.gpu_thread->GetTaskRunner();
    ui_runner = thread_host_.ui_thread->GetTaskRunner();
    io_runner = thread_host_.io_thread->GetTaskRunner();
  }
  blink::TaskRunners task_runners(thread_label,     // label
                                  platform_runner,  // platform
                                  gpu_runner,       // gpu
                                  ui_runner,        // ui
                                  io_runner         // io
  );
step2:
shell_ =
      Shell::Create(task_runners,             // task runners
                    settings_,                // settings
                    on_create_platform_view,  // platform view create callback
                    on_create_rasterizer      // rasterizer create callback
      );

/flutter/shell/common/shell.cc
如果編譯Engine不方便方便可在github直接查看

std::unique_ptr<Shell> Shell::Create(
    TaskRunners task_runners,
    Settings settings,
    Shell::CreateCallback<PlatformView> on_create_platform_view,
    Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
  PerformInitializationTasks(settings);
  PersistentCache::SetCacheSkSL(settings.cache_sksl);

  TRACE_EVENT0("flutter", "Shell::Create");

  auto vm = DartVMRef::Create(settings);
  FML_CHECK(vm) << "Must be able to initialize the VM.";

  auto vm_data = vm->GetVMData();

  return Shell::Create(std::move(task_runners),             //
                       std::move(settings),                 //
                       vm_data->GetIsolateSnapshot(),       // isolate snapshot
                       DartSnapshot::Empty(),               // shared snapshot
                       std::move(on_create_platform_view),  //
                       std::move(on_create_rasterizer),     //
                       std::move(vm)                        //
  );
}
//...
std::unique_ptr<Shell> Shell::Create(
    TaskRunners task_runners,
    Settings settings,
    fml::RefPtr<const DartSnapshot> isolate_snapshot,
    fml::RefPtr<const DartSnapshot> shared_snapshot,
    Shell::CreateCallback<PlatformView> on_create_platform_view,
    Shell::CreateCallback<Rasterizer> on_create_rasterizer,
    DartVMRef vm) {
//...
  shell = CreateShellOnPlatformThread(std::move(vm),
                                            std::move(task_runners),      //
                                            settings,                     //
                                            std::move(isolate_snapshot),  //
                                            std::move(shared_snapshot),   //
                                            on_create_platform_view,      //
                                            on_create_rasterizer          //
        );
//...
}

1根據(jù)setting執(zhí)行了初始化Task
2創(chuàng)建了DartVM并將其傳入Shell的Create方法中
在這里找到Shell真正的Create方法CreateShellOnPlatformThread

 // Create the rasterizer on the GPU thread.
 // Create the platform view on the platform thread (this thread).
 // Ask the platform view for the vsync waiter. This will be used by the engine
auto vsync_waiter = platform_view->CreateVSyncWaiter();
// Create the IO manager on the IO thread.
// Create the engine on the UI thread.

根據(jù)代碼注釋可知:
1 在GPUThread創(chuàng)建rasterizer
2 在platform thread(APP主線程) 創(chuàng)建PlatformView 并獲取其VSyncWaiter傳遞給Engine
3 在UIThread創(chuàng)建Engine
然后通過shell的Setup方法調(diào)用將platform_view、io_manager、rasterizer和engine四個unique_ptr保存到Shell對象中交由Shell對象管理并將Create的結(jié)果shell返回給AndroidShellHolder 由此Embedder層和Engine層就建立了聯(lián)系 并初始化了 四個線程 一個DartVM 和一個Engine。
這里畫了一個圖總結(jié)一下:


image.png

Flutter與線程

Flutter Engine自己不創(chuàng)建, 管理線程。Flutter Engine線程的創(chuàng)建和管理是由embedder負(fù)責(zé)的

Embeder提供四個Task Runner, 每個Task Runner負(fù)責(zé)不同的任務(wù),F(xiàn)lutter Engine不在乎Task Runner具體跑在哪個線程,但是它需要線程配置在整一個生命周期里面保持穩(wěn)定。也就是說一個Runner最好始終保持在同一線程運行

Platform Task Runner

根據(jù)代碼在初始化Engine的時候,將當(dāng)前線程設(shè)置為PlatformTaskRunner的Thread,是Flutter和Native交互的橋梁,而且官方要求所有和Flutter的交互必須發(fā)生在PlatformThread中,因為FlutterEngine中有很多模塊是非線程安全的,所以如果在其他線程調(diào)用Flutter engine會出現(xiàn)無法預(yù)期的異常
然是值得注意的是,PlatformThread阻塞并不會直接導(dǎo)致Flutter應(yīng)用卡頓,因為Flutter渲染的核心在UIThread中

UI Task Runner

前文中Embedder和Engine關(guān)聯(lián)后,Engine就開始著手執(zhí)行Dart root isolate代碼 ,Root Isolate負(fù)責(zé)創(chuàng)建管理的Layer Tree最終決定什么內(nèi)容要繪制到屏幕上。因此這個線程的過載會直接導(dǎo)致卡頓掉幀。

GPU Task Runner

GPU Task Runner中的模塊負(fù)責(zé)將Layer Tree提供的信息轉(zhuǎn)化為實際的GPU指令。GPU Task Runner同時也負(fù)責(zé)配置管理每一幀繪制所需要的GPU資源,這包括平臺Framebuffer的創(chuàng)建,Surface生命周期管理,保證Texture和Buffers在繪制的時候是可用的。
GPU Runner可以導(dǎo)致UI Runner的幀調(diào)度的延遲,GPU Runner的過載會導(dǎo)致Flutter應(yīng)用的卡頓。一般來說用戶沒有機會向GPU Runner直接提交任務(wù),因為平臺和Dart代碼都無法跑進(jìn)GPU Runner。但是Embeder還是可以向GPU Runner提交任務(wù)的。因此建議為每一個Engine實例都新建一個專用的GPU Runner線程。

IO Task Runner

主要功能是從圖片存儲(比如磁盤)中讀取壓縮的圖片格式,將圖片數(shù)據(jù)進(jìn)行處理為GPU Runner的渲染做好準(zhǔn)備。

總結(jié):

Platform Thread GPU Thread UI Thread IO Thread
Flutter Engine的接口調(diào)用 執(zhí)行設(shè)備GPU的指令 執(zhí)行Dart root isolate代碼 讀取并處理圖片數(shù)據(jù)

isolate

isolate是隔離的,每個isolate有自己的內(nèi)存和單線程運行的實體. isolate之間不互相共享內(nèi)存,且獨立GC。
isolate中的代碼是順序執(zhí)行的,且是單線程,所以不存在資源競爭和變量狀態(tài)同步的問題,也就不需要鎖。Dart中的并發(fā)都是多個isolate并行實現(xiàn)的

由于isolate不共享內(nèi)存,所以isolate之間不能直接互相通信,只能通過Port進(jìn)行通信,而且是異步的

Flutter Engine Runners與Dart Isolate

Dart的Isolate是Dart虛擬機自己管理的,F(xiàn)lutter Engine無法直接訪問。Root Isolate通過Dart的C++調(diào)用能力把UI渲染相關(guān)的任務(wù)提交到UI Runner執(zhí)行, 這樣就可以跟Flutter Engine相關(guān)模塊進(jìn)行交互,F(xiàn)lutter UI相關(guān)的任務(wù)也被提交到UI Runner也可以相應(yīng)的給Isolate一些事件通知, Dart isolate跟Flutter Runner是相互獨立的,它們通過任務(wù)調(diào)度機制相互協(xié)作

DalvikVM與DartVM

DartVM的內(nèi)存管理

準(zhǔn)確的說DartVM和JVM的GC機制相似 使用分年代收集的方式,將內(nèi)存分為新生代和老年代:

新生代

初次分配的對象都位于新生代中,該區(qū)域主要是存放內(nèi)存較小并且生命周期較短的對象,比如局部變量。新生代會頻繁執(zhí)行內(nèi)存回收(GC),回收采用“復(fù)制-清除”算法,將內(nèi)存分為兩塊,運行時每次只使用其中的一塊,另一塊備用。當(dāng)發(fā)生GC時,將當(dāng)前使用的內(nèi)存塊中存活的對象拷貝到備用內(nèi)存塊中,然后清除當(dāng)前使用內(nèi)存塊,最后,交換兩塊內(nèi)存的角色。


年輕代GC
老年代

老年代GC采用的是標(biāo)記-清理的方式而且在標(biāo)記的時候,該線程中內(nèi)存區(qū)域是處于不可修改的狀態(tài),類似于JVM中stop the world,但是由于dart優(yōu)秀的schedule機制和老年代GC頻率很低的原因,基本上不會出現(xiàn)這個問題。

schedule

在查看engine源碼的過程中我們看到,dartVM被作為一個變量傳入了engine,為了最小化GC對APP和UI的性能影響,當(dāng)FlutterApp處于空閑/無用戶交互/后臺的情況下,engine調(diào)用DartVM觸發(fā)GC

isolate

記得在JVM中Thread是執(zhí)行操作的最小單元,Dart區(qū)別于JVM的是:
isolate有自己獨立的堆棧
isolate之間內(nèi)存不共享
isolate之間GC不會相互影響
isolate之間不能直接相互通信,只能通過Port進(jìn)行異步通信
整個Flutter Framework Widget的渲染過程都運行在一個isolate中

DartVM區(qū)別于DalvikVM

由此可見Dart天生不存在數(shù)據(jù)競爭和變量不同步的問,或者說Dart是單線程的,可是在移動端,APP大多數(shù)時間是處于等待的狀態(tài):等待網(wǎng)絡(luò)請求結(jié)果,等待用戶操作等因此Flutter選擇Dart作為開發(fā)語言也有一定的道理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容