Android Flutter實(shí)現(xiàn)原理淺析
前言
flutter可以說是當(dāng)下最流行的跨平臺(tái)技術(shù)了,其最突出的
網(wǎng)上可以搜到的文章,大多數(shù)都是flutter的用法,即使介紹其實(shí)現(xiàn)原理的,也直接深入源碼直接解讀,造成只有一定功能的讀者才能理解。
本文希望以最通俗易解的方式介紹flutter的實(shí)現(xiàn)原理,也許不會(huì)介紹的深入或者詳細(xì),但是一定能讓讀者知道flutter的基本實(shí)現(xiàn)原理。
本文基于flutter2.0的源碼進(jìn)行原理分析,3.0的源碼有些許變動(dòng),但整體流程是一樣的。
一.安卓原生界面繪制的流程
原生繪制流程
有另外的一個(gè)系列文章來講原生的界面,為了方便讀者閱讀,本文會(huì)簡(jiǎn)略描述一下整個(gè)流程。
其主要流程是在每次sync的時(shí)候去執(zhí)行測(cè)量(measure),布局(layout),繪制(draw)的流程。
而draw的時(shí)候時(shí)候,核心是利用canvas執(zhí)行各種繪制命令,并且把這些命令轉(zhuǎn)換為buffer記錄,最終發(fā)送給WMS層,然后轉(zhuǎn)交給SurfaceFlinger,由其做最終的合成和渲染。
SurfaceView繪制流程
另外也許你還聽說過另外一種可以在子線程渲染的控件:surfaceView。我們的視頻播放器,高頻繪制的自定義View都是由其實(shí)現(xiàn)的。
其主要流程圖如下:
其原理其實(shí)和第一種方式類似,區(qū)別就是在于少了measure,layout的流程。而是自己去計(jì)算坐標(biāo),然后直接進(jìn)入draw的流程,通過canvas寫入native的數(shù)據(jù)buffer內(nèi)存中,最后統(tǒng)一發(fā)送給WMS進(jìn)行進(jìn)入渲染的流程。
而Flutter的實(shí)現(xiàn)原理,其實(shí)就和surfaceView類似。
二.Flutter上界面繪制的流程
flutter有混合開發(fā)和純flutter開發(fā)兩種。純flutter使用的是FlutterActivity,而混合開發(fā)一般使用的是FlutterView。我們先看一下使用FlutterActivity的方式。
FlutterActivity中的流程
首先看一下FlutterActivity的實(shí)現(xiàn),發(fā)現(xiàn)其核心流程都交給了FlutterActivityDelegate處理,所以我們直接看Delegate的onCreate方法:
public void onCreate(Bundle savedInstanceState) { ... this.flutterView = this.viewFactory.createFlutterView(this.activity); if (this.flutterView == null) { FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView(); this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView); this.flutterView.setLayoutParams(matchParent); this.activity.setContentView(this.flutterView); this.launchView = this.createLaunchView(); if (this.launchView != null) { this.addLaunchView(); } } ... }
主要流程就是創(chuàng)建一個(gè)flutterView,添加到contentView中,所以其實(shí)無論哪種方式,最終都是由flutterView來實(shí)現(xiàn)的。
FlutterView中的實(shí)現(xiàn)
首先我們看一下FlutterView類,發(fā)現(xiàn)其繼承自SurfaceView,這也回應(yīng)了我們上面的描述,其核心實(shí)現(xiàn)原理就是基于surfaceView實(shí)現(xiàn)的。
其構(gòu)造方法如下:非核心代碼已做了刪減處理
public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) { super(context, attrs); ... //創(chuàng)建在native層的處理對(duì)象,相關(guān)繪制邏輯其實(shí)都是在native層處理的,Java層只負(fù)責(zé)傳入 this.mNativeView = new FlutterNativeView(activity.getApplicationContext()); //創(chuàng)建dart的解釋器 this.dartExecutor = this.mNativeView.getDartExecutor(); //創(chuàng)建渲染對(duì)象 this.flutterRenderer = new FlutterRenderer(this.mNativeView.getFlutterJNI()); //native層的view對(duì)象進(jìn)行綁定 this.mNativeView.attachViewAndActivity(this, activity); //由于是surfaceView,所以在surface創(chuàng)建好之后傳入naitve this.mSurfaceCallback = new Callback() { public void surfaceCreated(SurfaceHolder holder) { FlutterView.this.assertAttached(); FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface()); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { FlutterView.this.assertAttached(); FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height); } public void surfaceDestroyed(SurfaceHolder holder) { FlutterView.this.assertAttached(); FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed(); } }; this.getHolder().addCallback(this.mSurfaceCallback); // this.mActivityLifecycleListeners = new ArrayList(); this.mFirstFrameListeners = new ArrayList(); this.navigationChannel = new NavigationChannel(this.dartExecutor); this.keyEventChannel = new KeyEventChannel(this.dartExecutor); this.lifecycleChannel = new LifecycleChannel(this.dartExecutor); this.localizationChannel = new LocalizationChannel(this.dartExecutor); this.platformChannel = new PlatformChannel(this.dartExecutor); this.systemChannel = new SystemChannel(this.dartExecutor); this.settingsChannel = new SettingsChannel(this.dartExecutor); final PlatformPlugin platformPlugin = new PlatformPlugin(activity, this.platformChannel); this.addActivityLifecycleListener(new ActivityLifecycleListener() { public void onPostResume() { platformPlugin.updateSystemUiOverlays(); } }); this.mImm = (InputMethodManager)this.getContext().getSystemService("input_method"); PlatformViewsController platformViewsController = this.mNativeView.getPluginRegistry().getPlatformViewsController(); this.mTextInputPlugin = new TextInputPlugin(this, this.dartExecutor, platformViewsController); this.androidKeyProcessor = new AndroidKeyProcessor(this.keyEventChannel, this.mTextInputPlugin); this.androidTouchProcessor = new AndroidTouchProcessor(this.flutterRenderer); this.mNativeView.getPluginRegistry().getPlatformViewsController().attachTextInputPlugin(this.mTextInputPlugin); this.sendLocalesToDart(this.getResources().getConfiguration()); this.sendUserPlatformSettingsToDart();
其構(gòu)造方法中,主要流程就是各種功能的初始化,以及完成surface和native的綁定。
我們可以看到下面這樣代碼,就是把surface傳入了native層。
FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
所以看到這里,我們可以做這樣的推測(cè)了:
flutter原理其實(shí)就類似于surfaceView的實(shí)現(xiàn)。通過傳遞surface到native層,然后通過這個(gè)surface獲取到canvas,寫入渲染buffer,最終通知到WMS完成繪制的整個(gè)流程。
native流程
onSurfaceCreated的創(chuàng)建最終會(huì)走到native層platform_view_android_jni_impl.cpp中的SurfaceCreated()方法。
static void SurfaceCreated(JNIEnv* env, jobject jcaller, jlong shell_holder, jobject jsurface) { // Note: This frame ensures that any local references used by // ANativeWindow_fromSurface are released immediately. This is needed as a // workaround for https://code.google.com/p/android/issues/detail?id=68174 fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env); auto window = fml::MakeRefCounted<AndroidNativeWindow>( ANativeWindow_fromSurface(env, jsurface)); ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window)); }
這里很簡(jiǎn)單,創(chuàng)建native層的Window對(duì)象,調(diào)用NotifyCreated方法繼續(xù)傳入。
走到platform_view.cc的NotifyCreated方法如下:
void PlatformViewAndroid::NotifyCreated( fml::RefPtr<AndroidNativeWindow> native_window) { if (android_surface_) { //1 InstallFirstFrameCallback(); ... } //2 PlatformView::NotifyCreated(); }
該方法中主要做了兩件事:
第一件:回調(diào)java的onFirstFrame方法;
第二件:?jiǎn)?dòng)渲染流程。
NotifyCreated中,主要是交給delegate_去處理:
void PlatformView::NotifyCreated() { std::unique_ptr<Surface> surface; ... delegate_.OnPlatformViewCreated(std::move(surface)); }
這個(gè)delegate_其實(shí)是shell對(duì)象,則會(huì)調(diào)用到shell.cc的OnPlatformViewCreated方法:
// |PlatformView::Delegate| void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) { TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated"); FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); ... //這里主要是一系列的判斷,避免死鎖 const bool should_post_raster_task = !task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread(); fml::AutoResetWaitableEvent latch; //UI線程執(zhí)行,渲染的流程 auto raster_task = fml::MakeCopyable([&waiting_for_first_frame = waiting_for_first_frame_, rasterizer = rasterizer_->GetWeakPtr(), // surface = std::move(surface)]() mutable { if (rasterizer) { // Enables the thread merger which may be used by the external view // embedder. rasterizer->EnableThreadMergerIfNeeded(); rasterizer->Setup(std::move(surface)); } waiting_for_first_frame.store(true); }); ... auto ui_task = [engine = engine_->GetWeakPtr()] { if (engine) { engine->OnOutputSurfaceCreated(); } }; ... //啟動(dòng)各種渲染的流程 fml::TaskRunner::RunNowOrPostTask(task_runners_.GetIOTaskRunner(), io_task); latch.Wait(); if (!should_post_raster_task) { // See comment on should_post_raster_task, in this case the raster_task // wasn't executed, and we just run it here as the platform thread // is the raster thread. raster_task(); } }
這個(gè)方法中,主要就是各種檢查,包括一些鎖機(jī)制的判斷,最后通知engine啟動(dòng)去渲染surface了
三.總結(jié)
Flutter的簡(jiǎn)單實(shí)現(xiàn)原理
Flutter的簡(jiǎn)單實(shí)現(xiàn)原理其實(shí)就類似于surfaceView的實(shí)現(xiàn)。
surfaceView中往buffer中寫入渲染數(shù)據(jù)是通過java層的canvas實(shí)現(xiàn)的,而在flutter中是通過native層實(shí)現(xiàn)。flutter就是在native層接收到surface,然后通過surface獲取到native層的canvas,對(duì)buffer進(jìn)行寫入,最終通知到WMS完成繪制的整個(gè)流程。
當(dāng)然,詳細(xì)的原理還包含了事件流程是如何分發(fā)的,如何翻譯dart成可執(zhí)行的代碼,如何解釋編譯的產(chǎn)物等等,由于篇幅限制,本篇就不詳細(xì)展開了,后續(xù)會(huì)逐漸寫文章進(jìn)行原理分析。
Flutter的幾個(gè)高頻問題
1.為什么主要流程使用jni實(shí)現(xiàn)?用Java實(shí)現(xiàn)是否可以?
我的理解是其實(shí)java實(shí)現(xiàn)也是完全可以的,但是要知道flutter是跨平臺(tái)的。如果用java的話,那么在安卓上是沒問題的,但是如果在IOS勢(shì)必又要用OC在寫一套邏輯,這樣造成重復(fù)的工作量。而使用C來編寫,任意平臺(tái)其實(shí)都是可以通用的,降低開發(fā)成本,而且更不容易出現(xiàn)差異。之前和螞蟻金服antv(螞蟻數(shù)據(jù)可視化團(tuán)隊(duì))的朋友聊天時(shí),他們也是類似的考慮,底層邏輯使用C實(shí)現(xiàn),安卓/IOS/PC等只做上層的接口封裝和兼容。
2.為什么使用dart而不使用其他語言?
這個(gè)我的理解是用JS應(yīng)該也是可以的,或者說java也可以。但是又都不夠好。
如果是用java的話,flutter的熱部署功能就無法實(shí)現(xiàn),java類加載機(jī)制有緩存,一旦加載就無法被替換。當(dāng)然不是絕對(duì)的,可以通過替換classLoader的方式進(jìn)行替換,類似于tomcat的熱部署。但如果這樣,實(shí)現(xiàn)成本就會(huì)及其的高,而且性能不佳。
使用js的話,實(shí)現(xiàn)熱部署肯定是沒有問題,但問題就在于生產(chǎn)環(huán)境,其實(shí)更需要的是效率。JIT的編譯方式效率肯定是比不過AOT的。
而dart同時(shí)支持AOT和JIT兩種方式,自然是最優(yōu)的選擇。
到此這篇關(guān)于Android Flutter實(shí)現(xiàn)原理淺析的文章就介紹到這了,更多相關(guān)Android Flutter內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android?Flutter實(shí)現(xiàn)搜索的三種方式詳解
- Android Flutter圖片處理之高斯模糊的實(shí)現(xiàn)
- Android使用Flutter實(shí)現(xiàn)錄音插件
- Android?Flutter繪制有趣的?loading加載動(dòng)畫
- Android Flutter利用CustomPaint繪制基本圖形詳解
- Android Flutter制作交錯(cuò)動(dòng)畫的示例代碼
- Android Flutter表格組件Table的使用詳解
- Android Flutter實(shí)現(xiàn)GIF動(dòng)畫效果的方法詳解
- Android利用Flutter實(shí)現(xiàn)立體旋轉(zhuǎn)效果
相關(guān)文章
Android開發(fā)實(shí)現(xiàn)簡(jiǎn)單的觀察者與被觀察者示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)簡(jiǎn)單的觀察者與被觀察者,簡(jiǎn)單描述了觀察者模式的概念、原理并結(jié)合實(shí)例形式分析了Android實(shí)現(xiàn)觀察者模式的簡(jiǎn)單操作技巧,需要的朋友可以參考下2017-11-11Android ListView之setEmptyView正確使用方法
這篇文章主要介紹了Android ListView之setEmptyView正確使用方法的相關(guān)資料,希望通過本文能幫助到大家使用該方法,需要的朋友可以參考下2017-09-09Android Studio升級(jí)4.1.1后各種錯(cuò)誤和解決方案
這篇文章主要介紹了Android Studio升級(jí)4.1.1后各種錯(cuò)誤和解決方案,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Android 使用fast-verification實(shí)現(xiàn)驗(yàn)證碼填寫功能的實(shí)例代碼
這篇文章主要介紹了Android 使用fast-verification實(shí)現(xiàn)驗(yàn)證碼填寫功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04