深入Flutter渲染-Android端

1,223 阅读6分钟

深入Flutter渲染-Android端

前言

前面讲到了渲染一,渲染二的原理都是Flutter端的渲染,但我们还是不知道Flutter端的UI是如何显示到手机屏幕上的,今天我们讲下在Android端是如何与Flutter端进行交互,渲染UI的。

先上图:Android端Flutter渲染流程图

Flutter渲染流程-Android端.png

1.1 Android端入口FlutterActivity

当我们创建一个flutter项目工程时,会看到工程中的Activity是继承于FlutterActivity的;这里FlutterActivity 就是Android端程序的入口,我们看下FlutterActivity 中onCreate方法内部做了什么处理;

FlutterActivity.java

Untitled.png Untitled 1.png

内部创建了一个代理类FlutterActivityAndFragmentDelegate 其实FlutterActivity 内部的操作基本上都是代理类FlutterActivityAndFragmentDelegate 处理的;包括生命周期的处理。

1.2 Flutter引擎创建

从[1.1]中看到创建完delegate后调用了onAttach()方法,这个方法内部是创建FlutterEngine引擎的;

FlutterActivityAndFragmentDelegate.java

Untitled 2.png Untitled 3.png

从这里可以看到创建引擎时会先从缓存中去取FlutterEngine,如果没有则去创建一个;这个需要注意的是如果创建的项目是一个Flutter项目,那么在Android端它只会有一个FlutterActivity去承载Flutter端的UI渲染,也只有一个FlutterEngine引擎;但如果是混合开发,可能是Flutter跳转原生页面,原生页面又跳转Flutter页面,那这里就会涉及多个FlutterEngine引擎的问题,因为创建一次FlutterActivity就等于又创建一个新的引擎了;那多个引擎之间是内存隔离,内存数据不共享的,会出现很多的问题;所以现在混合开发一般使用FlutterBoost这个框架去处理路由及引擎的问题,当然这个框架本身也存在不少坑,如果可以尽量不要混合开发。

当然我们也看到了上面不是有从缓存中去取引擎的方法嘛,怎么就不共享引擎了呢?

其实多个FlutterActivity是可以做到共享引擎的,我们在创建Intent的时候使用CachedEngineIntentBuilder 这个类去创建Intent就可以了;如下:

//引擎id需要自己定义了
Intent intent = new FlutterActivity
            .CachedEngineIntentBuilder(FlutterActivity.class, getCachedEngineId())
            .build(this);

1.3 FlutterRenderer

[1.2]中我们已经成功的创建了Flutter引擎的,下面看下引擎内部有什么处理;这里最重要的一个变量是renderer;在创建引擎的时候创建了FlutterRenderer对象;它主要是Flutter端传递过来的渲染纹理,并通过JNI将一些Java调用转发给本地的Flutter代码;但最终的绘制还是要交给各端用于具体绘的类,例如Android端是SurfaceView 见[1.5]。

FlutterEngine.java

public FlutterEngine(
            @NonNull Context context,
            @Nullable FlutterLoader flutterLoader,
            @NonNull FlutterJNI flutterJNI,
            @NonNull PlatformViewsController platformViewsController,
            @Nullable String[] dartVmArgs,
            boolean automaticallyRegisterPlugins,
            boolean waitForRestorationData) {
        ///....省略前面的代码
        this.renderer = new FlutterRenderer(flutterJNI);

        this.platformViewsController = platformViewsController;
        this.platformViewsController.onAttachedToJNI();
        this.pluginRegistry =
                new FlutterEngineConnectionRegistry(context.getApplicationContext(), this, flutterLoader);
        if (automaticallyRegisterPlugins) {
            registerPlugins();
        }
    }

回到1.1中我们在onAttach()方法中创建了Flutter引擎;再看下createFlutterView()方法内部是什么情况。

1.4 FlutterView 的创建及引擎绑定

FlutterActivityAndFragmentDelegate.java

Untitled 4.png

这里先创建了一个FlutterSurfaceView 对象(会根据实际情况进行创建,只要是RenderSurface 子类即可),后又创建了FlutterView ;最后将二者关联起来,FlutterView 绑定FlutterEngine;其实这里的FlutterSurfaceView 就是Android端绘制UI的地方;我们看下他们是怎么关联的[见1.5]。

1.5 FlutterView

其实FlutterView在Android中是一个继承FrameLayout的普通类,让它变的特殊的是它内部绑定了SurfaceView去绘制的UI;

Untitled 5.png

FlutterView.java

Untitled 6.png Untitled 7.png 可以看到内部只做了二个操作,将外面传递进来的SurfaceView 保存起来,将SurfaceView 添加到View上;这里要注意下SurfaceView 有很多子类的,有很多种;每种的实现有点不一样,但官方是推荐使用FlutterSurfaceView ;因为它的性能最好,如果硬件支持还可以实现GPU渲染加速功能。最终通过addView()方法将SurfaceView 添加到了FlutterView 上面。

通过[1.4]中可以看到最后一定是将FlutterViewFlutterEngine 进行了绑定;看下绑定方法内部做了什么处理;

FlutterView.java

Untitled 8.png

第一行代码是获取flutterRenderer对象,这个对象在1.3中FlutterEngine创建的时候创建的;第三行renderSurface.attachToRenderer(flutterRenderer) 则是将当前的FlutterView中的renderSurface对象与引擎中的flutterRenderer进行绑定;FlutterView创建的时候renderSurface对象就是外部传递过来的FlutterSurfaceView 对象;这个负责Flutter端渲染纹理的FlutterRenderer与负责具体绘制的FlutterSurfaceView 真正关联起来了;

1.6 FlutterSurfaceView

看下[1.5]中attachToRenderer() 方法的具体实现:

FlutterSurfaceView.java

Untitled 9.png Untitled 10.png

可以看出来,FlutterSurfaceView 这边初始化好后,就可以通过FlutterRenderer 通知Flutter端可以进行UI渲染了;当然最后的真正的渲染流程JNI层去完成的。

FlutterRenderer.java

Untitled 11.png

1.7 SurfaceView FlutterRenderer

从上面的分析中可以看出来**SurfaceViewFlutterRenderer之间的关系是协同工作,实现将Flutter UI渲染到Android设备屏幕上。SurfaceView提供了一个绘图表面,作为Flutter UI的显示容器,而FlutterRenderer**则负责将Flutter的UI元素绘制到该表面上。通过这种协作,Flutter应用程序能够在Android平台上展示出高性能的渲染效果。

  1. SurfaceView:**SurfaceView是Android平台上的一个视图控件,用于在UI层次结构中显示图像和视频。它提供了一个专用的绘图表面(Surface),可以在独立的线程中进行绘制操作,从而避免了主线程的阻塞和卡顿。在Flutter中,SurfaceView**用于承载Flutter引擎的渲染结果,即将Flutter UI绘制到屏幕上。
  2. FlutterRenderer:**FlutterRenderer是Flutter引擎的一部分,是负责将Flutter的UI元素渲染到设备屏幕上的核心组件。它接收来自Flutter引擎的绘制命令,并将其转换为底层图形库的操作,最终在SurfaceView上绘制出Flutter的UI。FlutterRenderer**负责处理绘制、布局和输入事件,并与底层图形库(如Skia)进行交互,实现高性能的渲染和交互体验。

1.8 Flutter端入口main.dart

上面的流程我们了解了Flutter端与Android端的渲染流程是如何关联交互的,目前为止我们还没有进入到flutter页面中,当然也不会进行渲染,前面的工作只是说双方的渲染交互初始化工作做好了;现在可以进行页面渲染了。从[1.1]中我们FlutterActivityonCreate()方法执行完后,会经过生命周期onStart() 方法,当然也是调用的代理类中的onStart() 方法,在这个方法内部我们会调用flutter的入口程序main.dart

FlutterActivityAndFragmentDelegate.java

Untitled 12.png Untitled 13.png

DartExecutor.java

Untitled 14.png

从上面可以看到最终执行的是通过flutterJNI去执行的,要执行的类名是entrypointFunctionName

这个参数传递过去的;host.getDartEntrypointFunctionName()最终看到是调用的FlutterActivity复写返回的参数。

FlutterActivity.java

Untitled 15.png Untitled 16.png

经过层层调用最终看到了我们熟悉的main这个字符,所以在onstart()方法中我们最终调用到了flutter端的main.dart这个类,这样我们就进入到了flutter的世界,后续可以在flutter端愉快的开发了。当然关于flutter页面渲染我们也不用操心,在flutter端进行了UI的纹理绘制后,会将纹理数据通过底层(C/C++实现)与SurfaceView 进行交互渲染。

相关文章:

  1. 深入Flutter渲染更新机制一
  2. 深入Flutter渲染更新机制二
  3. 深入Flutter渲染-Android端
  4. 深入理解StatefulWidget生命周期