• Flutter的实现原理初探


    前言:

    flutter可以说是当下最流行的跨平台技术了,其最突出的

    网上可以搜到的文章,大多数都是flutter的用法,即使介绍其实现原理的,也直接深入源码直接解读,造成只有一定功能的读者才能理解。

    本文希望以最通俗易解的方式介绍flutter的实现原理,也许不会介绍的深入或者详细,但是一定能让读者知道flutter的基本实现原理。

    本文基于flutter2.0的源码进行原理分析,3.0的源码有些许变动,但整体流程是一样的。

    一.安卓原生界面绘制的流程

    原生绘制流程

    有另外的一个系列文章来讲原生的界面,为了方便读者阅读,本文会简略描述一下整个流程。

    其主要流程是在每次sync的时候去执行测量(measure),布局(layout),绘制(draw)的流程。

    而draw的时候时候,核心是利用canvas执行各种绘制命令,并且把这些命令转换为buffer记录,最终发送给WMS层,然后转交给SurfaceFlinger,由其做最终的合成和渲染。

    SurfaceView绘制流程

    另外也许你还听说过另外一种可以在子线程渲染的控件:surfaceView。我们的视频播放器,高频绘制的自定义View都是由其实现的。

    其主要流程图如下:

    其原理其实和第一种方式类似,区别就是在于少了measure,layout的流程。而是自己去计算坐标,然后直接进入draw的流程,通过canvas写入native的数据buffer内存中,最后统一发送给WMS进行进入渲染的流程。

    而Flutter的实现原理,其实就和surfaceView类似。

    二.Flutter上界面绘制的流程

    flutter有混合开发和纯flutter开发两种。纯flutter使用的是FlutterActivity,而混合开发一般使用的是FlutterView。我们先看一下使用FlutterActivity的方式。

    FlutterActivity中的流程

    首先看一下FlutterActivity的实现,发现其核心流程都交给了FlutterActivityDelegate处理,所以我们直接看Delegate的onCreate方法:

    1. public void onCreate(Bundle savedInstanceState) {
    2. ...
    3. this.flutterView = this.viewFactory.createFlutterView(this.activity);
    4. if (this.flutterView == null) {
    5. FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
    6. this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
    7. this.flutterView.setLayoutParams(matchParent);
    8. this.activity.setContentView(this.flutterView);
    9. this.launchView = this.createLaunchView();
    10. if (this.launchView != null) {
    11. this.addLaunchView();
    12. }
    13. }
    14. ...
    15. }

    主要流程就是创建一个flutterView,添加到contentView中,所以其实无论哪种方式,最终都是由flutterView来实现的。

    FlutterView中的实现

    首先我们看一下FlutterView类,发现其继承自SurfaceView,这也回应了我们上面的描述,其核心实现原理就是基于surfaceView实现的。

    其构造方法如下:非核心代码已做了删减处理

    1. public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
    2. super(context, attrs);
    3. ...
    4. //创建在native层的处理对象,相关绘制逻辑其实都是在native层处理的,Java层只负责传入
    5. this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
    6. //创建dart的解释器
    7. this.dartExecutor = this.mNativeView.getDartExecutor();
    8. //创建渲染对象
    9. this.flutterRenderer = new FlutterRenderer(this.mNativeView.getFlutterJNI());
    10. //native层的view对象进行绑定
    11. this.mNativeView.attachViewAndActivity(this, activity);
    12. //由于是surfaceView,所以在surface创建好之后传入naitve
    13. this.mSurfaceCallback = new Callback() {
    14. public void surfaceCreated(SurfaceHolder holder) {
    15. FlutterView.this.assertAttached();
    16. FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
    17. }
    18. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    19. FlutterView.this.assertAttached();
    20. FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
    21. }
    22. public void surfaceDestroyed(SurfaceHolder holder) {
    23. FlutterView.this.assertAttached();
    24. FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed();
    25. }
    26. };
    27. this.getHolder().addCallback(this.mSurfaceCallback);
    28. //
    29. this.mActivityLifecycleListeners = new ArrayList();
    30. this.mFirstFrameListeners = new ArrayList();
    31. this.navigationChannel = new NavigationChannel(this.dartExecutor);
    32. this.keyEventChannel = new KeyEventChannel(this.dartExecutor);
    33. this.lifecycleChannel = new LifecycleChannel(this.dartExecutor);
    34. this.localizationChannel = new LocalizationChannel(this.dartExecutor);
    35. this.platformChannel = new PlatformChannel(this.dartExecutor);
    36. this.systemChannel = new SystemChannel(this.dartExecutor);
    37. this.settingsChannel = new SettingsChannel(this.dartExecutor);
    38. final PlatformPlugin platformPlugin = new PlatformPlugin(activity, this.platformChannel);
    39. this.addActivityLifecycleListener(new ActivityLifecycleListener() {
    40. public void onPostResume() {
    41. platformPlugin.updateSystemUiOverlays();
    42. }
    43. });
    44. this.mImm = (InputMethodManager)this.getContext().getSystemService("input_method");
    45. PlatformViewsController platformViewsController = this.mNativeView.getPluginRegistry().getPlatformViewsController();
    46. this.mTextInputPlugin = new TextInputPlugin(this, this.dartExecutor, platformViewsController);
    47. this.androidKeyProcessor = new AndroidKeyProcessor(this.keyEventChannel, this.mTextInputPlugin);
    48. this.androidTouchProcessor = new AndroidTouchProcessor(this.flutterRenderer);
    49. this.mNativeView.getPluginRegistry().getPlatformViewsController().attachTextInputPlugin(this.mTextInputPlugin);
    50. this.sendLocalesToDart(this.getResources().getConfiguration());
    51. this.sendUserPlatformSettingsToDart();
    52. }

    其构造方法中,主要流程就是各种功能的初始化,以及完成surface和native的绑定。

    我们可以看到下面这样代码,就是把surface传入了native层。

    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());

    所以看到这里,我们可以做这样的推测了:

    flutter原理其实就类似于surfaceView的实现。通过传递surface到native层,然后通过这个surface获取到canvas,写入渲染buffer,最终通知到WMS完成绘制的整个流程。

    native流程:

    onSurfaceCreated的创建最终会走到native层platform_view_android_jni_impl.cpp中的SurfaceCreated()方法。

    1. static void SurfaceCreated(JNIEnv* env,
    2. jobject jcaller,
    3. jlong shell_holder,
    4. jobject jsurface) {
    5. // Note: This frame ensures that any local references used by
    6. // ANativeWindow_fromSurface are released immediately. This is needed as a
    7. // workaround for https://code.google.com/p/android/issues/detail?id=68174
    8. fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env);
    9. auto window = fml::MakeRefCounted(
    10. ANativeWindow_fromSurface(env, jsurface));
    11. ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window));
    12. }

    这里很简单,创建native层的Window对象,调用NotifyCreated方法继续传入。

    走到platform_view.cc的NotifyCreated方法如下:

    1. void PlatformViewAndroid::NotifyCreated(
    2. fml::RefPtr native_window) {
    3. if (android_surface_) {
    4. //1
    5. InstallFirstFrameCallback();
    6. ...
    7. }
    8. //2
    9. PlatformView::NotifyCreated();
    10. }

    该方法中主要做了两件事:

    第一件:回调java的onFirstFrame方法;

    第二件:启动渲染流程。

    NotifyCreated中,主要是交给delegate_去处理:

    1. void PlatformView::NotifyCreated() {
    2. std::unique_ptr surface;
    3. ...
    4. delegate_.OnPlatformViewCreated(std::move(surface));
    5. }

    这个delegate_其实是shell对象,则会调用到shell.cc的OnPlatformViewCreated方法:

    1. // |PlatformView::Delegate|
    2. void Shell::OnPlatformViewCreated(std::unique_ptr surface) {
    3. TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
    4. FML_DCHECK(is_setup_);
    5. FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
    6. ...
    7. //这里主要是一系列的判断,避免死锁
    8. const bool should_post_raster_task =
    9. !task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread();
    10. fml::AutoResetWaitableEvent latch;
    11. //UI线程执行,渲染的流程
    12. auto raster_task =
    13. fml::MakeCopyable([&waiting_for_first_frame = waiting_for_first_frame_,
    14. rasterizer = rasterizer_->GetWeakPtr(), //
    15. surface = std::move(surface)]() mutable {
    16. if (rasterizer) {
    17. // Enables the thread merger which may be used by the external view
    18. // embedder.
    19. rasterizer->EnableThreadMergerIfNeeded();
    20. rasterizer->Setup(std::move(surface));
    21. }
    22. waiting_for_first_frame.store(true);
    23. });
    24. ...
    25. auto ui_task = [engine = engine_->GetWeakPtr()] {
    26. if (engine) {
    27. engine->OnOutputSurfaceCreated();
    28. }
    29. };
    30. ...
    31. //启动各种渲染的流程
    32. fml::TaskRunner::RunNowOrPostTask(task_runners_.GetIOTaskRunner(), io_task);
    33. latch.Wait();
    34. if (!should_post_raster_task) {
    35. // See comment on should_post_raster_task, in this case the raster_task
    36. // wasn't executed, and we just run it here as the platform thread
    37. // is the raster thread.
    38. raster_task();
    39. }
    40. }

    这个方法中,主要就是各种检查,包括一些锁机制的判断,最后通知engine启动去渲染surface了

    三.总结

    Flutter的简单实现原理:

    Flutter的简单实现原理其实就类似于surfaceView的实现。

    surfaceView中往buffer中写入渲染数据是通过java层的canvas实现的,而在flutter中是通过native层实现。flutter就是在native层接收到surface,然后通过surface获取到native层的canvas,对buffer进行写入,最终通知到WMS完成绘制的整个流程。

    当然,详细的原理还包含了事件流程是如何分发的,如何翻译dart成可执行的代码,如何解释编译的产物等等,由于篇幅限制,本篇就不详细展开了,后续会逐渐写文章进行原理分析。

    Flutter的几个高频问题:

    1.为什么主要流程使用jni实现?用Java实现是否可以?

    我的理解是其实java实现也是完全可以的,但是要知道flutter是跨平台的。如果用java的话,那么在安卓上是没问题的,但是如果在IOS势必又要用OC在写一套逻辑,这样造成重复的工作量。而使用C来编写,任意平台其实都是可以通用的,降低开发成本,而且更不容易出现差异。之前和蚂蚁金服antv(蚂蚁数据可视化团队)的朋友聊天时,他们也是类似的考虑,底层逻辑使用C实现,安卓/IOS/PC等只做上层的接口封装和兼容。

    2.为什么使用dart而不使用其他语言?

    这个我的理解是用JS应该也是可以的,或者说java也可以。但是又都不够好。

    如果是用java的话,flutter的热部署功能就无法实现,java类加载机制有缓存,一旦加载就无法被替换。当然不是绝对的,可以通过替换classLoader的方式进行替换,类似于tomcat的热部署。但如果这样,实现成本就会及其的高,而且性能不佳。

    使用js的话,实现热部署肯定是没有问题,但问题就在于生产环境,其实更需要的是效率。JIT的编译方式效率肯定是比不过AOT的。

    而dart同时支持AOT和JIT两种方式,自然是最优的选择。

  • 相关阅读:
    《计算机工程》期刊投稿记录(实时更新)
    windows的powershell中apt命令的替换命令
    C++算法 —— 动态规划(7)两个数组的dp
    【WebRTC---源码篇】(十:一)WEBRTC 发送视频RTP包
    云原生丨5大Datadog集成,快速提高团队效率!
    在内存分配时,使用 4096-1 的常见做法是为了实现对齐的目的
    洛谷 P1776:宝物筛选 ← 多重背包问题 二进制优化
    numpy对行操作总结
    Syncovery for Mac:高效文件备份和同步工具
    Redis基础
  • 原文地址:https://blog.csdn.net/AA5279AA/article/details/126165230