从源码看Flutter Android端的启动流程

d6d2da5ce8d55bcb78736550b7ceba75.png

点击上方蓝字关注我,知识会给你力量

77c8b3d982b6ea7e984f83eeb0626d63.png

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是我们暂时唯一不熟悉的内容,先来看看它是什么。caa9c0f085cc54c6a83092006ce6744d.pngFlutterActivityAndFragmentDelegate.Host看上去就是定义了一堆接口,这些可以理解为Flutter在运行时,需要Native所提供的抽象能力,而FlutterActivityAndFragmentDelegate,顾名思义,就是将Flutter在Activity和Fragment中的通用行为抽取出来的Delegate,从而做到功能的复用。

对于Activity来说,我们先从它的onCreate方法来看。90c35be99f5de7e71624b0018487223f.png在FlutterActivity初始化的时候,就是通过创建FlutterActivityAndFragmentDelegate的实例来进行一些初始化操作,包括delegate.onAttach,以及后面的createFlutterView,也是通过delegate.onCreateView来创建的。

而FlutterActivity中剩下的方法,大多都是实现FlutterActivityAndFragmentDelegate.Host的接口实现,以及对生命周期的绑定。7450192e8da200798e4723630b56f16f.png由此可见,FlutterActivity的整体初始化流程,都被代理到了FlutterActivityAndFragmentDelegate这个天命打工人来处理了。

FlutterActivityAndFragmentDelegate

从命名就能看出这个类的重要性了,在注释中,我们可以了解到,FlutterActivityAndFragmentDelegate实现了Flutter和Activity、Fragment交互的所有逻辑。557f9d7fd0831cf042ae41be449f97eb.png对于这个类,我们从onAttach和onCreateView两个方法来看,这两个方法,也是在FlutterActivity的onCreate中调用的方法。9efb3b36aa93b686acaf176d82779fbf.png这个类的核心方法有两个,一个是setupFlutterEngine,用来创建一个FlutterEngine,另一个是host.configureFlutterEngine(flutterEngine),回调创建的Engine给外界,从而标志着Engine达到可用状态。

onCreateView方法稍微复杂一点,它会创建一个FlutterView,并将其通过setContentView设置给Activity。8b4593541104092f81da425b035feaaf.png首先,会判断当前的渲染模式是Surface还是Texture,从而判断是创建FlutterSurfaceView还是FlutterTextureView,但不管是哪种,最后都会封装成FlutterView,并和FlutterEngine绑定。接下来就是添加一个首帧数据渲染完成的回调,这个回调对应Host中的两个方法:onFlutterUiDisplayed和onFlutterUiNoLongerDisplayed。

FlutterSplashView这块先不用管,大部分时间用不到。

后面就会调用FlutterView的attachToFlutterEngine方法,将FlutterView和Engine进行关联。

在FlutterActivity启动的生命周期中,还有一个onStart是比较重要的时间点,在这个方法中,会开始执行FlutterView中的Dart代码,可以认为,onStart之后,才是Flutter代码执行的开始。f221fa0584b1924d31c939fa124ddd83.png其中最重要的就是doInitialFlutterViewRun这个方法了。bab6a5d20dfffa66ef13e9046606e002.png在这个方法中,我们看见了很多熟悉的配置,例如DartEntrypoint、initialRoute等等。

FlutterFragment

FlutterFragment和FlutterActivity如出一辙,唯一不同的是,FlutterFragment多实现了一个FlutterActivityAndFragmentDelegate.DelegateFactory。7df31347bac1fc31dbbd9e4cfcc43850.png而它的实现,同样也是为了创建FlutterActivityAndFragmentDelegate。c1b0ff1f0eff9796bf8e4755b44bda6c.png与FlutterActivity在onCreate中创建FlutterActivityAndFragmentDelegate不同的是,FlutterFragment选择在onAttach的时候创建。7db884c52d1a6ef1a436203d9be6c891.png其它的流程与FlutterActivity基本一致。

FlutterFragmentActivity

从注释可以了解,FlutterFragmentActivity是对FragmentActivity的封装,帮你实现了一些要关联的生命周期API。709d7d69f199cc4e259805d7a670ca8b.png我们同样先来看下它的onCreate实现。272cd553ecb9684faa998743f62e7f56.png这里就很有意思了,为什么官方推荐使用FlutterFragmentActivity?原因就是这里,它对Fragment的生命周期等一系列问题,做了一些处理和防御,我们来看下这几个关键的方法。首先是retrieveExistingFlutterFragmentIfPossible。e9eba27c6c359ee4e40045d293ce12fd.png在onCreate前,先通过tag来取一次FragmentManager中的缓存。然后再看createFragmentContainer方法。c63819407f07d63e253be3a6d593f7ca.png这就是官方的实现,创建一个Fragment的容器。最后是ensureFlutterFragmentCreated方法。aa70e1ec3d2a94349234fc8fe957c23c.png在这里,会重新从缓存中再拿一次FlutterFragment,如果还是没有,那么才会通过createFlutterFragment来创建新的FlutterFragment。这里就是创建Engine的一般方法,区分了不同种类的Engine,例如NewEngine、EngineGroup等。40a4089f877a48dbf05c5174b50d9776.png02560f4535c7f18cd22be5d7a586a3c1.png剩下的,就是一些生命周期函数的联动。83f29f4725108e30beaa6a84bd4a0966.png参考官方FlutterFragmentActivity的做法,我们可以很好的处理自己添加FlutterFragment时产生的一些生命周期问题,果然,官方的做法才是最佳实践。

FlutterActivity、FlutterFragmentActivity、FragmentActivity的关系

在使用过程中,官方推荐使用FlutterActivity来作为Flutter的容器,从而避免自己去实现一些生命周期的绑定。5c9f17c707a52c85ee1520abac7cadc8.png那么对应FlutterFragment来说,如果载体是Activity或者是FragmentActivity,那么就需要自己来绑定一些生命周期,这些在文档中也有提到。https://flutter.cn/docs/add-to-app/android/add-flutter-fragment?tab=forward-activity-calls-kotlin-tab3cf33f907873b1908f1ab130810d1424.png所以官方提供了FlutterFragmentActivity来给你打个样,告诉你该如何写,当然你也可以直接用。

源码中的log还是很多的,通过切换不同的tag,可以找到很多有用的信息。

FlutterEngine

在FlutterActivityAndFragmentDelegate的onAttach方法中,会通过setupFlutterEngine来创建FlutterEngine,那么FlutterEngine又是个什么东西呢?058d4c1eea8d08f8a0228e3d650f9dff.png359b73874ab887dd3a2208021d040740.png这里的代码还比较简单,无非是判断Engine类型,从而创建Engine,那么Engine到底是什么呢?我们来看下它类的定义。f89969cceb2208141a8807f053d1276b.png从大致的结构上,我们能猜测出它的作用,实际上是对一些关键逻辑类的管理,例如FlutterJNI、FlutterRenderer和一些System channels。我们找到它的构造方法。1e97fdf2bad6eb04a3aef528a3d6fa1c.png4cb393c5abfba76553e11883a8b5a733.png构造方法中,就是对这些逻辑管理类的一一初始化,还有插件的初始化,一个是FlutterEngineConnectionRegistry,另一个是GeneratedPluginRegister.registerGeneratedPlugins,这个东西,就是我们熟悉的内容了。5b03bc52a5753b2b08968fba8af8c5dd.png这就是我们在Flutter中注册的这些插件,就是在此时此地初始化的。

FlutterLoader

在初始化过程中,我们还看见一个陌生的类——FlutterLoader。66304fd6e96ba8781075f7ce3612e56f.png这个类是一个用于加载相关so资源的辅助类,我们主要关注它的startInitialization方法,而它里面最重要的就是对VsyncWaiter的初始化。6b013cb6e5f9fb8c89a3e65b1c3fcdc2.png这个类就是刷新同步的处理类。

VsyncWaiter

现代屏幕的刷新,是通过显示器的VSync信号来进行同步的,VsyncWaiter这个类,就是Flutter中这个信号的接收者,当我们调用它的init方法时,就是注册一个我们熟悉的Choreographer.FrameCallback,这就是Android中的VSync回调。1552f4e9e291394a70c9b819948ec49b.png在每次VSync信号的回调中,通过flutterJNI的Native方法,将同步信号传递给Flutter。

FlutterEngineGroup

FlutterEngineGroup维护了一个多引擎的管理实例。e771e5ebc226411c5279e47a02a9aeaa.png我们来看下构造方法。b1b7efae5d836b80295565202bbcbb5e.pngbc8455a40c71a2c7a7f0a3ff632a0d34.png从上面的代码中我们可以发现,FlutterEngineGroup创建Engine的逻辑,当Engine不存在时,和普通FlutterEngine的创建是一样的,当Engine存在时,直接通过spawn方法来创建新的Engine实例。e2ba2d1f9b83fa8d2de7e6cd37a10114.png而这里又通过Native的spawn方法来创建新的JNI实例。6e8a64da43a142cbef50ac62d7b63bca.pngFlutterEngineGroup正是通过这种方式,实现了低成本、高效率的Engine创建。

FlutterView

在FlutterActivityAndFragmentDelegate的onCreateView方法中,会创建FlutterView,这也是Android中用于承载Flutter内容的容器,我们来看下它的类申明。b0239a67387d83dbe48b3206cbf07435.png看来,FlutterView实际上是一个FrameLayout,这是因为它内部会放上不同的Child,例如FlutterSurfaceView、FlutterTextureView。它们的区别在文档中也有说明。a2c668f5013c78ab839939356a3ac931.png大部分时间,我们使用Surface模式即可,只有当需要使用透明背景且有一些和NativeView的层级影响时,才需要使用Texture模式。同样的,我们先来看下FlutterSurfaceView的类定义。dcd6cfa3228b969b505f666dba0f71fb.png它其实就是一个SurfaceView,同样会在SurfaceHolder.Callback中创建渲染逻辑。8ff59ef9ef379b4e96d307a12b778beb.png实际的渲染逻辑在这里。f4aeec47fd674c3ccd6078394ac744bc.png最后压力给到了FlutterRenderer,看来渲染的实际打工人就是它了。

FlutterTextureView和它类似,就不单独看了。

不管是哪一种,它们都实现了RenderSurface接口,用于FlutterRenderer来调用其抽象方法。de08f4261b6c7aba35d5c729bd680bee.png最后在FlutterView的init方法中,我们看到了具体的FlutterView是如何添加到容器中的。8fd38a487c26e50e5c9f3dc8601e2700.png

FlutterImageView用的比较少,这里也不作展开。

FlutterRenderer

国际惯例,先看FlutterRenderer的申明。4af8d1590e28ef14b8466df67cfddd26.png由此可见,FlutterRenderer的作用,就是连接了两个重要的内容:FlutterJNI和Surface。在startRenderingToSurface方法中,就是它们的关联方法。FlutterRenderer借助FlutterJNI,将Flutter的纹理渲染到Surface中,从而实现Flutter的画面渲染。

最后再整理下流程,最开始在FlutterActivityAndFragmentDelegate的onCreateView中,我们创建FlutterView,并调用FlutterView实例的attachToFlutterEngine方法将Engine的FlutterRenderer和RenderSurface的具体实现(FlutterSurfaceView或者是FlutterTextureView)进行绑定,从而将这一切捆绑起来。

事件传递

既然FlutterView是一个标准的AndroidView,那么它的事件是如何传递给Flutter的呢?首先,我们来看Android的一些系统回调,例如下面这些。f0d4f57af7cdcc9d90f653ed98efe85c.png剩下的就不截图了,可以参考源码中的Process View configuration that Flutter cares about这部分注释。这些代码基本类似,都是在这些Android的原生回调中,将事件传递到Flutter中,例如onSizeChanged回调中的sendViewportMetricsToFlutter方法。be2c4e63d4eb64f5c4e20c9fe275e195.png还有点击事件的处理,我们来看onTouchEvent和dispatchKeyEvent方法。01069ca860c5e889c33614a71401d31a.png最后的打工人,又来到了androidTouchProcessor,它是在attachToFlutterEngine的时候初始化的,AndroidTouchProcessor就是将触摸事件转发到Flutter的核心类。6d4c3b8d9ed4b164fd835cc9df736cd1.png

上帝视角

来个整体流程图。acdcc5788abc56874d0b8b6a3d410086.jpeg

向大家推荐下我的网站 https://www.yuque.com/xuyisheng  点击原文一键直达

专注 Android-Kotlin-Flutter 欢迎大家访问

往期推荐

本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。

< END >

作者:徐宜生

更文不易,点个“三连”支持一下👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值