Flutter PlatformViewsController
PlatformViewsController 是 Flutter 内嵌原生视图能力在 Android 的管理类。
PlatformViewsChannel 只负责接收和解析消息,但不包含处理逻辑。处理逻辑都转发到 PlatformViewsController 来进行实际处理。另外一点,不论是 Virtual displays 模式还是 Hybrid composition 模式,底层都由 PlatformViewsController 统一处理。
除了嵌原生视图之外,该类还负责外接纹理的纹理管理。
核心成员
PlatformViewsController 类成员都是重量级选手:
| 成员 | 类型 | 说明 | 备注 | 
|---|---|---|---|
| registry | PlatformViewRegistryImpl | 所有平台视图的注册表 | |
| androidTouchProcessor | AndroidTouchProcessor | Android 手势处理器 | |
| context | Context | Android Context | |
| flutterView | FlutterView | Android FlutterView,用于展示 Flutter UI 的视图 | |
| textureRegistry | TextureRegistry | 纹理注册表 | |
| textInputPlugin | TextInputPlugin | Flutter 在 Android 侧的输入插件 | |
| platformViewsChannel | PlatformViewsChannel | 与 Flutter 通信的 Channel | 参见笔记《Flutter PlatformViewsChannel》 | 
| accessibilityEventsDelegate | AccessibilityEventsDelegate | Semantic 辅助功能相关 | |
| vdControllers | HashMap<Integer, VirtualDisplayController> | VirtualDisplay 的注册表 | VirtualDisplayController:是用于管理虚拟显示的控制器 | 
| contextToPlatformView | HashMap<Context, View> | 虚拟显示中的实际视图 | 键是 Context对象,值是View对象。每个虚拟显示都有一个唯一的Context。View是Android中的视图,这里特指平台视图。这个映射用于根据Context查找在同一个虚拟显示中的平台视图。 | 
| platformViews | SparseArray<PlatformView>  | Hybrid composition 模式下的平台视图 | |
| platformViewParent | SparseArray<FlutterMutatorView> | HC 平台视图的父视图 | 这是一个 SparseArray,它存储了FlutterMutatorView对象。FlutterMutatorView是一个特殊的视图,它可以对其子视图(即平台视图)应用一些操作,如变换矩阵或设置透明度。 | 
| overlayLayerViews | SparseArray<FlutterImageView> | HC 平台视图的 Overlay UI | 这也是一个 SparseArray,它存储了FlutterImageView对象。FlutterImageView是一个视图,它可以显示一个 Flutter 渲染的图像。 | 
| nextOverlayLayerId | int | 用于生成下一个图层的唯一ID | 默认值为 0 | 
| flutterViewConvertedToImageView | boolean | 跟踪 flutterView 是否已经被转换为 FlutterImageView | 默认值为 false | 
| synchronizeToNativeViewHierarchy | boolean | 设置是否在添加平台视图时,将 flutterView的渲染表面转换为FlutterImageView | 默认值 true | 
| currentFrameUsedOverlayLayerIds | HashSet<Integer> | 储了在当前帧中显示的图层的ID | |
| currentFrameUsedPlatformViewIds | HashSet<Integer> | 储了在当前帧中显示的平台视图的ID | |
| motionEventTracker | MotionEventTracker | 获取原始的触摸事件 | 
PlatformViewsHandler
除了上述成员外,还有一个 PlatformViewsHandler,它实现了 PlatformViewsChannel 的 PlatformViewsHandler 接口,参见《Flutter PlatformViewsChannel#PlatformViewsHandler 接口》。
其功能是,PlatformViewsChannel 收到 Flutter 侧操作请求后,通过该类转到 PlatformViewsController 中处理。
channelHandler 属性是你个匿名内部类:
private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
    new PlatformViewsChannel.PlatformViewsHandler() {
      @Override
      public void createAndroidViewForPlatformView(
          @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
        //...
      }
      @Override
      public void disposeAndroidViewForPlatformView(int viewId) {
        //..
      }
      //...
}
上面代码仅用于释义,channelHandler 内部类实现了 PlatformViewsHandler 接口。这些接口的实现逻辑非常关键,将在后面小节中介绍。
Virtual displays 模式
createVirtualDisplayForPlatformView 创建
首先看 PlatformViewsHandler 的 Virtual displays 模式下创建原生视图的过程:
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public long createVirtualDisplayForPlatformView(
    @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
  // 省略一些校验逻辑...
  // 解码创建参数
  Object createParams = null;
  if (request.params != null) {
    createParams = viewFactory.getCreateArgsCodec().decodeMessage(request.params);
  }
  // 屏幕尺寸
  int physicalWidth = toPhysicalPixels(request.logicalWidth);
  int physicalHeight = toPhysicalPixels(request.logicalHeight);
  validateVirtualDisplayDimensions(physicalWidth, physicalHeight);
  // 创建 SurfaceTexture
  TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture();
  // 创建 Flutter 控制 VirtualDisplay 的控制器
  VirtualDisplayController vdController =
      VirtualDisplayController.create(
          context,
          accessibilityEventsDelegate,
          viewFactory,
          textureEntry,
          physicalWidth,
          physicalHeight,
          request.viewId,
          createParams,
          (view, hasFocus) -> {
            if (hasFocus) {
              platformViewsChannel.invokeViewFocused(request.viewId);
            }
          });
  // ...
  // If our FlutterEngine is already attached to a Flutter UI, provide that Android
  // View to this new platform view.
  if (flutterView != null) {
    vdController.onFlutterViewAttached(flutterView);
  }
  vdControllers.put(request.viewId, vdController);
  View platformView = vdController.getView();
  platformView.setLayoutDirection(request.direction);
  // 这里还对 Context 有所采集,需要注意
  contextToPlatformView.put(platformView.getContext(), platformView);
  // 返回纹理 id
  return textureEntry.id();
}
其中,textureRegistry.createSurfaceTexture 实现类位于 FlutterRenderer,创建了一个 SurfaceTexture 实例,并将其注册进 FlutterEngine 中:
/**
 * Creates and returns a new {@link SurfaceTexture} managed by the Flutter engine that is also
 * made available to Flutter code.
 */
@Override
public SurfaceTextureEntry createSurfaceTexture() {
  Log.v(TAG, "Creating a SurfaceTexture.");
  final SurfaceTexture surfaceTexture = new SurfaceTexture(0);
  return registerSurfaceTexture(surfaceTexture);
}
/**
 * Registers and returns a {@link SurfaceTexture} managed by the Flutter engine that is also made
 * available to Flutter code.
 */
@Override
public SurfaceTextureEntry registerSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) {
  surfaceTexture.detachFromGLContext();
  final SurfaceTextureRegistryEntry entry =
      new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture);
  Log.v(TAG, "New SurfaceTexture ID: " + entry.id());
  registerTexture(entry.id(), entry.textureWrapper());
  return entry;
}
其中,SurfaceTexture 是 Android 系统提供的底层图形渲染组件,其功能为:
Android 的 SurfaceTexture 提供了一种高效的方法,通过 OpenGL ES 将图像流中的帧捕获并作为纹理渲染。这意味着,您可以将来自摄像头、视频文件或其他图像流的帧直接渲染到OpenGL环境中,而不需要进行复杂的数据转换或处理。这样做的好处是能够实现高性能和低延迟的图像处理和显示,非常适合需要实时视频处理的应用,比如视频聊天、增强现实(AR)应用等。
Flutter VirtualDisplayController 是专门负责 Android VirtualDisplay 逻辑的控制器(详情可点击阅读 Flutter VirtualDisplayController ),在 Flutter VirtualDisplayController 的构造函数中会创建 Flutter SingleViewPresentation,在 Presentation 内部会真正创建原生视图。
vdController.onFlutterViewAttached(flutterView); 这步,Flutter VirtualDisplayController 实现逻辑为:
/** See {@link PlatformView#onFlutterViewAttached(View)} */
/*package*/ void onFlutterViewAttached(@NonNull View flutterView) {
  if (presentation == null || presentation.getView() == null) {
    return;
  }
  presentation.getView().onFlutterViewAttached(flutterView);
}
Flutter SingleViewPresentation 的 getView() 将返回 PlatformView,PlatformView 是供开发者在 Native 侧创建的原生视图类。给原生视图一个时机,获取到当前容器的 FlutterView。代码中有一个判断分支,引擎与 FlutterView 不总是绑定状态,当 App 切后台后,两者将会解绑。如果是后台状态下创建的平台视图,这个回调将会在未来返回前台后调用。
detach
这个方法的主要作用是断开PlatformViewsController的连接,通常在Flutter应用程序切换到后台运行或被销毁时调用。
断开后,将停止处理平台视图消息,销毁所有的覆盖层表面,以及释放对Android上下文对象和纹理注册表的引用。
@UiThread
public void detach() {
  if (platformViewsChannel != null) {
    platformViewsChannel.setPlatformViewsHandler(null);
  }
  destroyOverlaySurfaces();
  platformViewsChannel = null;
  context = null;
  textureRegistry = null;
}
Usage:
- PlatformViewsController.detach
- FlutterPluginRegistry.detach
- FlutterNativeView.detach
- 已废弃
 
 
- FlutterNativeView.detach
- FlutterEngineConnectionRegistry.detachFromActivityInternal
 
- FlutterPluginRegistry.detach
detachFromView
detachFromView方法的作用是将PlatformViewsController和其FlutterEngine从渲染Flutter UI的Android View中分离,包括销毁所有的覆盖层表面,从Flutter视图中移除所有的覆盖层视图,以及通知所有的VirtualDisplayController对象Flutter视图已经被分离。
这个方法的主要作用是将PlatformViewsController和其FlutterEngine从渲染Flutter UI的Android View中分离。
public void detachFromView() {
  destroyOverlaySurfaces();
  removeOverlaySurfaces();
  this.flutterView = null;
  flutterViewConvertedToImageView = false;
  // Inform all existing platform views that they are no longer associated with
  // a Flutter View.
  for (VirtualDisplayController controller : vdControllers.values()) {
    controller.onFlutterViewDetached();
  }
}
其中:
- 将 flutterView 置空了
- flutterViewConvertedToImageView 也设置为了 False
FlutterMutatorView 声明周期管理
FlutterMutatorView 是 Hybrid composition 模式下,用于封装 PlatformView 的布局。
在 PlatformViewsController 中,有一个 SparseArray 列表进行管理:
// The platform view parents that are appended to `FlutterView`.
// If an entry in `platformViews` doesn't have an entry in this array, the platform view isn't
// in the view hierarchy.
//
// This view provides a wrapper that applies scene builder operations to the platform view.
// For example, a transform matrix, or setting opacity on the platform view layer.
//
// This is only applies to hybrid composition.
private final SparseArray<FlutterMutatorView> platformViewParent;
创建时机 initializePlatformViewIfNeeded:
/**
 * Initializes a platform view and adds it to the view hierarchy.
 *
 * @param viewId The view ID. This member is not intended for public use, and is only visible for
 *     testing.
 */
@VisibleForTesting
void initializePlatformViewIfNeeded(int viewId) {
  final PlatformView platformView = platformViews.get(viewId);
  // ...
  // 创建 FlutterMutatorView 实例
  final FlutterMutatorView parentView =
      new FlutterMutatorView(
          context, context.getResources().getDisplayMetrics().density, androidTouchProcessor);
  parentView.setOnDescendantFocusChangeListener(
      (view, hasFocus) -> {
        if (hasFocus) {
          platformViewsChannel.invokeViewFocused(viewId);
        } else if (textInputPlugin != null) {
          textInputPlugin.clearPlatformViewClient(viewId);
        }
      });
  // 添加到 platformViewParent
  platformViewParent.put(viewId, parentView);
  // 将 FlutterMutatorView 添加到它的父布局中
  parentView.addView(platformView.getView());
  flutterView.addView(parentView);
}
FlutterMutatorView 什么时候从父布局中删除的?
本文作者:Maeiee
本文链接:Flutter PlatformViewsController
版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!
喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!
