Flutter AndroidView

在 Flutter 《Flutter 内嵌原生视图能力》Anroid 的 Virtual displays 模式下,AndroidView 是开发者在 Flutter 侧的开端。关于 Virtual displays 如何使用,请点击阅读《Flutter 内嵌原生视图 Android 端接入实现》。在本文中,将深入 AndroidView 的内部,讲解其底层实现原理。

由于 AndroidView 比较复杂,在深入研究之前,请先完成几篇前置文章的学习《Flutter Android Virtual Display 实现原理》《Flutter RenderAndroidView》《Flutter AndroidViewController》,有了这些文章“打底”,我们将底气十足,再学起 AndroidView 来,则小菜一碟。

AndroidView 是一个 Flutter 组件(StatefulWidget),表示一个嵌入 Flutter 中的 Android 原生视图。它的特性如下:

Note

注意,本文基于 Flutter Engine 2.10.5 版本。未来我也会基于 Flutter 3 新版本进行回顾,到时再更新本文。Flutter Engine 2.10.5 对应的 commit 为:57d3bac3dd5cb5b0e464ab70e7bc8a0d8cf083ab

Warning

在注释中提到,嵌入 Android 视图是一项昂贵的操作,应当尽可能避免使用这一功能。


AndroidView

组成结构

AndroidView 是一个 Flutter StatefulWidget,由如下部分组成:

这三层结构还是比较好理解的。再加上一个东东:

我们之前做的积累派上用场了:《Flutter Android Virtual Display 实现原理》《Flutter RenderAndroidView》《Flutter AndroidViewController》。是不是有底气了?

输入参数

StatefulWidget 的主要作用是管理组件入参,具体包括以下:

// 平台视图创建成功后回调
final PlatformViewCreatedCallback? onPlatformViewCreated;

// 视图类型
final String viewType;

// 点击测试相关
final PlatformViewHitTestBehavior hitTestBehavior;

// 布局方向
final TextDirection? layoutDirection;

// 手势识别器
final Set<Factory<OneSequenceGestureRecognizer>>? gestureRecognizers;

// 原生侧 PlatformView 视图的构建参数
final dynamic creationParams;

// 构建参数的 Channel 所采用的编码器
final MessageCodec<dynamic>? creationParamsCodec;

// 是否需要裁剪
final Clip clipBehavior;

其中:

AndroidView 的内部逻辑和生命周期,都在 _AndroidViewState 中。接下来,我们进入 State 部分。


_AndroidViewState

_AndroidViewState 是 AndroidView 的 State,想到 State,会想到生命周期、内部状态、build,总之,关键的逻辑都在 _AndroidViewState 中。

状态属性

首先看 _AndroidViewState 中包含以下属性:

// 每个原生视图都有一个 id,由 Flutter 生成
int? _id;
// 大部分逻辑都封装在 _controller 内部
late AndroidViewController _controller;
// 文本方向
TextDirection? _layoutDirection;
// 表示是否初始化过
bool _initialized = false;
// 焦点
FocusNode? _focusNode;

其中,AndroidViewController 是一个比较关键的属性:_controller 已在《Flutter AndroidViewController》和《Flutter TextureAndroidViewController》两篇文章介绍过。

_controller_AndroidViewState 初始化时进行创建,接下来我们看初始化流程。


_initializeOnce 初始化

_initializeOnce_AndroidViewState 中的初始化逻辑 ,由 _initialized 属性避免重复初始化。由 didChangeDependencies 方法所触发:

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  //...
  _initializeOnce();
  //...
}
void _initializeOnce() {
  if (_initialized) {
    return;
  }
  _initialized = true;
  _createNewAndroidView();
  _focusNode = FocusNode(debugLabel: 'AndroidView(id: $_id)');
}

_createNewAndroidView 方法实现如下,可以看到,同时对 _id_controller 进行初始化:

void _createNewAndroidView() {
  _id = platformViewsRegistry.getNextPlatformViewId();
  _controller = PlatformViewsService.initAndroidView(
    id: _id!,
    viewType: widget.viewType,
    layoutDirection: _layoutDirection!,
    creationParams: widget.creationParams,
    creationParamsCodec: widget.creationParamsCodec,
    onFocus: () {
      _focusNode!.requestFocus();
    },
  );
  if (widget.onPlatformViewCreated != null) {
    _controller.addOnPlatformViewCreatedListener(widget.onPlatformViewCreated!);
  }
}

其中,PlatformViewsService.initAndroidView 创建出 Flutter TextureAndroidViewController。id 则由 platformViewsRegistry.getNextPlatformViewId() 在 Flutter 侧生成,其实现:

int getNextPlatformViewId() => _nextPlatformViewId++;

build

梳理到这里,开始讲到 AndroidView 的渲染过程,文章开头梳理了 AndroidView 的结构,这里的 build 创建一个 _AndroidPlatformView,后面小节会介绍 _AndroidPlatformView,实际上它里面没什么代码,它的作用,只是对更加底层的 RenderAndroidView 进行封装,将 RenderAndroidView 的 RenderObject 通过 _AndroidPlatformView 封装为 Widget,然后这里的 state(AndroidView 组件在 build 时创建了 _AndroidPlatformView。具体如下:

@override
Widget build(BuildContext context) {
  return Focus(
    focusNode: _focusNode,
    onFocusChange: _onFocusChange,
    child: _AndroidPlatformView(
      controller: _controller,
      hitTestBehavior: widget.hitTestBehavior,
      gestureRecognizers: widget.gestureRecognizers ?? _emptyRecognizersSet,
      clipBehavior: widget.clipBehavior,
    ),
  );
}

其中,对于 _AndroidPlatformView,我们放到后面小节中梳理。

PlatformViewsService.initAndroidView

initAndroidView是一个静态方法,用于创建一个新的 Flutter TextureAndroidViewController(实现了 Flutter AndroidViewController),这个控制器用于管理 Android 侧原生视图。

方法的参数包括:

在方法体中,创建了一个TextureAndroidViewController实例,并将onFocus回调函数存储在_instance._focusCallbacks中,最后返回创建的控制器实例。

Note

注意,==Android 侧的原生视图只有在首次调用AndroidViewController.setSize后才会被创建。==具体参见《Flutter TextureAndroidViewController#setSize 设置大小》。

实现源码如下:

static TextureAndroidViewController initAndroidView({
  required int id,
  required String viewType,
  required TextDirection layoutDirection,
  dynamic creationParams,
  MessageCodec<dynamic>? creationParamsCodec,
  VoidCallback? onFocus,
}) {
  //...

  final TextureAndroidViewController controller = TextureAndroidViewController._(
    viewId: id,
    viewType: viewType,
    layoutDirection: layoutDirection,
    creationParams: creationParams,
    creationParamsCodec: creationParamsCodec,
  );
  // 全局字典,id 到 _focusCallbacks 的映射
  _instance._focusCallbacks[id] = onFocus ?? () {};
  return controller;
}

_AndroidPlatformView

该类继承自 LeafRenderObjectWidget,它的作用,只是对更加底层的 RenderAndroidView 进行封装,将 RenderAndroidView 的 RenderObject 封装为 Widget,

createRenderObject

对应的是 RenderAndroidView:

@override
RenderObject createRenderObject(BuildContext context) =>
    RenderAndroidView(
      viewController: controller,
      hitTestBehavior: hitTestBehavior,
      gestureRecognizers: gestureRecognizers,
      clipBehavior: clipBehavior,
    );

updateRenderObject

@override
void updateRenderObject(BuildContext context, RenderAndroidView renderObject) {
  renderObject.viewController = controller;
  renderObject.hitTestBehavior = hitTestBehavior;
  renderObject.updateGestureRecognizers(gestureRecognizers);
  renderObject.clipBehavior = clipBehavior;
}

本文作者:Maeiee

本文链接:Flutter AndroidView

版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!


喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!