深入Flutter渲染-Android端
前言
前面讲到了渲染一,渲染二的原理都是Flutter端的渲染,但我们还是不知道Flutter端的UI是如何显示到手机屏幕上的,今天我们讲下在Android端是如何与Flutter端进行交互,渲染UI的。
先上图:Android端Flutter渲染流程图
1.1 Android端入口FlutterActivity
当我们创建一个flutter项目工程时,会看到工程中的Activity是继承于FlutterActivity
的;这里FlutterActivity
就是Android端程序的入口,我们看下FlutterActivity
中onCreate方法内部做了什么处理;
FlutterActivity.java
内部创建了一个代理类FlutterActivityAndFragmentDelegate
其实FlutterActivity
内部的操作基本上都是代理类FlutterActivityAndFragmentDelegate
处理的;包括生命周期的处理。
1.2 Flutter
引擎创建
从[1.1]中看到创建完delegate后调用了onAttach()方法,这个方法内部是创建FlutterEngine引擎的;
FlutterActivityAndFragmentDelegate.java
从这里可以看到创建引擎时会先从缓存中去取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
这里先创建了一个FlutterSurfaceView
对象(会根据实际情况进行创建,只要是RenderSurface
子类即可),后又创建了FlutterView
;最后将二者关联起来,FlutterView
绑定FlutterEngine
;其实这里的FlutterSurfaceView
就是Android端绘制UI的地方;我们看下他们是怎么关联的[见1.5]。
1.5 FlutterView
类
其实FlutterView在Android中是一个继承FrameLayout的普通类,让它变的特殊的是它内部绑定了SurfaceView
去绘制的UI;
FlutterView.java
可以看到内部只做了二个操作,将外面传递进来的
SurfaceView
保存起来,将SurfaceView
添加到View上;这里要注意下SurfaceView
有很多子类的,有很多种;每种的实现有点不一样,但官方是推荐使用FlutterSurfaceView
;因为它的性能最好,如果硬件支持还可以实现GPU渲染加速功能。最终通过addView()方法将SurfaceView
添加到了FlutterView
上面。
通过[1.4]中可以看到最后一定是将FlutterView
与FlutterEngine
进行了绑定;看下绑定方法内部做了什么处理;
FlutterView.java
第一行代码是获取flutterRenderer
对象,这个对象在1.3中FlutterEngine
创建的时候创建的;第三行renderSurface.attachToRenderer(flutterRenderer)
则是将当前的FlutterView
中的renderSurface
对象与引擎中的flutterRenderer
进行绑定;FlutterView
创建的时候renderSurface
对象就是外部传递过来的FlutterSurfaceView
对象;这个负责Flutter端渲染纹理的FlutterRenderer
与负责具体绘制的FlutterSurfaceView
真正关联起来了;
1.6 FlutterSurfaceView
类
看下[1.5]中attachToRenderer()
方法的具体实现:
FlutterSurfaceView.java
可以看出来,FlutterSurfaceView
这边初始化好后,就可以通过FlutterRenderer
通知Flutter端可以进行UI渲染了;当然最后的真正的渲染流程JNI层去完成的。
FlutterRenderer.java
1.7 SurfaceView
和 FlutterRenderer
从上面的分析中可以看出来**SurfaceView
和FlutterRenderer
之间的关系是协同工作,实现将Flutter UI渲染到Android设备屏幕上。SurfaceView
提供了一个绘图表面,作为Flutter UI的显示容器,而FlutterRenderer
**则负责将Flutter的UI元素绘制到该表面上。通过这种协作,Flutter应用程序能够在Android平台上展示出高性能的渲染效果。
- SurfaceView:**
SurfaceView
是Android平台上的一个视图控件,用于在UI层次结构中显示图像和视频。它提供了一个专用的绘图表面(Surface),可以在独立的线程中进行绘制操作,从而避免了主线程的阻塞和卡顿。在Flutter中,SurfaceView
**用于承载Flutter引擎的渲染结果,即将Flutter UI绘制到屏幕上。 - FlutterRenderer:**
FlutterRenderer
是Flutter引擎的一部分,是负责将Flutter的UI元素渲染到设备屏幕上的核心组件。它接收来自Flutter引擎的绘制命令,并将其转换为底层图形库的操作,最终在SurfaceView
上绘制出Flutter的UI。FlutterRenderer
**负责处理绘制、布局和输入事件,并与底层图形库(如Skia)进行交互,实现高性能的渲染和交互体验。
1.8 Flutter
端入口main.dart
上面的流程我们了解了Flutter端与Android端的渲染流程是如何关联交互的,目前为止我们还没有进入到flutter页面中,当然也不会进行渲染,前面的工作只是说双方的渲染交互初始化工作做好了;现在可以进行页面渲染了。从[1.1]中我们FlutterActivity
中onCreate()
方法执行完后,会经过生命周期onStart()
方法,当然也是调用的代理类中的onStart()
方法,在这个方法内部我们会调用flutter的入口程序main.dart
FlutterActivityAndFragmentDelegate.java
DartExecutor.java
从上面可以看到最终执行的是通过flutterJNI去执行的,要执行的类名是entrypointFunctionName
这个参数传递过去的;host.getDartEntrypointFunctionName()
最终看到是调用的FlutterActivity
复写返回的参数。
FlutterActivity.java
经过层层调用最终看到了我们熟悉的main
这个字符,所以在onstart()
方法中我们最终调用到了flutter端的main.dart
这个类,这样我们就进入到了flutter的世界,后续可以在flutter端愉快的开发了。当然关于flutter页面渲染我们也不用操心,在flutter端进行了UI的纹理绘制后,会将纹理数据通过底层(C/C++实现)与SurfaceView
进行交互渲染。
相关文章: