Flutter Android 端 Activity/Fragment 流程源码分析

Flutter 专栏收录该内容
9 篇文章 10 订阅

Flutter 系列文章连载~

背景

前面文章我们分析了 flutter 在 android 端编译命令相关流程,我们接下来需要先分析一下 Flutter Android 端 framework 平台实现代码(非 native engine 引擎部分),下面以一个纯 Flutter App 为例展开分析。

工程结构及 API 变更

对于一个纯 flutter app 来说,当我们在 yaml 依赖中添加两个 flutter plugin 依赖,然后铜过 Android Studio 导入安卓工程后可以看到如下结构:
在这里插入图片描述
gradle sync 后对应的安卓依赖如下:
在这里插入图片描述
可以看到,上面依赖就是我们《Flutter Android 工程结构及应用层编译源码深入分析》一文中分析 Flutter Android App 编译流程中提到过的动态追加依赖。

对于 Android 平台来说,Flutter 依赖其实蛮简单的,我们以启用 androidx 为例展示 release 模式下的依赖关系,如下:

releaseRuntimeClasspath - Resolved configuration for runtime for variant: release
+--- io.flutter:flutter_embedding_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce
|    +--- androidx.lifecycle:lifecycle-common:2.2.0
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.lifecycle:lifecycle-common-java8:2.2.0
|    |    +--- androidx.lifecycle:lifecycle-common:2.2.0 (*)
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.lifecycle:lifecycle-runtime:2.2.0
|    |    +--- androidx.lifecycle:lifecycle-common:2.2.0 (*)
|    |    +--- androidx.arch.core:core-common:2.1.0
|    |    |    \--- androidx.annotation:annotation:1.1.0
|    |    \--- androidx.annotation:annotation:1.1.0
|    +--- androidx.fragment:fragment:1.1.0
|    |    +--- androidx.annotation:annotation:1.1.0
|    |    +--- androidx.core:core:1.1.0
|    |    |    +--- androidx.annotation:annotation:1.1.0
|    |    |    +--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.2.0 (*)
|    |    |    +--- androidx.versionedparcelable:versionedparcelable:1.1.0
|    |    |    |    \--- androidx.collection:collection:1.0.0 -> 1.1.0
|    |    |    |         \--- androidx.annotation:annotation:1.1.0
|    |    |    \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
|    |    +--- androidx.collection:collection:1.1.0 (*)
|    |    +--- androidx.viewpager:viewpager:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    +--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    |    \--- androidx.customview:customview:1.0.0
|    |    |         +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |         \--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    +--- androidx.loader:loader:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    +--- androidx.core:core:1.0.0 -> 1.1.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-livedata:2.0.0
|    |    |    |    +--- androidx.arch.core:core-runtime:2.0.0
|    |    |    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0
|    |    |    |    |    \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    |    +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0
|    |    |    |    |    +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.2.0 (*)
|    |    |    |    |    +--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    |    |    \--- androidx.arch.core:core-runtime:2.0.0 (*)
|    |    |    |    \--- androidx.arch.core:core-common:2.0.0 -> 2.1.0 (*)
|    |    |    \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0
|    |    |         \--- androidx.annotation:annotation:1.1.0
|    |    +--- androidx.activity:activity:1.0.0
|    |    |    +--- androidx.annotation:annotation:1.1.0
|    |    |    +--- androidx.core:core:1.1.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-runtime:2.1.0 -> 2.2.0 (*)
|    |    |    +--- androidx.lifecycle:lifecycle-viewmodel:2.1.0 (*)
|    |    |    \--- androidx.savedstate:savedstate:1.0.0
|    |    |         +--- androidx.annotation:annotation:1.1.0
|    |    |         +--- androidx.arch.core:core-common:2.0.1 -> 2.1.0 (*)
|    |    |         \--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.2.0 (*)
|    |    \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.1.0 (*)
|    \--- androidx.annotation:annotation:1.1.0
+--- io.flutter:armeabi_v7a_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce
+--- io.flutter:arm64_v8a_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce
\--- io.flutter:x86_64_release:1.0.0-241c87ad800beeab545ab867354d4683d5bfb6ce

可以看到依赖主要都是 androidx,还是蛮香的。

源码分析

Flutter Android 端源码主要依赖于 gradle maven 下载,也就是上图中的io.flutter:flutter_embedding_XXX代码,另一个 ABI 依赖是libflutter.so引擎依赖。

本文以 Flutter 2.2.3 版本为例分析,由于新旧版本的 Android 入口存在差异,譬如新版本不再默认使用FlutterApplication配合io.flutter.app.FlutterActivity模式,而是直接使用io.flutter.embedding.android.FlutterActivty,所以我们的入口要从新的看起(注意新旧同类名不同包名的区别)。相关新旧版本迁移变更可以参考官方说明的Upgrading-pre-1.12-Android-projects

FlutterActivity 相关分析

Android App 中默认 Flutter UI 界面呈现在平台层的实现都继承自io.flutter.embedding.android.FlutterActivity,主题默认也是一个全屏无 ActionBar 形式,源码如下:

public class FlutterActivity extends Activity
    implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
  ......
}

依据这个继承关系可以看到,FlutterActivity 直接继承自 Activity,而不是兼容包的 AppCompatActivity,这对于有历史包袱的 App 来说是一件好事,也秉承了一个优质 SDK 去依赖的优质特点。同时其实现了两个接口,LifecycleOwner 为标准 AAC 框架成员,我们不再解释;重点看下FlutterActivityAndFragmentDelegate.Host,源码如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  ......
  //这里的一堆extends接口不多解释,注释都很明确
  interface Host
      extends SplashScreenProvider,
          FlutterEngineProvider,
          FlutterEngineConfigurator,
          PlatformPlugin.PlatformPluginDelegate {
    //1、获取宿主Activity或Fragment的context。
    //对应上面FlutterActivity实现此接口就是返回他自己的context,也就是this。
    @NonNull
    Context getContext();
    //2、是否可以通过deeplink调起initial route路由。
    //主要是在AndroidManifest.xml中Activity配置flutter_deeplinking_enabled meta值。
    //参见官方文档 https://flutter.dev/docs/development/ui/navigation/deep-linking
    @Nullable
    boolean shouldHandleDeeplinking();
	//3、获取宿主Activity或Fragment的attached Activity。
    //对应上面FlutterActivity实现此接口就是返回他自己,也就是this。
    @Nullable
    Activity getActivity();
	//4、获取宿主Activity或Fragment的Lifecycle。
    @NonNull
    Lifecycle getLifecycle();
	//5、获取宿主启动Flutter携带的参数,通过intent解析,譬如enable-dart-profiling等。
    @NonNull
    FlutterShellArgs getFlutterShellArgs();
	//6、获取静态缓存的EngineId,如果没有就返回空,通过intent的cached_engine_id参数传递。
    @Nullable
    String getCachedEngineId();
    //7、当FlutterActivity destory后是否销毁引擎实例,默认要销毁。
    //当FlutterEngine属于Activity自己则需要销毁返回true,当FlutterEngine属于静态缓存的,则不用销毁,这里应该返回false。
    boolean shouldDestroyEngineWithHost();
    //8、当FlutterEngine已经attach到另一个Activity时这个Activity就需要与FlutterEngine断开。
    void detachFromFlutterEngine();
    //9、获取dart主入口,默认时main。
    //可以在AndroidManifest.xml中给Activity设置io.flutter.Entrypoint的meta自定义。
    @NonNull
    String getDartEntrypointFunctionName();
    //10、返回app bundle dart代码存在的路径。
    @NonNull
    String getAppBundlePath();
    //11、获取初始路由地址。
    //默认先从intent中解析route的值,没有就去meta-data解析io.flutter.InitialRoute的值,没有就返回null。
    @Nullable
    String getInitialRoute();
    //12、获取渲染模式,用在FlutterView呈现FlutterEngine引擎渲染效果。
    @NonNull
    RenderMode getRenderMode();
    //13、获取Transparency模式,用在FlutterView呈现FlutterEngine引擎渲染效果。
    @NonNull
    TransparencyMode getTransparencyMode();
	//14、提供一个Flutter开屏图片,默认有配置。
	//通过meta-data配置io.flutter.embedding.android.SplashScreenDrawable可生效。
    @Nullable
    SplashScreen provideSplashScreen();
    //15、返回一个用来渲染FlutterView的FlutterEngine引擎。
    //如果返回null则框架会自动新建一个FlutterEngine引擎实例,默认就是自动新建,我们可以重写复用等。
    @Nullable
    FlutterEngine provideFlutterEngine(@NonNull Context context);
    //16、创建和配置platform plugin。
    @Nullable
    PlatformPlugin providePlatformPlugin(
        @Nullable Activity activity, @NonNull FlutterEngine flutterEngine);
    void configureFlutterEngine(@NonNull FlutterEngine flutterEngine);
    void cleanUpFlutterEngine(@NonNull FlutterEngine flutterEngine);
    boolean shouldAttachEngineToActivity();
    void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView);
    void onFlutterTextureViewCreated(@NonNull FlutterTextureView flutterTextureView);
    void onFlutterUiDisplayed();
    void onFlutterUiNoLongerDisplayed();
    boolean shouldRestoreAndSaveState();
  }
}

可以看到FlutterActivityAndFragmentDelegate.Host是 Flutter Android 平台层实现与标准 Activity/Fragment 之间的一个接口约定层,FlutterActivity 实现了这个接口的一系列方法,这些接口的含义上面也列举了,所以我们下面重心回到标准 Android Activity 生命周期线,如下:

public class FlutterActivity extends Activity
    implements FlutterActivityAndFragmentDelegate.Host, LifecycleOwner {
  ......
  //步骤1、重点!关联Activity、Fragment与Flutter的接口桥梁委托实现
  protected FlutterActivityAndFragmentDelegate delegate;
  ......
  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
  	//步骤2、将清单文件中标准配置的主题切换回普通主题。很巧妙的让launch app和initialized后activity主题发生变化。
  	//普通主题通过io.flutter.embedding.android.NormalTheme的meta-data配置。
  	//清单标准配置的是一个图标、启动后执行到这里被换成标准纯背景色,两个主题不要对窗体size进行差异配置,不然会抖动。
    switchLaunchThemeForNormalTheme();

    super.onCreate(savedInstanceState);
	//步骤3、创建一个委托代理类实例,然后调用他的一系列方法。
    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(this);
    delegate.onRestoreInstanceState(savedInstanceState);
	//步骤4、标准AAC操作,不解释。
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
	//步骤5、从Activity的Intent中解析background_mode字段看是transparent还是opaque。
	//透明则通过getWindow().setBackgroundDrawable设置为透明,否则保持NormalTheme的暗黑适配纯色背景。
    configureWindowForTransparency();
    //步骤6、创建一个View让Activity显示,这就是Flutter的View容器。
    setContentView(createFlutterView());
    //步骤7、官方对全屏状态栏的兼容配置。。。
    configureStatusBarForFullscreenFlutterExperience();
  }
  ......

  //步骤8、创建并返回一个View用来给Activity显示。
  @NonNull
  private View createFlutterView() {
    return delegate.onCreateView(
        null /* inflater */, null /* container */, null /* savedInstanceState */);
  }

  //步骤9、官方对全屏状态栏的兼容配置。
  //这些flag不用解释了吧,标准安卓操作。
  //记住这个坑即可,我们如果想修改FlutterActivity的这玩意就在他之后覆盖即可。
  private void configureStatusBarForFullscreenFlutterExperience() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      Window window = getWindow();
      window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
      window.setStatusBarColor(0x40000000);
      window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
    }
  }
  
  //步骤10、生命周期回调处理,AAC调用、delegate对应方法触发等
  @Override
  protected void onStart() {
    super.onStart();
    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
    //判断delegate是否不为null
    if (stillAttachedForEvent("onStart")) {
      delegate.onStart();
    }
  }
	
  //步骤11、同步骤10的一堆回调类似触发,省略实现。。。
  @Override
  protected void onResume() {......}
  @Override
  public void onPostResume() {......}
  @Override
  protected void onPause() {......}
  @Override
  protected void onStop() {......}
  @Override
  protected void onSaveInstanceState(Bundle outState) {......}
  @Override
  protected void onDestroy() {......}
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {......}
  @Override
  protected void onNewIntent(@NonNull Intent intent) {......}
  @Override
  public void onBackPressed() {......}
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {......}
  @Override
  public void onUserLeaveHint() {......}
  @Override
  public void onTrimMemory(int level) {......}
  ......
  //步骤12、一堆前面介绍的FlutterActivityAndFragmentDelegate.Host接口实现方法。
  ......
}

FlutterActivityAndFragmentDelegate 相关分析

上一小节我们看到 FlutterActivity 中的核心就是与 FlutterActivityAndFragmentDelegate 实例进行交互,那我们就继续看看这个实例对应的源码,重点先放到 FlutterActivity 中调用的实例化、onAttach、onRestoreInstanceState 上。如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  private static final String TAG = "FlutterActivityAndFragmentDelegate";
  private static final String FRAMEWORK_RESTORATION_BUNDLE_KEY = "framework";
  private static final String PLUGINS_RESTORATION_BUNDLE_KEY = "plugins";

  //步骤1、host实例就是FlutterActivity或FlutterFragment
  @NonNull private Host host;
  @Nullable private FlutterEngine flutterEngine;
  @Nullable private FlutterSplashView flutterSplashView;
  @Nullable private FlutterView flutterView;
  @Nullable private PlatformPlugin platformPlugin;
  private boolean isFlutterEngineFromHost;
	
  //步骤2、前面小节FlutterActivity的onCreate中实例化,host为FlutterActivity自己的this。
  FlutterActivityAndFragmentDelegate(@NonNull Host host) {
    this.host = host;
  }
  
  //步骤3、前面小节FlutterActivity的onCreate中调用
  void onAttach(@NonNull Context context) {
    //确保host不为空,否则抛出异常。
    ensureAlive();

    //步骤4、flutterEngine为空就创建。
    if (flutterEngine == null) {
      setupFlutterEngine();
    }
	//步骤5、前面小节FlutterActivity中接口实现,默认为true。
    if (host.shouldAttachEngineToActivity()) {
      //步骤6、flutterEngine与FlutterActivity进行attach关联。
      Log.v(TAG, "Attaching FlutterEngine to the Activity that owns this delegate.");
      flutterEngine.getActivityControlSurface().attachToActivity(this, host.getLifecycle());
    }

    //步骤7、通过host获取PlatformPlugin实例。
    platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);
	//步骤8、给host配置flutterEngine。
    host.configureFlutterEngine(flutterEngine);
  }

  //步骤9、前面小节FlutterActivity的onCreate中调用
  void onRestoreInstanceState(@Nullable Bundle bundle) {
    Log.v(
        TAG,
        "onRestoreInstanceState. Giving framework and plugins an opportunity to restore state.");
    ensureAlive();
	//步骤10、这两个变量都是在Activity的onSaveInstanceState方法进行set操作赋值的。
    Bundle pluginState = null;
    byte[] frameworkState = null;
    if (bundle != null) {
      //说明来自异常终止恢复Activity
      pluginState = bundle.getBundle(PLUGINS_RESTORATION_BUNDLE_KEY);
      frameworkState = bundle.getByteArray(FRAMEWORK_RESTORATION_BUNDLE_KEY);
    }
	//步骤11、存放时也是这个规则,优先判断intent中的enable_state_restoration配置。
	//不存在就看getCachedEngineId是不是不为null,是就不会要恢复,即此条件false,反之恢复。
    if (host.shouldRestoreAndSaveState()) {
      flutterEngine.getRestorationChannel().setRestorationData(frameworkState);
    }
	//步骤12、FlutterActivity默认实现是true。
    if (host.shouldAttachEngineToActivity()) {
      flutterEngine.getActivityControlSurface().onRestoreInstanceState(pluginState);
    }
  }
  ......
}

看完上面这段,接下来我们继续把目光挪到 FlutterActivityAndFragmentDelegate 的 onCreateView 方法上,这个方法的返回值在前面 FlutterActivity 的 onCreate 中被 setContent 设置为 Activity 的 View。如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  ......
  //步骤13、FlutterActivity中调用时参数均为null,返回一个androd view实例。
  @NonNull
  View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Log.v(TAG, "Creating FlutterView.");
    //确保host属性不为null。
    ensureAlive();
	//步骤14、依据前面FlutterActivity的intent参数background_mode决定模式,默认surface模式。
	//FlutterActivity默认背景是opaque、可以设置为transparent。
	//当FlutterActivity的window背景不透明则RenderMode为surface模式、反之texture模式。
    if (host.getRenderMode() == RenderMode.surface) {
      //步骤15、创建一个FlutterSurfaceView。
      //然后通过host接口调用FlutterActivity的onFlutterSurfaceViewCreated方法,默认空实现。
      //getTransparencyMode模式和FlutterActivity的window背景模式完全一样逻辑。
      FlutterSurfaceView flutterSurfaceView =
          new FlutterSurfaceView(
              host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
      host.onFlutterSurfaceViewCreated(flutterSurfaceView);

      //步骤15、创建一个FlutterView包含FlutterSurfaceView。
      flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
    } else {
      //步骤16、创建一个FlutterTextureView。
      //然后通过host接口调用FlutterActivity的onFlutterSurfaceViewCreated方法,默认空实现。
      FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
      host.onFlutterTextureViewCreated(flutterTextureView);

      //步骤17、创建一个FlutterView包含FlutterTextureView。
      flutterView = new FlutterView(host.getActivity(), flutterTextureView);
    }

    //步骤18、添加监听,当flutter渲染首帧时回调。
    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
	//步骤19、创建一个FlutterSplashView开屏view
    flutterSplashView = new FlutterSplashView(host.getContext());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      flutterSplashView.setId(View.generateViewId());
    } else {
      //这里不得不吐槽官方,不过确实没好的办法,直接写死了一个随机id,有可能冲突,且一个view树只能有一个FlutterSplashView了。
      flutterSplashView.setId(486947586);
    }
    //步骤20、显示开屏图标,即io.flutter.embedding.android.SplashScreenDrawable配置的drawable图。
    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
	//步骤21、FlutterView与flutterEngine关联attach。
    Log.v(TAG, "Attaching FlutterEngine to FlutterView.");
    flutterView.attachToFlutterEngine(flutterEngine);
	//返回被开屏view包裹的FlutterView。
    return flutterSplashView;
  }

  //步骤22、一组回调监听定义,回调中本质是触发调用对应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();
        }
      };
  ......
}

接着继续看 FlutterActivity 生命周期及事件相关方法对 FlutterActivityAndFragmentDelegate 相关方法的调用,如下:

class FlutterActivityAndFragmentDelegate implements ExclusiveAppComponent<Activity> {
  ......
  void onStart() {
    ......
    doInitialFlutterViewRun();
  }

  //步骤23、开始在FlutterView中执行dart程序。
  private void doInitialFlutterViewRun() {
    ......
	//步骤24、判断是否dart已经运行中。
	//这个情况只会发生在config change后我们没有保留Fragment实例的场景,尽量不要这样。
    if (flutterEngine.getDartExecutor().isExecutingDart()) {
      return;
    }
    //步骤25、各种优先级获取初始跳转dart的路由地址。
    String initialRoute = host.getInitialRoute();
    if (initialRoute == null) {
      initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
      if (initialRoute == null) {
        initialRoute = DEFAULT_INITIAL_ROUTE; //值为 /
      }
    }
    //过滤这个tag可以调试flutter初始路由跳转信息。
    Log.v(
        TAG,
        "Executing Dart entrypoint: "
            + host.getDartEntrypointFunctionName()
            + ", and sending initial route: "
            + initialRoute);

    //步骤26、通过引擎的NavigationChannel设置初始路由信息。
    flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
	//步骤27、按照优先级获取appBundlePath,默认从host获取,无则从FlutterLoader获取。
    String appBundlePathOverride = host.getAppBundlePath();
    if (appBundlePathOverride == null || appBundlePathOverride.isEmpty()) {
      appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
    }

    //步骤28、配置dart的entrypoint并且执行,默认入口函数名为main,可通过meta-data的io.flutter.Entrypoint修改。
    DartExecutor.DartEntrypoint entrypoint =
        new DartExecutor.DartEntrypoint(
            appBundlePathOverride, host.getDartEntrypointFunctionName());
    flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
  }
  ......
  //步骤29、FlutterActivity的onResume调用它。
  void onResume() {
	......
	//调用引擎的LifecycleChannel触发方法。
    flutterEngine.getLifecycleChannel().appIsResumed();
  }

  //步骤30、雷同onResume不做说明,都是调用flutterEngine.getLifecycleChannel()的对应方法。
  void onPause() {......}
  void onStop() {......}
  void onUserLeaveHint() {......}
  ......
  void onPostResume() {
    ......
    if (flutterEngine != null) {
      if (platformPlugin != null) {
        //步骤31、即FlutterActivity中providePlatformPlugin方法返回的PlatformPlugin实例。
        platformPlugin.updateSystemUiOverlays();
      }
    } else {
      Log.w(TAG, "onPostResume() invoked before FlutterFragment was attached to an Activity.");
    }
  }
  ......
  //步骤32、返回按钮触发,通过NavigationChannel通道退栈route。
  void onBackPressed() {
    ensureAlive();
    if (flutterEngine != null) {
      Log.v(TAG, "Forwarding onBackPressed() to FlutterEngine.");
      flutterEngine.getNavigationChannel().popRoute();
    } else {
      Log.w(TAG, "Invoked onBackPressed() before FlutterFragment was attached to an Activity.");
    }
  }

  //步骤33、动态权限申请返回处理,转发到感兴趣的Flutter Plugin去。
  void onRequestPermissionsResult(
      int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    ensureAlive();
    if (flutterEngine != null) {
      ......
      flutterEngine
          .getActivityControlSurface()
          .onRequestPermissionsResult(requestCode, permissions, grantResults);
    } else {
      Log.w(
          TAG,
          "onRequestPermissionResult() invoked before FlutterFragment was attached to an Activity.");
    }
  }

  //步骤34、activity result返回处理,转发到感兴趣的Flutter Plugin去。
  void onActivityResult(int requestCode, int resultCode, Intent data) {
    ensureAlive();
    if (flutterEngine != null) {
      ......
      flutterEngine.getActivityControlSurface().onActivityResult(requestCode, resultCode, data);
    } else {
      Log.w(TAG, "onActivityResult() invoked before FlutterFragment was attached to an Activity.");
    }
  }

  //步骤35、通过SystemChannel发送低内存消息。
  void onLowMemory() {
    Log.v(TAG, "Forwarding onLowMemory() to FlutterEngine.");
    ensureAlive();
    flutterEngine.getDartExecutor().notifyLowMemoryWarning();
    flutterEngine.getSystemChannel().sendMemoryPressureWarning();
  }
  ......
}

通过这一小节的代码段分析,我们可以看出来 Flutter 在平台 SDK 层包装都是 FlutterActivityAndFragmentDelegate 来负责的,FlutterActivityAndFragmentDelegate 和核心是 FlutterView 和 FlutterEngine 的创建关联与管理调度。

FlutterFragment 相关分析

分析完上面 FlutterActivity 相关流程,我们接着看看 FlutterFragment,继承自androidx.fragment.app.Fragment,言外之意就是说 Activity 也得最好是用配套的 FlutterFragmentActivity。关于 FlutterFragmentActivity 我们会在下一个小节分析,这里重点关注 FlutterFragment。

其实官方注释也明确说明了,他们不是特别优先推荐使用 FlutterFragment,建议尽可能优选 FlutterActivity。因为使用 FlutterFragment 如果配合的 Activity 不是 FlutterFragmentActivity,需要我们自己去关联一些 Activity 与 FlutterFragment 的方法,这些方法在 FlutterFragment 的源码中都以@ActivityCallThrough进行了注释声明,让使用变的没那么方便,譬如:

  • onPostResume()
  • onBackPressed()
  • onRequestPermissionsResult(int, String[], int[])} ()
  • onNewIntent(Intent)} ()
  • onUserLeaveHint()

如上 FlutterFragment 中的方法都需要主动与 Acitivty 关联调用(FlutterFragmentActivity 已实现)。下面是 FlutterFragment 的主要源码:

//步骤36、FlutterFragment也实现了前面分析的FlutterActivityAndFragmentDelegate.Host接口,含义不解释。
public class FlutterFragment extends Fragment
    implements FlutterActivityAndFragmentDelegate.Host, ComponentCallbacks2 {
  ......
  @Override
  public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    //步骤37、与FlutterActivity的区别在于FlutterFragment在他自己的onAttach中实例化FlutterActivityAndFragmentDelegate并调用onAttach方法。
    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(context);
  }

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //步骤38、与FlutterActivity类似,不做过多分析说明。
    delegate.onRestoreInstanceState(savedInstanceState);
  }

  @Nullable
  @Override
  public View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    //步骤39、与FlutterActivity类似,只不过是在FlutterFragment对应生命周期回调。
    return delegate.onCreateView(inflater, container, savedInstanceState);
  }
  ......
  //步骤39、与FlutterActivity类似,只是这个方法不是Fragment自己框架回调,需要依赖在Activity中调用。
  //譬如FlutterFragmentActivity中对应同名方法的实现。
  //注意这里的@ActivityCallThrough注解就是这个含义。
  @ActivityCallThrough
  public void onPostResume() {
    delegate.onPostResume();
  }
  ......
}

可以看到,FlutterFragment 和 FlutterActivity 基本没啥区别,核心都是实现了FlutterActivityAndFragmentDelegate.Host接口,在自己生命周期内先实例化一个 FlutterActivityAndFragmentDelegate,接着调用其一系列方法进行交互,前面 FlutterActivity 已经解释过了,这里不多解释。

FlutterFragmentActivity 相关分析

通过上面 FlutterFragment 源码我们可以看到,FlutterFragmentActivity 可以说是 FlutterFragment 的一个承载 Activity,这个 Activity 继承自androidx.fragment.app.FragmentActivity,所以使用 FlutterFragment 及 FlutterFragmentActivity 对你应用的基类 Activity 还是有一点限制的,没有前面介绍的 FlutterActivity 香。

由于 FlutterFragmentActivity 继承自androidx.fragment.app.FragmentActivity,所以相比 FlutterActivity 来说,AAC 架构那套就不用自己显式关联了,因为androidx.fragment.app.FragmentActivity内部已做好关联处理。

//步骤40、这里implements的一堆其实FlutterActivityAndFragmentDelegate.Host都有implements,算是Host的子集吧。
//本质和FlutterActivityAndFragmentDelegate.Host对于实现方干的一样的事。
public class FlutterFragmentActivity extends FragmentActivity
    implements SplashScreenProvider, FlutterEngineProvider, FlutterEngineConfigurator {
  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    //步骤41、这里和FlutterActivity完全一样,只是不用实例化一个FlutterActivityAndFragmentDelegate,因为其内部的FlutterFragment会做这些事。
    switchLaunchThemeForNormalTheme();
    super.onCreate(savedInstanceState);
    configureWindowForTransparency();
    //步骤42、这里区别是调用createFragmentContainer生成了一个View设置给Activity的content。
    setContentView(createFragmentContainer());
    //步骤43、这里和FlutterActivity完全一样。
    configureStatusBarForFullscreenFlutterExperience();
    //步骤44、与FlutterActivity不一样,这里检验的是FlutterFragment是否添加OK。
    ensureFlutterFragmentCreated();
  }

  //步骤45、上面步骤42设置的View,用来放置FlutterFragment的容器View,本质是一个FrameLayout且MATCH_PARENT。
  @NonNull
  private View createFragmentContainer() {
    FrameLayout container = provideRootLayout(this);
    container.setId(FRAGMENT_CONTAINER_ID);
    container.setLayoutParams(
        new ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    return container;
  }

  protected FrameLayout provideRootLayout(Context context) {
    return new FrameLayout(context);
  }

  //步骤46、确保给Activity上attach一个FlutterFragment,不存在就创建一个通过FragmentManager添加。
  private void ensureFlutterFragmentCreated() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    flutterFragment = (FlutterFragment) fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT);
    if (flutterFragment == null) {
      flutterFragment = createFlutterFragment();
      fragmentManager
          .beginTransaction()
          .add(FRAGMENT_CONTAINER_ID, flutterFragment, TAG_FLUTTER_FRAGMENT)
          .commit();
    }
  }

  //步骤47、创建一个FlutterFragment。
  //如果我们自定义FlutterFragmentActivity子类,可以重写这个方法实现自己的自定义FlutterFragment。
  @NonNull
  protected FlutterFragment createFlutterFragment() {
    final BackgroundMode backgroundMode = getBackgroundMode();
    final RenderMode renderMode = getRenderMode();
    final TransparencyMode transparencyMode =
        backgroundMode == BackgroundMode.opaque
            ? TransparencyMode.opaque
            : TransparencyMode.transparent;
	//步骤48、依据是否Engine缓存决定怎么创建FlutterFragment。
    if (getCachedEngineId() != null) {
      ......
      return FlutterFragment.withCachedEngine(getCachedEngineId())
          .renderMode(renderMode)
          .transparencyMode(transparencyMode)
          .handleDeeplinking(shouldHandleDeeplinking())
          .shouldAttachEngineToActivity(shouldAttachEngineToActivity())
          .destroyEngineWithFragment(shouldDestroyEngineWithHost())
          .build();
    } else {
      ......
      return FlutterFragment.withNewEngine()
          .dartEntrypoint(getDartEntrypointFunctionName())
          .initialRoute(getInitialRoute())
          .appBundlePath(getAppBundlePath())
          .flutterShellArgs(FlutterShellArgs.fromIntent(getIntent()))
          .handleDeeplinking(shouldHandleDeeplinking())
          .renderMode(renderMode)
          .transparencyMode(transparencyMode)
          .shouldAttachEngineToActivity(shouldAttachEngineToActivity())
          .build();
    }
  }
  ......
  //步骤49、调用flutterFragment对应生命周期回调。
  //可以看到,使用FlutterFragmentActivity配合FlutterFragment的好处就是这些FlutterFragment的@ActivityCallThrough都帮你调用好了。
  @Override
  public void onPostResume() {
    super.onPostResume();
    flutterFragment.onPostResume();
  }
  ......
}

总结

到此我们其实就知道 FlutterActivity 和 FlutterFragment 的大致实现,相信你通过上面分析对 Flutter App 在安卓端的承载有一定认识,通常一个 engine 的整个 Flutter Dart 无论页面栈多少级,终归在安卓端都是一个 Activity 或者 Fragment 承载,抑或 View,端侧仅仅算是一个容器而已。

这也就是为什么我们在 Android 平台上查看一个标准 Flutter App 的 Activity 堆栈默认只有继承自 FlutterActivity 的一个 Activity,其内部 View 层级如下的原因:
在这里插入图片描述
关于本文更多样例可以参见官方文档:

这里不做过多演示。

  • 2
    点赞
  • 2
    评论
  • 8
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

<h4 style="font-weight:500;font-size:1.5rem;font-family:'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif;color:#222226;background-color:#ffffff;text-align:center;"> <span style="font-size:14px;">期末</span><span style="font-size:14px;background-color:#fbeeb8;">考点</span><span style="font-size:14px;">都对应</span><span style="font-size:14px;background-color:#fbeeb8;">详解视频</span><span style="font-size:14px;">,</span><span style="font-size:14px;"><span style="color:#e03e2d;">基础阶段</span></span><span style="font-size:14px;">内容全面,语言通俗易懂(翻译书中的语言为</span><span style="font-size:14px;background-color:#fbeeb8;">人话)</span><span style="font-size:14px;">,</span> </h4> <h4 style="font-weight:500;font-size:1.5rem;font-family:'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif;color:#222226;background-color:#ffffff;text-align:center;"> <span style="font-size:14px;">老师精心研究</span><span style="font-size:14px;background-color:#fbeeb8;">百份</span><span style="font-size:14px;">考卷,总结每一个考点,同时结合你肯定可以听懂的骚话,</span> </h4> <h4 style="font-weight:500;font-size:1.5rem;font-family:'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif;color:#222226;background-color:#ffffff;text-align:center;"> <span style="font-size:14px;background-color:#fbeeb8;">扫清你的数据库系统盲区</span> </h4> <h4 style="font-weight:500;font-size:1.5rem;font-family:'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif;color:#222226;background-color:#ffffff;text-align:center;"> <span style="font-size:14px;"><span style="color:#e03e2d;">真题阶段</span></span><span style="font-size:14px;">为你提供</span><span style="font-size:14px;background-color:#fbeeb8;">解题思路</span><span style="font-size:14px;">,培养你的</span><span style="font-size:14px;background-color:#fbeeb8;">解题思维</span><span style="font-size:14px;">,同时</span><span style="font-size:14px;background-color:#fbeeb8;">点明考点</span><span style="font-size:14px;">,结合文档进行重点解读,加深你的印象.</span> </h4> <h4 style="font-weight:500;font-size:1.5rem;font-family:'PingFang SC', 'Hiragino Sans GB', Arial, 'Microsoft YaHei', Verdana, Roboto, Noto, 'Helvetica Neue', sans-serif;color:#222226;background-color:#ffffff;text-align:center;"> <span style="font-size:14px;color:#3598db;">只为你的高分,我们交个朋友!让每位学生都可以学的起!!</span> </h4> <p> <span style="font-size:14px;color:#3598db;"><img src="https://img-bss.csdnimg.cn/202103040423318088.png" alt="" width="788" height="450" /></span> </p>
<p> <span style="font-family:-apple-system, system-ui, 'PingFang SC', Helvetica, Tahoma, Arial, 'Microsoft YaHei', 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif;font-size:12px;background-color:#ffffff;">1、系统全面介绍了Python的基础语法 </span> </p> <p> <span style="font-family:-apple-system, system-ui, 'PingFang SC', Helvetica, Tahoma, Arial, 'Microsoft YaHei', 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif;font-size:12px;background-color:#ffffff;">2、在课程中融入了算法思想 </span> </p> <p> <span style="font-family:-apple-system, system-ui, 'PingFang SC', Helvetica, Tahoma, Arial, 'Microsoft YaHei', 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif;font-size:12px;background-color:#ffffff;">3、帮助初学者厘清逻辑,掌握Python的主体脉络 </span> </p> <p> <span style="font-family:-apple-system, system-ui, 'PingFang SC', Helvetica, Tahoma, Arial, 'Microsoft YaHei', 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif;font-size:12px;background-color:#ffffff;">4、从全方位立体角度解析知识点 </span> </p> <p> <span style="font-family:-apple-system, system-ui, 'PingFang SC', Helvetica, Tahoma, Arial, 'Microsoft YaHei', 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif;font-size:12px;background-color:#ffffff;">5、实战案例驱动、课程包含近200个相关案例、边讲解边实操</span> </p> <p> <span style="font-family:-apple-system, system-ui, 'PingFang SC', Helvetica, Tahoma, Arial, 'Microsoft YaHei', 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif;font-size:12px;background-color:#ffffff;"><br /> </span> </p> <p> <span style="font-family:-apple-system, system-ui, 'PingFang SC', Helvetica, Tahoma, Arial, 'Microsoft YaHei', 微软雅黑, 黑体, Heiti, sans-serif, SimSun, 宋体, serif;font-size:12px;background-color:#ffffff;"><img src="https://img-bss.csdnimg.cn/202107120808123109.png" alt="" /><br /> </span> </p>
<p> <span style="font-size:14px;color:#337FE5;">【为什么学爬虫?】</span> </p> <p> <span style="font-size:14px;">       1、爬虫入手容易,但是深入较难,如何写出高效率的爬虫,如何写出灵活性高可扩展的爬虫都是一项技术活。另外在爬虫过程中,经常容易遇到被反爬虫,比如字体反爬、IP识别、验证码等,如何层层攻克难点拿到想要的数据,这门课程,你都能学到!</span> </p> <p> <span style="font-size:14px;">       2、如果是作为一个其他行业的开发者,比如app开发,web开发,学习爬虫能让你加强对技术的认知,能够开发出更加安全的软件和网站</span> </p> <p> <br /> </p> <span style="font-size:14px;color:#337FE5;">【课程设计】</span> <p class="ql-long-10663260"> <span> </span> </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 一个完整的爬虫程序,无论大小,总体来说可以分成三个步骤,分别是: </p> <ol> <li class="" style="font-size:11pt;color:#494949;"> 网络请求:模拟浏览器的行为从网上抓取数据。 </li> <li class="" style="font-size:11pt;color:#494949;"> 数据解析:将请求下来的数据进行过滤,提取我们想要的数据。 </li> <li class="" style="font-size:11pt;color:#494949;"> 数据存储:将提取到的数据存储到硬盘或者内存中。比如用mysql数据库或者redis等。 </li> </ol> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 那么本课程也是按照这几个步骤循序渐进的进行讲解,带领学生完整的掌握每个步骤的技术。另外,因为爬虫的多样性,在爬取的过程中可能会发生被反爬、效率低下等。因此我们又增加了两个章节用来提高爬虫程序的灵活性,分别是: </p> <ol> <li class="" style="font-size:11pt;color:#494949;"> 爬虫进阶:包括IP代理,多线程爬虫,图形验证码识别、JS加密解密、动态网页爬虫、字体反爬识别等。 </li> <li class="" style="font-size:11pt;color:#494949;"> Scrapy和分布式爬虫:Scrapy框架、Scrapy-redis组件、分布式爬虫等。 </li> </ol> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 通过爬虫进阶的知识点我们能应付大量的反爬网站,而Scrapy框架作为一个专业的爬虫框架,使用他可以快速提高我们编写爬虫程序的效率和速度。另外如果一台机器不能满足你的需求,我们可以用分布式爬虫让多台机器帮助你快速爬取数据。 </p> <p style="font-size:11pt;color:#494949;">   </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 从基础爬虫到商业化应用爬虫,本套课程满足您的所有需求! </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> <br /> </p> <p> <br /> </p> <p> <span style="font-size:14px;background-color:#FFFFFF;color:#337FE5;">【课程服务】</span> </p> <p> <span style="font-size:14px;">专属付费社群+定期答疑</span> </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="font-size:16px;"><br /> </span> </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="font-size:16px;"></span> </p>
©️2021 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值