Flutter实践深入分析之——FlutterActivity/Fragment原理流程分析
Posted Beason_H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter实践深入分析之——FlutterActivity/Fragment原理流程分析相关的知识,希望对你有一定的参考价值。
文章目录
前言
之前了解了flutter从启动到view的创建流程,本文一起来分析下Flutter android端FlutterActivity和FlutterFragment代码流程分析。
Flutter Android在创建新Flutter项目的时候并没有看到FlutterActivity/FlutterFragment,原因是Flutter Android的源码主要在maven端,也就是:io.flutter:flutter_embedding_xxx包中,配置地方是在flutter.gradle,可查看文章“深度了解Flutter APP的构建流程”。
如果使用flutter1.12版本之前FlutterActivity位于io.flutter.app.FlutterActivity,该类已经被Deprecated掉了。所以本文以我们项目中使用的版本flutter2.0.6为例,FlutterActivity位于:io.flutter.embedding.android.Flutter,下面我们直接进入FlutterActivity/FlutterFragment分析
FlutterActivity分析
在Flutter App Android端默认的MainActivity就是继承自io.flutter.embedding.android.FlutterActivity
,该类展示的是一个全屏的Flutter UI。它的主要作用是:
- 显示Android的启动动画
- 下手Flutter的启动动画
- 配置状态栏
- 选择Dart执行应用程序包路径入口点(默认是main()),选择Flutter的初始路由
- 保存和回复实例状态
首先我们来看类声明部分
public class FlutterActivity extends Activity
implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
FlutterActivityAndFragmentDelegate.Host分析
根据继承关系可以发现,FlutterActivity直接继承于Activity,同时实现了FlutterActivityAndFrameDelegate.Host
,LifecycleOwner
接口。Activity和LifecycleOwner不做解释,我们来看FlutterActivityAndFragmentDelegate.Host
接口
class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
/**
* 扩展四个接口
* SplashScreenProvider,提供一个 SplashScreen 以在 Flutter 初始化和渲染其第一帧时显示
* FlutterEngineProvider,提供和创建FlutterEngine
* FlutterEngineConfigurator,在创建 FlutterEngine 后配置它,例如,添加插件
* PlatformPlugin.PlatformPluginDelegate,PlatformPlugin 通常为 Flutter 框架请求的平台功能实现了默认行为,允许实现者自定义 Flutter 框架调用弹出 Android 端导航堆栈时所需的行为。
*/
interface Host
extends SplashScreenProvider,
FlutterEngineProvider,
FlutterEngineConfigurator,
PlatformPlugin.PlatformPluginDelegate {
@NonNull
Context getContext();
// 是否从intent获取路由
@Nullable
boolean shouldHandleDeeplinking();
@Nullable
Activity getActivity();
// 获取Activity或者Fragment的Lifecycle
@NonNull
Lifecycle getLifecycle();
// 获取宿主启动Flutter携带的参数,通过intent解析,譬如enable-dart-profiling等。
@NonNull
FlutterShellArgs getFlutterShellArgs();
// 获取静态缓存的EngineId,如果没有就返回空,通过intent的cached_engine_id参数传递。
@Nullable
String getCachedEngineId();
// 引擎是否跟宿主一起destory
boolean shouldDestroyEngineWithHost();
// detach flutter engine
void detachFromFlutterEngine();
// 获取dart主入口,默认main。
@NonNull
String getDartEntrypointFunctionName();
// 返回app bundle dart代码存在的路径
@NonNull
String getAppBundlePath();
// 获取初始路由地址。
// 默认先从intent中解析route的值,没有就去meta-data解析io.flutter.InitialRoute的值,没有就返回null。
@Nullable
String getInitialRoute();
// 获取Flutter的渲染模式,详情见“[Flutter实践深入分析中——FlutterView相关源码分析](https://beason.blog.csdn.net/article/details/120929369)”
@NonNull
RenderMode getRenderMode();
// 获取Transparency模式,用在FlutterView呈现FlutterEngine引擎渲染效果
@NonNull
TransparencyMode getTransparencyMode();
// 提供一个Flutter开屏图片。
@Nullable
SplashScreen provideSplashScreen();
// 返回一个用来渲染FlutterView的FlutterEngine引擎
@Nullable
FlutterEngine provideFlutterEngine(@NonNull Context context);
// 创建和配置platform plugin。
@Nullable
PlatformPlugin providePlatformPlugin(
@Nullable Activity activity, @NonNull FlutterEngine flutterEngine);
// 根据需要配置FLutterEngine
void configureFlutterEngine(@NonNull FlutterEngine flutterEngine);
// 周期detached之前清除FlutterEngine配置
void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine);
// 如果 FlutterEngine 的插件系统已经连接到Activity,则返回 true,允许插件与其交互
boolean shouldAttachEngineToActivity();
void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView);
void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView);
// Flutter UI开始绘制时调用
void onFlutterUiDisplayed();
// Flutter停止绘制时调用
void onFlutterUiNoLongerDisplayed();
// 恢复状态
boolean shouldRestoreAndSaveState();
}
}
根据上面的源码分析可以知道FlutterActivityAndFragmentDelegate.Host提供的一系列相关引擎声明周期、Flutter UI绘制周期、插件相关周期等方法可以知道,它是一个中间层,它是Flutter与Activity/Fragment之间的一个接口约定,而宿主Activity/Fragment几乎不直接参加与Flutter之间的交互。这样做的好处有:
- 利于解耦,Flutter/Fragment不直接与Flutter交互,利于维护
- Flutter版本迭代快,利于项目后期Flutter SDK的升级,而不必修改任何原生代码
- 代码的重复利用,后面会介绍Fragment和FlutterFragmentActivity,大部分都是复用了FlutterActivityAndFragmentDelegate内部相关逻辑
下面我们再来看看FlutterActivity的onCreate方法
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
switchLaunchThemeForNormalTheme();
super.onCreate(savedInstanceState);
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(this);
delegate.onRestoreInstanceState(savedInstanceState);
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
configureWindowForTransparency();
setContentView(createFlutterView());
configureStatusBarForFullscreenFlutterExperience();
}
详细的介绍之前的文章有介绍这里不再详述,见:Flutter时间深入分析之——Flutter APP启动流程分析
FlutterActivityAndFragmentDelegate分析
从上面分析我们知道FlutterActivityAndFragmentDelegate.Host声明了大量的Activity/Fragment与Flutter平台通信的接口,那么FlutterActivityAndFragmentDelegate根据名字我们大概判断它就是Activity/Fragment的一个代理类,也是直接与Activity/Fragment进行交互的类。
下面一个个来分析FlutterActivityAndFragmentDelegate的核心方法
onAttach方法
onAttach方法在Activity的onCreate方法和Fragment的onAttach方法中被调用,核心源码:
void onAttach(@NonNull Context context) {
// 确保delegate没有被release
ensureAlive();
if (flutterEngine == null) {
setupFlutterEngine();
}
if (host.shouldAttachEngineToActivity()) {
flutterEngine.getActivityControlSurface().attachToActivity(this, host.getLifecycle());
}
platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
host.configureFlutterEngine(flutterEngine);
}
从上面的代码分析,attach方法主要职责:
- 初始化Flutter系统,确保delegate没有被release
- 获取(根据EngineID获取,目前还未正式使用)或者创建FlutterEngine
- 平台插件获取和自定义插件的注册
- 引擎配置。
onStart方法
onStart方法在Activity和Fragment的onStart方法被调用,核心源码:
// Activity和Fragment的onStart方法被调用,开始执行Dart 代码的入口(Dart代码如果没有执行的情况下)
void onStart() {
Log.v(TAG, "onStart()");
ensureAlive();
doInitialFlutterViewRun();
}
/**
* 首次在FlutterView中执行Dart代码
* 不支持在给定的FlutterView中重新加载、重启Dart。如果Dart已经运行,那么什么都不做
*/
private void doInitialFlutterViewRun() {
if (host.getCachedEngineId() != null) {
return;
}
if (flutterEngine.getDartExecutor().isExecutingDart()) {
return;
}
// 各种优先级获取初始跳转dart的路由地址。
String initialRoute = host.getInitialRoute();
if (initialRoute == null) {
initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
if (initialRoute == null) {
initialRoute = DEFAULT_INITIAL_ROUTE;
}
}
// 通过引擎的NavigationChannel设置初始路由信息。
flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
//按照优先级获取appBundlePath,默认从host获取,无则从FlutterLoader获取。
String appBundlePathOverride = host.getAppBundlePath();
if (appBundlePathOverride == null || appBundlePathOverride.isEmpty()) {
appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
}
// 配置dart的entrypoint并且执行,默认入口函数名为main,可通过meta-data的io.flutter.Entrypoint修改。
DartExecutor.DartEntrypoint entrypoint =
new DartExecutor.DartEntrypoint(
appBundlePathOverride, host.getDartEntrypointFunctionName());
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
}
onCreateView方法
看完上面的逻辑,引擎,插件,环境都已经准备妥当,接下来就是创建View,onCreateView见名知意,大概职责如下:
- 在 View 层次结构中创建一个新的 FlutterView
- 添加一个 FlutterUiDisplayListener
- 将 FlutterEngine 附加到新的 FlutterView
- 返回新的视图层次结构
我们来看看onCreateView方法:
@NonNull
View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// 确保 delegate没有吧release
ensureAlive();
// 根据不同的渲染模式选择不同的View(SurfaceView或者TextureView)
if (host.getRenderMode() == RenderMode.surface) {
FlutterSurfaceView flutterSurfaceView =
new FlutterSurfaceView(
host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
// 创建FLutterView包含FlutterSurfaceView
host.onFlutterSurfaceViewCreated(flutterSurfaceView);
flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
} else {
FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
// 创建FLutterView包含FlutterTextureView
host.onFlutterTextureViewCreated(flutterTextureView);
flutterView = new FlutterView(host.getActivity(), flutterTextureView);
}
// 添加监听,当flutter渲染首帧时回调。当 Flutter 开始和停止将像素渲染到 Android 视图层次结构时调用的侦听器。
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
// 创建一个FlutterSplashView开屏view
flutterSplashView = new FlutterSplashView(host.getContext());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
flutterSplashView.setId(View.generateViewId());
} else {
flutterSplashView.setId(486947586);
}
// 显示开屏图标,即io.flutter.embedding.android.SplashScreenDrawable配置的drawable图
flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
// FlutterView与flutterEngine关联attach。
flutterView.attachToFlutterEngine(flutterEngine);
// 返回被开屏view包裹的FlutterView。
return flutterSplashView;
}
//回调监听定义,回调中本质是触发调用对应FlutterActivity或FlutterFragment的FlutterActivityAndFragmentDelegate.Host实现方法。
@NonNull
private final FlutterUiDisplayListener flutterUiDisplayListener =
new FlutterUiDisplayListener() {
@Override
public void onFlutterUiDisplayed() {
//本质在FlutterActivity中调用Activity 5.0以上的reportFullyDrawn()安卓官方方法。
host.onFlutterUiDisplayed();
}
@Override
public void onFlutterUiNoLongerDisplayed() {
//本质在FlutterActivity中调用,默认空实现。
host.onFlutterUiNoLongerDisplayed();
}
};
到这里我们FlutterActivityAndFragmentDelegate的核心代码基本上介绍完毕
从上面代码分析结果看onCreateView的职责和逻辑都比较清晰,但是唯一有个疑问就是为什么最后返回的不是FLutterView而是返回的一个包含FLutterView的FlutterSplashView,下面我们再一起来分析下FlutterSplashView
,看看是如何处理FlutterSplashView和FlutterView之间的关系。
FlutterSplashView分析
FlutterSplashView按照字面理解它的主要作用就是显示 SplashScreen 的视图,直到给定的 FlutterView 呈现其第一帧。
我们来看看它的核心流程:
final class FlutterSplashView extends FrameLayout {
// 当 FlutterEngine 附加到给定 FlutterView 或从给定 FlutterView 分离时收到通知的侦听器。
@NonNull
private final FlutterView.FlutterEngineAttachmentListener flutterEngineAttachmentListener = ...
// 当 Flutter 开始和停止将像素渲染到 Android 视图层次结构时调用的侦听器。
@NonNull
private final FlutterUiDisplayListener flutterUiDisplayListener = ...
// 将启动画面转换为 Flutter UI
@NonNull
private final Runnable onTransitionComplete =
new Runnable() {
@Override
public void run() {
removeView(splashScreenView);
previousCompletedSplashIsolate = transitioningIsolateId;
}
};
/**
* 把给定的splashScreen显示在flutterView之上,直到flutterView的首帧渲染出来才过渡消失
*/
public void displayFlutterViewWithSplash(
@NonNull FlutterView flutterView, @Nullable SplashScreen splashScreen) {
// 如果上一个FlutterView显示中,先删除.
if (this.flutterView != null) {
this.flutterView.removeOnFirstFrameRenderedListener(flutterUiDisplayListener);
removeView(this.flutterView);
}
// 复位
if (splashScreenView != null) {
removeView(splashScreenView);
}
// 把flutterView添加给当前FlutterSplashView,本质是一个FrameLayout。
this.flutterView = flutterView;
addView(flutterView);
this.splashScreen = splashScreen;
// 显示一个splash screen开屏图。
if (splashScreen != null) {
//如果flutterView未渲染出来则条件成立。
if (isSplashScreenNeededNow()) {
splashScreenView = splashScreen.createSplashView(getContext(), splashScreenState);
addView(this.splashScreenView);
flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
} else if (isSplashScreenTransitionNeededNow()) {
splashScreenView = splashScreen.createSplashView(getContext(), splashScreenState);
addView(splashScreenView);
transitionToFlutter();
} else if (!flutterView.isAttachedToFlutterEngine()) {
flutterView.addFlutterEngineAttachmentListener(flutterEngineAttachmentListener);
}
}
}
/**
* 如果启动画面正在过渡到 Flutter 体验,则返回 true
*/
private boolean wasPreviousSplashTransitionInterrupted() {
return flutterView.hasRenderedFirstFrame() && !hasSplashCompleted();
}
/**
* 如果特定 Flutter 体验的启动 UI 已经完成,则返回 true。
*/
private boolean hasSplashCompleted() {
return flutterView.getAttachedFlutterEngine().getDartExecutor().getIsolateServiceId() != null
&& flutterView
.getAttachedFlutterEngine()
.getDartExecutor()
.getIsolateServiceId()
.equals(previousCompletedSplashIsolate);
}
/**
* 开屏过渡到flutterview显示
*/
private void transitionToFlutter() {
transitioningIsolateId =
flutterView.getAttachedFlutterEngine().getDartExecutor().getIsolateServiceId();
splashScreen.transitionToFlutter(onTransitionComplete);
}
}
从上面的代码分析,FlutterSplashView逻辑并不复杂,主要就是在FlutterUI第一帧渲染之前显示默认的Drawable。等到Flutter UI第一帧绘制的时候再remove掉。内部的实现逻辑都比较简单这里不再介绍。下面继续
FlutterFragment分析
上面分析完FlutterActivity的流程,我们再来看FlutterFragment就比较简单了。
我们在使用FlutterFragment的时候,如果宿主Actvity而不是FlutterFragmentActivity的话,需要我们手动关联一下方法,这些方法都被添加了@ActvivityCallThrough
注释声明,如:
- onPostResume()
- onBackPressed()
- onRequestPermissionsResult(int, String[], int[]) ()}
- onNewIntent(Intent) ()}
- onUserLeaveHint()
- onTrimMemory(int)
此外,当为此 Fragment 的startActivityForResult 时,请务必调用 Fragment.startActivityForResult(Intent, int) 而不是 Activity.startActivityForResult(Intent, int)。如果调用了该方法的 Activity 版本,则此 Fragment 将永远不会收到其 Fragment.onActivityResult(int, int, Intent) 回调。如果方便,可以考虑使用 FlutterActivity 而不是 FlutterFragment 来避免转发调用的工作。
下面看核心源码
//FlutterFragment也实现了前面分析的FlutterActivityAndFragmentDelegate.Host接口。
public class FlutterFragment extends Fragment
implements FlutterActivityAndFragmentDelegate.Host, ComponentCallbacks2 {
......
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
//FlutterActivity的区别在于FlutterFragment在他自己的onAttach中实例化FlutterActivityAndFragmentDelegate并调用onAttach方法。
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(context);
}
@Nullable
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//FlutterActivity类似,只不过是在FlutterFragment对应生命周期回调。
return delegate.onCreateView(inflater, container, savedInstanceState);
}
......
//与FlutterActivity类似,只是这个方法不是Fragment自己框架回调,需要依赖在Activity中调用。
//譬如FlutterFragmentActivity中对应同名方法的实现。
//注意这里的@ActivityCallThrough注解就是这个含义。
@ActivityCallThrough
public void onPostResume() {
delegate.onPostResume();
}
......
}
其实我们掌握了FlutterActivity之后,FlutterFragment核心基本上没啥区别,主要都是通过代理FlutterActivityAndFragmentDelegate与Flutter平台打交道,实现UI的展示。不做细说,下面继续
FlutterFragmentActivity分析
从上面的FlutterFragment可以看到,FlutterFragmentActivity可以说是FlutterFragment的一个宿主Activity,给我们自己使用Activity绑定FlutterFragment做了很好的参考,其内部与Flutter平台的关联关系都已经处理,用户不需要再考虑上面的各种关联方法的关联。
FlutterFragmentActivity是一个基于 FragmentActivity 的 Flutter Activity。
FlutterFragmentActivity 的存在是因为生态系统中有一些 Android API 只接受一个 FragmentActivity。 如果不需要 FragmentActivity,则应考虑使用常规 FlutterActivity 代替。
我们继续看FlutterFragmentActivity核心方法
onCreate方法
@Override
protected void onCreate(@Nullable 以上是关于Flutter实践深入分析之——FlutterActivity/Fragment原理流程分析的主要内容,如果未能解决你的问题,请参考以下文章
Flutter实践深入分析之——FlutterActivity/Fragment原理流程分析
Flutter实践深入分析之——FlutterActivity/Fragment原理流程分析
Flutter实践深入——平台整合Hybrid composition分析
Flutter 命令本质之 Flutter tools 机制源码深入分析