最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android Flutter實(shí)現(xiàn)原理淺析

 更新時(shí)間:2022年08月10日 11:29:15   作者:失落夏天  
這篇文章主要介紹了Android Flutter的實(shí)現(xiàn)原理是怎么樣的,flutter可以說(shuō)是當(dāng)下最流行的跨平臺(tái)技術(shù)了,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

flutter可以說(shuō)是當(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è)系列文章來(lái)講原生的界面,為了方便讀者閱讀,本文會(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繪制流程

另外也許你還聽(tīng)說(shuō)過(guò)另外一種可以在子線程渲染的控件:surfaceView。我們的視頻播放器,高頻繪制的自定義View都是由其實(shí)現(xiàn)的。

其主要流程圖如下:

其原理其實(shí)和第一種方式類似,區(qū)別就是在于少了measure,layout的流程。而是自己去計(jì)算坐標(biāo),然后直接進(jìn)入draw的流程,通過(guò)canvas寫(xiě)入native的數(shù)據(jù)buffer內(nèi)存中,最后統(tǒng)一發(fā)送給WMS進(jìn)行進(jìn)入渲染的流程。

而Flutter的實(shí)現(xiàn)原理,其實(shí)就和surfaceView類似。

二.Flutter上界面繪制的流程

flutter有混合開(kāi)發(fā)和純flutter開(kāi)發(fā)兩種。純flutter使用的是FlutterActivity,而混合開(kāi)發(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í)無(wú)論哪種方式,最終都是由flutterView來(lái)實(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)。通過(guò)傳遞surface到native層,然后通過(guò)這個(gè)surface獲取到canvas,寫(xiě)入渲染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中寫(xiě)入渲染數(shù)據(jù)是通過(guò)java層的canvas實(shí)現(xiàn)的,而在flutter中是通過(guò)native層實(shí)現(xiàn)。flutter就是在native層接收到surface,然后通過(guò)surface獲取到native層的canvas,對(duì)buffer進(jìn)行寫(xiě)入,最終通知到WMS完成繪制的整個(gè)流程。

當(dāng)然,詳細(xì)的原理還包含了事件流程是如何分發(fā)的,如何翻譯dart成可執(zhí)行的代碼,如何解釋編譯的產(chǎn)物等等,由于篇幅限制,本篇就不詳細(xì)展開(kāi)了,后續(xù)會(huì)逐漸寫(xiě)文章進(jìn)行原理分析。

Flutter的幾個(gè)高頻問(wèn)題

1.為什么主要流程使用jni實(shí)現(xiàn)?用Java實(shí)現(xiàn)是否可以?

我的理解是其實(shí)java實(shí)現(xiàn)也是完全可以的,但是要知道flutter是跨平臺(tái)的。如果用java的話,那么在安卓上是沒(méi)問(wèn)題的,但是如果在IOS勢(shì)必又要用OC在寫(xiě)一套邏輯,這樣造成重復(fù)的工作量。而使用C來(lái)編寫(xiě),任意平臺(tái)其實(shí)都是可以通用的,降低開(kāi)發(fā)成本,而且更不容易出現(xiàn)差異。之前和螞蟻金服antv(螞蟻數(shù)據(jù)可視化團(tuán)隊(duì))的朋友聊天時(shí),他們也是類似的考慮,底層邏輯使用C實(shí)現(xiàn),安卓/IOS/PC等只做上層的接口封裝和兼容。

2.為什么使用dart而不使用其他語(yǔ)言?

這個(gè)我的理解是用JS應(yīng)該也是可以的,或者說(shuō)java也可以。但是又都不夠好。

如果是用java的話,flutter的熱部署功能就無(wú)法實(shí)現(xiàn),java類加載機(jī)制有緩存,一旦加載就無(wú)法被替換。當(dāng)然不是絕對(duì)的,可以通過(guò)替換classLoader的方式進(jìn)行替換,類似于tomcat的熱部署。但如果這樣,實(shí)現(xiàn)成本就會(huì)及其的高,而且性能不佳。

使用js的話,實(shí)現(xiàn)熱部署肯定是沒(méi)有問(wèn)題,但問(wèn)題就在于生產(chǎn)環(huán)境,其實(shí)更需要的是效率。JIT的編譯方式效率肯定是比不過(guò)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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android那兩個(gè)你碰不到但是很重要的類之ViewRootImpl

    Android那兩個(gè)你碰不到但是很重要的類之ViewRootImpl

    這兩個(gè)類就是ActivityThread和ViewRootImpl,之所以說(shuō)碰不到是因?yàn)槲覀儫o(wú)法通過(guò)正常的方式引用這兩個(gè)類或者其類的對(duì)象,本文就嘗試從幾個(gè)我們經(jīng)常接觸的方面先談?wù)刅iewRootImpl,感興趣的可以參考閱讀下
    2023-05-05
  • Kotlin中局部方法的深入探究

    Kotlin中局部方法的深入探究

    這篇文章主要給大家介紹了關(guān)于Kotlin中局部方法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • Android如何實(shí)現(xiàn)年月選擇器功能

    Android如何實(shí)現(xiàn)年月選擇器功能

    這篇文章主要介紹了Android如何實(shí)現(xiàn)年月選擇器功能,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下
    2021-03-03
  • Android中實(shí)現(xiàn)下載URL地址的網(wǎng)絡(luò)資源的實(shí)例分享

    Android中實(shí)現(xiàn)下載URL地址的網(wǎng)絡(luò)資源的實(shí)例分享

    這篇文章主要介紹了Android中實(shí)現(xiàn)下載URL地址的網(wǎng)絡(luò)資源的實(shí)例,其中還有一個(gè)進(jìn)行多線程下載的Java代碼示例,非常典型,需要的朋友可以參考下
    2016-04-04
  • Android彈出DatePickerDialog并獲取值的方法

    Android彈出DatePickerDialog并獲取值的方法

    這篇文章主要為大家詳細(xì)介紹了Android彈出DatePickerDialog并獲取值的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • Handler實(shí)現(xiàn)倒計(jì)時(shí)功能

    Handler實(shí)現(xiàn)倒計(jì)時(shí)功能

    這篇文章主要為大家詳細(xì)介紹了Handler實(shí)現(xiàn)倒計(jì)時(shí)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • Android入門(mén)之讀寫(xiě)本地文件的實(shí)現(xiàn)

    Android入門(mén)之讀寫(xiě)本地文件的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Android如何實(shí)現(xiàn)讀寫(xiě)本地文件的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Android有一定的幫助,需要的可以參考一下
    2022-12-12
  • Android編程中關(guān)于單線程模型的理解與分析

    Android編程中關(guān)于單線程模型的理解與分析

    這篇文章主要介紹了Android編程中關(guān)于單線程模型的理解與分析,較為詳細(xì)的分析了Android編程中關(guān)于單線程的原理與相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • Android獲取所在時(shí)區(qū)時(shí)間的兩種方式

    Android獲取所在時(shí)區(qū)時(shí)間的兩種方式

    Android獲取所在時(shí)區(qū)正確時(shí)間的方式有兩種,通過(guò)wifi獲取時(shí)間和通過(guò)通過(guò)GPS獲取時(shí)間這兩種方式,文中通過(guò)代碼示例給大家的介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04
  • SpringBoot實(shí)現(xiàn)短信驗(yàn)證碼登錄功能(案例)

    SpringBoot實(shí)現(xiàn)短信驗(yàn)證碼登錄功能(案例)

    這篇文章主要介紹了SpringBoot實(shí)現(xiàn)短信驗(yàn)證碼登錄功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-08-08

最新評(píng)論

黄冈市| 石河子市| 托克逊县| 灵武市| 姚安县| 车致| 舒城县| 城固县| 特克斯县| 全南县| 元江| 资兴市| 获嘉县| 灵璧县| 常山县| 博客| 公主岭市| 夏津县| 淮滨县| 新安县| 井冈山市| 于都县| 涟水县| 鱼台县| 阿拉善左旗| 云安县| 集贤县| 宜春市| 弥渡县| 邢台市| 鹤山市| 台中市| 南木林县| 岳池县| 遵化市| 仁化县| 肃北| 大庆市| 济阳县| 夏邑县| 罗定市|