Flutter PlatformViewsChannel

在《Flutter Android Virtual Display 实现原理》一文中,完成了对 Virtual displays 模式的 Flutter 侧实现分析。从这一篇开始,进入 Android 侧的实现分析。PlatformViewsChannel是 Flutter SDK 中的一个 Java 类,用于与 Flutter 侧 Virtual displays 模式相关类进行通信。

Virtual displays 模式中,Android 原生视图的创建与销毁,完全是由 Flutter 侧 AndroidView 组件的生命周期所驱动。AndroidView 这个 SatefulWidget 控制了什么时候要创建、销毁原生视图。两者之间通过 Channel 进行通信,在 Dart 一头的 Channel 为 SystemChannels.platform_views(具体参见《Flutter TextureAndroidViewController》,在 Android 一侧对应的接收方就是本文的 PlatformViewsChannel。

Note

不论是 Virtual displays 模式还是 Hybrid composition 模式,他们在 Android 侧对接的都是 PlatformViewsChannel


核心成员

该类有两个成员值得关注:

// 与 Flutter 通信的 Channel
private final MethodChannel channel;

// 接口类,代理实现
private PlatformViewsHandler handler;

PlatformViewsChannel 中只负责消息的接收、解析,并不包含具体处理逻辑。具体处理逻辑都通过 PlatformViewsHandler 接口进行。而该接口的实现,位于 PlatViewsController 中。


PlatformViewsHandler 接口

PlatformViewsHandler 接口声明了 Virtual displays 模式下,Flutter 侧与 Android 侧通信的所有能力,这些方法如下:

其中,对于 synchronizeToNativeViewHierarchy 并没有讲解透彻,这部分留到分析 Hybrid composition 模式时,在进行透彻研究。


PlatformViewCreationRequest 接口

在创建平台视图的 API 中,参数中包含一个 PlatformViewCreationRequest 类型的参数,这是创建平台视图所需的信息:

/** Request sent from Flutter to create a new platform view. */
public static class PlatformViewCreationRequest {
  // 视图 ID,由 Flutter 侧创建
  public final int viewId;

  // 视图类型
  @NonNull public final String viewType;

  /** The density independent width to display the platform view. */
  public final double logicalWidth;

  /** The density independent height to display the platform view. */
  public final double logicalHeight;

  // 布局方向
  public final int direction;

  // 视图的构建参数
  @Nullable public final ByteBuffer params;
}

接收消息

PlatformViewsChannel 并不复杂,本质上是个 Channel,设置 setMethodCallHandler 来接受 Flutter 侧消息。首先在构造函数中关联 Channel:

public PlatformViewsChannel(@NonNull DartExecutor dartExecutor) {
  channel =
      new MethodChannel(dartExecutor, "flutter/platform_views", StandardMethodCodec.INSTANCE);
  channel.setMethodCallHandler(parsingHandler);
}

由 parsingHandler 负责解析:

private final MethodChannel.MethodCallHandler parsingHandler =
    new MethodChannel.MethodCallHandler() {
      @Override
      public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        //...
        switch (call.method) {
          case "create":
            create(call, result);
            break;
          case "dispose":
            dispose(call, result);
            break;
          case "resize":
            resize(call, result);
            break;
          case "touch":
            touch(call, result);
            break;
          case "setDirection":
            setDirection(call, result);
            break;
          case "clearFocus":
            clearFocus(call, result);
            break;
          case "synchronizeToNativeViewHierarchy":
            synchronizeToNativeViewHierarchy(call, result);
            break;
          default:
            result.notImplemented();
        }
      }

其中:parsingHandler 创建了一个匿名内部类实例,create、dispose 这些方法都定义在内部类内部。

通过上面代码,能清晰了解到 platform_views 这条 Channel 上传递事件的全集。接下来我们对这些方法进行逐个分析。处理逻辑都是一样的:解析参数,调用 PlatformViewsHandler 中对应的 API,下面以 create 方法为例。


MethodCallHandler.create

private void create(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
  Map<String, Object> createArgs = call.arguments();
  // 是否是 Hybrid composition 模式
  boolean usesHybridComposition =
      createArgs.containsKey("hybrid") && (boolean) createArgs.get("hybrid");
  // Hybrid composition 模式下,尺寸由 the Flow layer 的尺寸决定
  double width = (usesHybridComposition) ? 0 : (double) createArgs.get("width");
  double height = (usesHybridComposition) ? 0 : (double) createArgs.get("height");

  PlatformViewCreationRequest request =
      new PlatformViewCreationRequest(
          (int) createArgs.get("id"),          // 视图 id
          (String) createArgs.get("viewType"), // 视图类型
          width,                               // 视图宽度
          height,                              // 视图高度
          (int) createArgs.get("direction"),   // 视图方向
          createArgs.containsKey("params")     // 视图创建参数
              ? ByteBuffer.wrap((byte[]) createArgs.get("params"))
              : null);
  try {
    // 根据不同模式,调用不同的 API
    if (usesHybridComposition) {
      handler.createAndroidViewForPlatformView(request);
      result.success(null);
    } else {
      // Virtual Display 模式下,创建的原生视图得到一个纹理 id,需要传回给 Flutter 侧
      long textureId = handler.createVirtualDisplayForPlatformView(request);
      result.success(textureId);
    }
  } catch (IllegalStateException exception) {
    result.error("error", detailedExceptionString(exception), null);
  }
}

本文作者:Maeiee

本文链接:Flutter PlatformViewsChannel

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


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