Android Flutter实现原理浅析

目录
  • 前言
  • 一.安卓原生界面绘制的流程
    • 原生绘制流程
    • SurfaceView绘制流程
  • 二.Flutter上界面绘制的流程
    • FlutterActivity中的流程
    • FlutterView中的实现
    • native流程
  • 三.总结
    • Flutter的简单实现原理
    • 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方法:

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();
            }
        }
        ...
    }

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

FlutterView中的实现

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

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

public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
            super(context, attrs);
            ...
            //创建在native层的处理对象,相关绘制逻辑其实都是在native层处理的,Java层只负责传入
            this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
            //创建dart的解释器
            this.dartExecutor = this.mNativeView.getDartExecutor();
            //创建渲染对象
            this.flutterRenderer = new FlutterRenderer(this.mNativeView.getFlutterJNI());
            //native层的view对象进行绑定
            this.mNativeView.attachViewAndActivity(this, activity);
            //由于是surfaceView,所以在surface创建好之后传入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();

其构造方法中,主要流程就是各种功能的初始化,以及完成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()方法。

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));
}

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

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

void PlatformViewAndroid::NotifyCreated(
    fml::RefPtr<AndroidNativeWindow> native_window) {
  if (android_surface_) {
    //1
    InstallFirstFrameCallback();
    ...
  }
  //2
  PlatformView::NotifyCreated();
}

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

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

第二件:启动渲染流程。

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

void PlatformView::NotifyCreated() {
  std::unique_ptr<Surface> surface;
  ...
  delegate_.OnPlatformViewCreated(std::move(surface));
}

这个delegate_其实是shell对象,则会调用到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线程执行,渲染的流程
  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();
    }
  };
  ...
    //启动各种渲染的流程
    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();
  }
}

这个方法中,主要就是各种检查,包括一些锁机制的判断,最后通知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两种方式,自然是最优的选择。

到此这篇关于Android Flutter实现原理浅析的文章就介绍到这了,更多相关Android Flutter内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android Flutter表格组件Table的使用详解

    目录 Table.TabRow.TabCell 小结 之前开发中用到的表格,本篇文章主要介绍如何在页面中使用表格做一个记录. Table组件不同于其它Flex布局,它是直接继承的RenderObjectWidget的.相当于是一个独立的组件,区别与其他系列组件. Table.TabRow.TabCell 惯例,先看下Table相关的构造方法: Table({ Key? key, this.children = const <TableRow>[],//行列表 表示多少行 this.column

  • Android Flutter图片处理之高斯模糊的实现

    目录 ImageFilter 横向模糊 垂直模糊 xy轴同时模糊 用法 BackdropFilter ImageFiltered 区别 ImageFilter 在Flutter中,使图片模糊有2种方式,这2种方式都需要配合ImageFilter.blur()使用. factory ImageFilter.blur({ double sigmaX = 0.0, double sigmaY = 0.0, TileMode tileMode = TileMode.clamp }) sigmaX:以x轴

  • Android Flutter利用CustomPaint绘制基本图形详解

    目录 绘制矩形 绘制圆形 绘制椭圆 绘制任意形状 绘制弧形 总结 上一篇我们介绍了 CustomPaint 的基本概念和使用,可以看到 CustomPaint 其实和 前端的 Canvas基本上是一样的,实际上前端 Canvas 支持的绘制方法 CustomPaint 都支持,毕竟 CustomPaint 其实也是基于 Canvas 实现的.本篇我们来介绍 CustomPaint 基本图形的绘制. 绘制矩形 绘制矩形比较简单,方法定义如下: void drawRect(Rect rect, Pa

  • Android使用Flutter实现录音插件

    目录 安卓部分 手动注册 Android和Dart的通讯 安卓录音 Dart module部分 iOS部分 手动注册插件 iOS插件 Dart调用部分 原生提供功能,Dart module 通过 method channel 异步调用 安卓部分 手动注册 Flutter 官方的做法,就是自动注册插件, 很方便 手动注册,体现本文的不同 插件是 AudioRecorderPlugin class MainActivity: FlutterActivity() { override fun onCr

  • Android Flutter绘制有趣的 loading加载动画

    目录 前言 效果1:圆环内滚动的球 效果2:双轨运动 效果3:钟摆运动 总结 前言 在网络速度较慢的场景,一个有趣的加载会提高用户的耐心和对 App 的好感,有些 loading 动效甚至会让用户有想弄清楚整个动效过程到底是怎么样的冲动.然而,大部分的 App的 loading 就是下面这种千篇一律的效果 —— 俗称“转圈”. 本篇我们利用Flutter 的 PathMetric来玩几个有趣的 loading 效果. 效果1:圆环内滚动的球 如上图所示,一个红色的小球在蓝色的圆环内滚动,而且在往

  • Android Flutter实现GIF动画效果的方法详解

    目录 前言 交错动画机制 代码实现 Interval 介绍 总结 前言 我们之前介绍了不少有关动画的篇章.前面介绍的动画都是只有一个动画效果,那如果我们想对某个组件实现一组动效,比如下面的效果,该怎么办? staggered animation 这个时候我们需要用到组合动效, Flutter 提供了交错动画(Staggered Animation)的方式实现.对于多个 Anmation 对象,可以共用一个 AnimationController,然后在不同的时间段执行动画效果.这就有点像 GIF

  • Android利用Flutter实现立体旋转效果

    目录 前言 ImageShader 简介 构建 ui.Image对象 使用 ImageShader 填充形状 立体旋转效果实现 总结 前言 之前我们提到了 CustomPaint er 的 Paint 可以使用渐变(GradientShader)来填充绘制的图形,本篇我们来介绍使用图片填充,并且配合动画实现“立体”旋转效果,之所以给“立体”加上引号,是因为实际是通过填充图片自身的光影效果旋转后看起来像是立体效果一样.下面是实现的效果图. ImageShader 简介 ImageShader 的定

  • Android Flutter实现搜索的三种方式详解

    目录 示例 1 :使用搜索表单创建全屏模式 编码 示例 2:AppBar 内的搜索字段(最常见于娱乐应用程序) 编码 示例 3:搜索字段和 SliverAppBar 编码 结论 示例 1 :使用搜索表单创建全屏模式 我们要构建的小应用程序有一个应用程序栏,右侧有一个搜索按钮.按下此按钮时,将出现一个全屏模式对话框.它不会突然跳出来,而是带有淡入淡出动画和幻灯片动画(从上到下).在圆形搜索字段旁边,有一个取消按钮,可用于关闭模式.在搜索字段下方,我们会显示一些搜索历史记录(您可以添加其他内容,如建

  • Android Flutter制作交错动画的示例代码

    目录 前言 动画解析 编码实现 总结 前言 之前一篇我们讲了 Flutter组合动画实现的方式 —— 交错动画.借助 GIF 和绘图技巧是可以做到类似 GIF 那种效果的.本篇我们来一个应用实例,我们让轮子在草地滚动着前进,而且还能粘上“绿色的草”,运行效果如下动画所示. 动画解析 上面实现的效果实际上由三个动画组成: 轮子前进的动画 轮子滚动 轮子的边缘颜色渐变(由黑色变成绿色) 这三个动画是同时进行的,因此需要使用到交错动画,即使用一个 AnimationController来控制三个 Tw

  • Android Flutter实现原理浅析

    目录 前言 一.安卓原生界面绘制的流程 原生绘制流程 SurfaceView绘制流程 二.Flutter上界面绘制的流程 FlutterActivity中的流程 FlutterView中的实现 native流程 三.总结 Flutter的简单实现原理 Flutter的几个高频问题 前言 flutter可以说是当下最流行的跨平台技术了,其最突出的 网上可以搜到的文章,大多数都是flutter的用法,即使介绍其实现原理的,也直接深入源码直接解读,造成只有一定功能的读者才能理解. 本文希望以最通俗易解

  • Android微信抢红包功能的实现原理浅析

    快到过农历年了,微信红包也越来越多了,出现了好多红包外挂程序,就很好奇如何实现的,于是自己研究了一番,亲自写了个微信抢红包的APP.现在就一步一步来实现它. 实现思路 微信抢红包程序开启时候,他就可以随时识别.捕获红包,服务可以实现正在功能,当我们开启服务的时候,服务就不停的在后台运行,不停地轮询着微信里面的消息,当发现红包时候就立即打开微信红包所在的界面.但是他怎识别红包呢?需要找到微信抢红包里面节点的view,当找到对应的view,在获取view的关键字或者id,根据关键字或者id,自动的模

  • Javascript自执行匿名函数(function() { })()的原理浅析

    函数是JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途.匿名函数指没有指定函数名或指针的函数,自执行匿名函数只是其中一种,下文中称这种函数为:自执行函数 下面是一个最常见的自执行函数: // 传统匿名函数 (function() { alert('hello'); })(); 这段代码的执行效果就是在页面再载入时弹出:"hello" 是什么促使它自动执行的?,来看下面的代码 // 在传统写法上去掉小括号,并在前面加上运算符 ~,!,+,- ~function(){

  • Android 推送原理(Android Push Notification)详解

    Android 推送原理 由于最近项目中涉及到了Android推送,所以看了一些关于android推送方面的东西,总结到后面我们知道android推送的实现可以归结为3种: 1.POLL,拉.大致思路为向服务器定时的发送请求,然后自己让服务器返回信息. 优点:实现简单. 缺点:实时性差.如果定时间隔小连接数又多,对服务器会有高压力要求.据说还会费电--不知道是不是真的. 2.SMS,彩信方式.据说是拦截彩信,并解析内容.这个还没有动手实践过. 优点:实现简单.实时性也好. 缺点:SMS服务的成本

  • Android 属性动画原理与DataBinding

    Android 属性动画原理与DataBinding 看到这个标题的时候你可能会有疑问,属性动画和 DataBinding 之间有什么关系?我个人理解的是:它们内部的实现思想有相似之处.这篇文章主要对 Android 属性动画的知识通过文字进行整理记录,内容参考于<Android开发艺术探索>,在最后会给出我如此理解属性动画和 DataBinding 的原因. Android动画概述: Android 的动画可以分为三种:View 动画.帧动画和属性动画,View 动画通过对场景里的对象不断做

  • Java 读写锁实现原理浅析

    最近做的一个小项目中有这样的需求:整个项目有一份config.json保存着项目的一些配置,是存储在本地文件的一个资源,并且应用中存在读写(读>>写)更新问题.既然读写并发操作,那么就涉及到操作互斥,这里自然想到了读写锁,本文对读写锁方面的知识做个梳理. 为什么需要读写锁? 与传统锁不同的是读写锁的规则是可以共享读,但只能一个写,总结起来为:读读不互斥,读写互斥,写写互斥,而一般的独占锁是:读读互斥,读写互斥,写写互斥,而场景中往往读远远大于写,读写锁就是为了这种优化而创建出来的一种机制. 注

  • java DelayQueue的原理浅析

    在对DelayQueue延迟功能的使用上,很多人不能后完全理解延迟的一些功能使用,这里我们深入来挖掘一下DelayQueue的原理. 下面将从构造方法.接口.继承体系三个方面进行分析,需要注意的是,相较于其它的阻塞队列,DelayQueue因为延迟的功能多了接口的使用,一起来看具体内容. 1.构造方法 public DelayQueue() {} public DelayQueue(Collection<? extends E> c) { this.addAll(c); } 构造方法比较简单,

  • Android Binder的原理与使用

    前言 Binder是安卓中实现IPC(进程间通信的)常用手段,四大组件之间的跨进程通信也是利用Binder实现的,Binder是学习四大组件工作原理的的一个重要基础. 好多文章都会深入C代码去介绍Binder的工作流程,没点水平真的难以理解,本文不会太深入底层去剖析原理,尽可能较为简单的让大家了解Binder是怎么工作的. Binder的使用 在介绍Binder原理之前,我们先来看看在安卓中怎么使用Binder来进程间通信. 在使用之前我们先来介绍Binder的几个方法: public fina

  • Android Flutter自适应瀑布流案例详解

    目录 Flutter自适应瀑布流 根据效果图可以分为四步: 1.图片自适应: 2.自适应标签: 3.上拉刷新和下拉加载 4.底部的点赞按钮 Flutter自适应瀑布流 前言:在电商app经常会看到首页商品推荐的瀑布流,或者类似短视频app首页也是瀑布流,这些都是需要自适应的,才能给用户带来好的体验 (具体代码请联系我,当天会回复) 话不多说先上效果图: 根据效果图可以分为四步: 图片自适应 自适应标签 上拉刷新和下拉加载 底部的点赞按钮可以去掉或者自己修改样式,我这里使用的like_button

  • 详解Android Lint的原理及其使用

    Android Lint 原理及使用详解 Android Lint 是 ADT 16中引入的新工具,用于扫描 Android 项目源中的潜在错误. Lint 是 Android 提供的一个强大的,用于静态扫描应用源码并找出其中的潜在问题的实用工具.lint 工具可以检查你的 Android 项目源文件是否有潜在的错误,以及在正确性.安全性.性能.易用性.无障碍性和国际化方面是否需要优化改进. Lint 既可以用作命令行工具,也可以与 Eclipse 和 IntelliJ 集成在一起.它被设计成独

随机推荐