点击上方蓝字关注我,知识会给你力量
Flutter容器
Flutter在Android中的渲染载体就是Flutter容器,通常是以Activity和Fragment的形式承载,虽然也有FlutterView,但是需要单独处理的关联方法太多,所以不太建议使用,这篇文章将分析Flutter在Android中的加载和启动流程,了解Flutter是如何在Android中加载并渲染的。
小小Android,easy easy!
FlutterActivity
FlutterActivity是最基本的Flutter容器,我们先来看看FlutterActivity的实现,类定义如下:
java
public class FlutterActivity extends Activity
implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
FlutterActivityAndFragmentDelegate.Host是我们暂时唯一不熟悉的内容,先来看看它是什么。FlutterActivityAndFragmentDelegate.Host看上去就是定义了一堆接口,这些可以理解为Flutter在运行时,需要Native所提供的抽象能力,而FlutterActivityAndFragmentDelegate,顾名思义,就是将Flutter在Activity和Fragment中的通用行为抽取出来的Delegate,从而做到功能的复用。
对于Activity来说,我们先从它的onCreate方法来看。在FlutterActivity初始化的时候,就是通过创建FlutterActivityAndFragmentDelegate的实例来进行一些初始化操作,包括delegate.onAttach,以及后面的createFlutterView,也是通过delegate.onCreateView来创建的。
而FlutterActivity中剩下的方法,大多都是实现FlutterActivityAndFragmentDelegate.Host的接口实现,以及对生命周期的绑定。由此可见,FlutterActivity的整体初始化流程,都被代理到了FlutterActivityAndFragmentDelegate这个天命打工人来处理了。
FlutterActivityAndFragmentDelegate
从命名就能看出这个类的重要性了,在注释中,我们可以了解到,FlutterActivityAndFragmentDelegate实现了Flutter和Activity、Fragment交互的所有逻辑。对于这个类,我们从onAttach和onCreateView两个方法来看,这两个方法,也是在FlutterActivity的onCreate中调用的方法。这个类的核心方法有两个,一个是setupFlutterEngine,用来创建一个FlutterEngine,另一个是host.configureFlutterEngine(flutterEngine),回调创建的Engine给外界,从而标志着Engine达到可用状态。
onCreateView方法稍微复杂一点,它会创建一个FlutterView,并将其通过setContentView设置给Activity。首先,会判断当前的渲染模式是Surface还是Texture,从而判断是创建FlutterSurfaceView还是FlutterTextureView,但不管是哪种,最后都会封装成FlutterView,并和FlutterEngine绑定。接下来就是添加一个首帧数据渲染完成的回调,这个回调对应Host中的两个方法:onFlutterUiDisplayed和onFlutterUiNoLongerDisplayed。
FlutterSplashView这块先不用管,大部分时间用不到。
后面就会调用FlutterView的attachToFlutterEngine方法,将FlutterView和Engine进行关联。
在FlutterActivity启动的生命周期中,还有一个onStart是比较重要的时间点,在这个方法中,会开始执行FlutterView中的Dart代码,可以认为,onStart之后,才是Flutter代码执行的开始。其中最重要的就是doInitialFlutterViewRun这个方法了。在这个方法中,我们看见了很多熟悉的配置,例如DartEntrypoint、initialRoute等等。
FlutterFragment
FlutterFragment和FlutterActivity如出一辙,唯一不同的是,FlutterFragment多实现了一个FlutterActivityAndFragmentDelegate.DelegateFactory。而它的实现,同样也是为了创建FlutterActivityAndFragmentDelegate。与FlutterActivity在onCreate中创建FlutterActivityAndFragmentDelegate不同的是,FlutterFragment选择在onAttach的时候创建。其它的流程与FlutterActivity基本一致。
FlutterFragmentActivity
从注释可以了解,FlutterFragmentActivity是对FragmentActivity的封装,帮你实现了一些要关联的生命周期API。我们同样先来看下它的onCreate实现。这里就很有意思了,为什么官方推荐使用FlutterFragmentActivity?原因就是这里,它对Fragment的生命周期等一系列问题,做了一些处理和防御,我们来看下这几个关键的方法。首先是retrieveExistingFlutterFragmentIfPossible。在onCreate前,先通过tag来取一次FragmentManager中的缓存。然后再看createFragmentContainer方法。这就是官方的实现,创建一个Fragment的容器。最后是ensureFlutterFragmentCreated方法。在这里,会重新从缓存中再拿一次FlutterFragment,如果还是没有,那么才会通过createFlutterFragment来创建新的FlutterFragment。这里就是创建Engine的一般方法,区分了不同种类的Engine,例如NewEngine、EngineGroup等。剩下的,就是一些生命周期函数的联动。参考官方FlutterFragmentActivity的做法,我们可以很好的处理自己添加FlutterFragment时产生的一些生命周期问题,果然,官方的做法才是最佳实践。
FlutterActivity、FlutterFragmentActivity、FragmentActivity的关系
在使用过程中,官方推荐使用FlutterActivity来作为Flutter的容器,从而避免自己去实现一些生命周期的绑定。那么对应FlutterFragment来说,如果载体是Activity或者是FragmentActivity,那么就需要自己来绑定一些生命周期,这些在文档中也有提到。https://flutter.cn/docs/add-to-app/android/add-flutter-fragment?tab=forward-activity-calls-kotlin-tab所以官方提供了FlutterFragmentActivity来给你打个样,告诉你该如何写,当然你也可以直接用。
源码中的log还是很多的,通过切换不同的tag,可以找到很多有用的信息。
FlutterEngine
在FlutterActivityAndFragmentDelegate的onAttach方法中,会通过setupFlutterEngine来创建FlutterEngine,那么FlutterEngine又是个什么东西呢?这里的代码还比较简单,无非是判断Engine类型,从而创建Engine,那么Engine到底是什么呢?我们来看下它类的定义。从大致的结构上,我们能猜测出它的作用,实际上是对一些关键逻辑类的管理,例如FlutterJNI、FlutterRenderer和一些System channels。我们找到它的构造方法。构造方法中,就是对这些逻辑管理类的一一初始化,还有插件的初始化,一个是FlutterEngineConnectionRegistry,另一个是GeneratedPluginRegister.registerGeneratedPlugins,这个东西,就是我们熟悉的内容了。这就是我们在Flutter中注册的这些插件,就是在此时此地初始化的。
FlutterLoader
在初始化过程中,我们还看见一个陌生的类——FlutterLoader。这个类是一个用于加载相关so资源的辅助类,我们主要关注它的startInitialization方法,而它里面最重要的就是对VsyncWaiter的初始化。这个类就是刷新同步的处理类。
VsyncWaiter
现代屏幕的刷新,是通过显示器的VSync信号来进行同步的,VsyncWaiter这个类,就是Flutter中这个信号的接收者,当我们调用它的init方法时,就是注册一个我们熟悉的Choreographer.FrameCallback,这就是Android中的VSync回调。在每次VSync信号的回调中,通过flutterJNI的Native方法,将同步信号传递给Flutter。
FlutterEngineGroup
FlutterEngineGroup维护了一个多引擎的管理实例。我们来看下构造方法。从上面的代码中我们可以发现,FlutterEngineGroup创建Engine的逻辑,当Engine不存在时,和普通FlutterEngine的创建是一样的,当Engine存在时,直接通过spawn方法来创建新的Engine实例。而这里又通过Native的spawn方法来创建新的JNI实例。FlutterEngineGroup正是通过这种方式,实现了低成本、高效率的Engine创建。
FlutterView
在FlutterActivityAndFragmentDelegate的onCreateView方法中,会创建FlutterView,这也是Android中用于承载Flutter内容的容器,我们来看下它的类申明。看来,FlutterView实际上是一个FrameLayout,这是因为它内部会放上不同的Child,例如FlutterSurfaceView、FlutterTextureView。它们的区别在文档中也有说明。大部分时间,我们使用Surface模式即可,只有当需要使用透明背景且有一些和NativeView的层级影响时,才需要使用Texture模式。同样的,我们先来看下FlutterSurfaceView的类定义。它其实就是一个SurfaceView,同样会在SurfaceHolder.Callback中创建渲染逻辑。实际的渲染逻辑在这里。最后压力给到了FlutterRenderer,看来渲染的实际打工人就是它了。
FlutterTextureView和它类似,就不单独看了。
不管是哪一种,它们都实现了RenderSurface接口,用于FlutterRenderer来调用其抽象方法。最后在FlutterView的init方法中,我们看到了具体的FlutterView是如何添加到容器中的。
FlutterImageView用的比较少,这里也不作展开。
FlutterRenderer
国际惯例,先看FlutterRenderer的申明。由此可见,FlutterRenderer的作用,就是连接了两个重要的内容:FlutterJNI和Surface。在startRenderingToSurface方法中,就是它们的关联方法。FlutterRenderer借助FlutterJNI,将Flutter的纹理渲染到Surface中,从而实现Flutter的画面渲染。
最后再整理下流程,最开始在FlutterActivityAndFragmentDelegate的onCreateView中,我们创建FlutterView,并调用FlutterView实例的attachToFlutterEngine方法将Engine的FlutterRenderer和RenderSurface的具体实现(FlutterSurfaceView或者是FlutterTextureView)进行绑定,从而将这一切捆绑起来。
事件传递
既然FlutterView是一个标准的AndroidView,那么它的事件是如何传递给Flutter的呢?首先,我们来看Android的一些系统回调,例如下面这些。剩下的就不截图了,可以参考源码中的Process View configuration that Flutter cares about这部分注释。这些代码基本类似,都是在这些Android的原生回调中,将事件传递到Flutter中,例如onSizeChanged回调中的sendViewportMetricsToFlutter方法。还有点击事件的处理,我们来看onTouchEvent和dispatchKeyEvent方法。最后的打工人,又来到了androidTouchProcessor,它是在attachToFlutterEngine的时候初始化的,AndroidTouchProcessor就是将触摸事件转发到Flutter的核心类。
上帝视角
来个整体流程图。
向大家推荐下我的网站 https://www.yuque.com/xuyisheng 点击原文一键直达
专注 Android-Kotlin-Flutter 欢迎大家访问
往期推荐
本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。
< END >
作者:徐宜生
更文不易,点个“三连”支持一下👇