flutter androidView实现原理

2020-08-05  本文已影响0人  ben大福

1,创建PlatformView

PlatformView是flutter中可以渲染原生界面的view,在android中的体现是AndroidView
flutter 创建AndroidView的时候,实际渲染的是_AndroidViewState build方法

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

_initializeOnce是在didChangeDependencies和didUpdateWidget的时候调用的而且除非viewtype改变了否则只会调用一次

_AndroidViewState
  void _initializeOnce() {
    if (_initialized) {
      return;
    }
    _initialized = true;
    _createNewAndroidView();
    _focusNode = FocusNode(debugLabel: 'AndroidView(id: $_id)');
  }

_AndroidViewState
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 ,内部创建了一个AndroidViewController,后面创建Texture就是使用这个类创建的

  static AndroidViewController initAndroidView({
    @required int id,
    @required String viewType,
    @required TextDirection layoutDirection,
    dynamic creationParams,
    MessageCodec<dynamic> creationParamsCodec,
    VoidCallback onFocus,
  }) {
    assert(id != null);
    assert(viewType != null);
    assert(layoutDirection != null);
    assert(creationParams == null || creationParamsCodec != null);
    final AndroidViewController controller = AndroidViewController._(
      id,
      viewType,
      creationParams,
      creationParamsCodec,
      layoutDirection,
    );
    _instance._focusCallbacks[id] = onFocus ?? () {};
    return controller;
  }

视线转移到AndroidView的Render

  RenderAndroidView
  void performResize() {
    size = constraints.biggest;
    _sizePlatformView();
  }

  Future<void> _sizePlatformView() async {
    ···
    do {
      targetSize = size;
      await _viewController.setSize(targetSize);
      _currentAndroidViewSize = targetSize;
      // We've resized the platform view to targetSize, but it is possible that
      // while we were resizing the render object's size was changed again.
      // In that case we will resize the platform view again.
    } while (size != targetSize);
    ...
  }

  Future<void> setSize(Size size) async {
    if (_state == _AndroidViewState.waitingForSize)
      return _create(size);
    await SystemChannels.platform_views.invokeMethod<void>('resize', <String, dynamic>{
      'id': id,
      'width': size.width,
      'height': size.height,
    });
  }

当AndroidViewState为waitingForSize时会调用_create方法

  Future<void> _create(Size size) async {
    ···
    _textureId = await SystemChannels.platform_views.invokeMethod('create', args);
    _state = _AndroidViewState.created;
    for (final PlatformViewCreatedCallback callback in _platformViewCreatedCallbacks) {
      callback(id);
    }
···
  }

此处会调用methodchannel event 为 create返回textureid
继续看android实现

PlatfromViewsChannel.java
        private void create(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
          Map<String, Object> createArgs = call.arguments();
          PlatformViewCreationRequest request =
              new PlatformViewCreationRequest(
                  (int) createArgs.get("id"),
                  (String) createArgs.get("viewType"),
                  (double) createArgs.get("width"),
                  (double) createArgs.get("height"),
                  (int) createArgs.get("direction"),
                  createArgs.containsKey("params")
                      ? ByteBuffer.wrap((byte[]) createArgs.get("params"))
                      : null);

          try {
            long textureId = handler.createPlatformView(request);
            result.success(textureId);
          } catch (IllegalStateException exception) {
            result.error("error", detailedExceptionString(exception), null);
          }
        }

public long createPlatformView(
            @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
          PlatformViewFactory viewFactory = registry.getFactory(request.viewType);
          if (viewFactory == null) {
            throw new IllegalStateException(
                "Trying to create a platform view of unregistered type: " + request.viewType);
          }

          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);

          TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture();
          VirtualDisplayController vdController =
              VirtualDisplayController.create(
                  context,
                  accessibilityEventsDelegate,
                  viewFactory,
                  textureEntry,
                  physicalWidth,
                  physicalHeight,
                  request.viewId,
                  createParams,
                  (view, hasFocus) -> {
                    if (hasFocus) {
                      platformViewsChannel.invokeViewFocused(request.viewId);
                    }
                  });

          if (flutterView != null) {
            vdController.onFlutterViewAttached(flutterView);
          }

          vdControllers.put(request.viewId, vdController);
          View platformView = vdController.getView();
          platformView.setLayoutDirection(request.direction);
          return textureEntry.id();
        }

上图列出关键步骤,textureRegistry创建了一个SurfaceTextureEntry 这就是flutter最终渲染的texture

     @Override
        public void resizePlatformView(
            @NonNull PlatformViewsChannel.PlatformViewResizeRequest request,
            @NonNull Runnable onComplete) {
          ensureValidAndroidVersion();

          final VirtualDisplayController vdController = vdControllers.get(request.viewId);
          if (vdController == null) {
            throw new IllegalStateException(
                "Trying to resize a platform view with unknown id: " + request.viewId);
          }

          int physicalWidth = toPhysicalPixels(request.newLogicalWidth);
          int physicalHeight = toPhysicalPixels(request.newLogicalHeight);
          validateVirtualDisplayDimensions(physicalWidth, physicalHeight);
          lockInputConnection(vdController);
          vdController.resize(
              physicalWidth,
              physicalHeight,
              new Runnable() {
                @Override
                public void run() {
                  unlockInputConnection(vdController);
                  onComplete.run();
                }
              });
        }

VirtualDisplayController 是控制展示的类

  public static VirtualDisplayController create(
      Context context,
      AccessibilityEventsDelegate accessibilityEventsDelegate,
      PlatformViewFactory viewFactory,
      TextureRegistry.SurfaceTextureEntry textureEntry,
      int width,
      int height,
      int viewId,
      Object createParams,
      OnFocusChangeListener focusChangeListener) {
    textureEntry.surfaceTexture().setDefaultBufferSize(width, height);
    Surface surface = new Surface(textureEntry.surfaceTexture());
    DisplayManager displayManager =
        (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);

    int densityDpi = context.getResources().getDisplayMetrics().densityDpi;
    VirtualDisplay virtualDisplay =
        displayManager.createVirtualDisplay("flutter-vd", width, height, densityDpi, surface, 0);

    if (virtualDisplay == null) {
      return null;
    }

    return new VirtualDisplayController(
        context,
        accessibilityEventsDelegate,
        virtualDisplay,
        viewFactory,
        surface,
        textureEntry,
        focusChangeListener,
        viewId,
        createParams);
  }

virturalDisplay需要渲染的显示抽象

create方法创建了VirtualDisplay,他负责渲染图像到Flutter提供的surface。
我们关注SingleViewPresentation

onCreate(){ 创建view,在attacEngine的时候调用
  ··· 
if (state.platformView == null) {
      state.platformView = viewFactory.create(context, viewId, createParams);
    }
  ···
}

然后每次factory创建的自定义view调用onDraw方法就会渲染到flutter提供的surface中,达到在flutter中渲染的目的

AndroidView事件分发

获取到手指事件
  MotionEventDispatcher.dart
  void handlePointerEvent(PointerEvent event) {
    if (event is PointerDownEvent) {
      if (nextPointerId == 0)
        downTimeMillis = event.timeStamp.inMilliseconds;
      pointerProperties[event.pointer] = propertiesFor(event, nextPointerId++);
    }
    pointerPositions[event.pointer] = coordsFor(event);

    dispatchPointerEvent(event);

    ···
  }
分发事件,最终调用了 touch channel回调原生
  _MotionEventsDispatcher.dart
  void dispatchPointerEvent(PointerEvent event) {
    ····
    final AndroidMotionEvent androidMotionEvent = AndroidMotionEvent(
        downTime: downTimeMillis,
        eventTime: event.timeStamp.inMilliseconds,
        action: action,
        pointerCount: pointerPositions.length,
        pointerProperties: pointers.map<AndroidPointerProperties>((int i) => pointerProperties[i]).toList(),
        pointerCoords: pointers.map<AndroidPointerCoords>((int i) => pointerPositions[i]).toList(),
        metaState: 0,
        buttonState: 0,
        xPrecision: 1.0,
        yPrecision: 1.0,
        deviceId: 0,
        edgeFlags: 0,
        source: 0,
        flags: 0,
    );
    viewController.sendMotionEvent(androidMotionEvent);
  ····
  }
  AndroidViewController.dart
  Future<void> sendMotionEvent(AndroidMotionEvent event) async {
    await SystemChannels.platform_views.invokeMethod<dynamic>(
        'touch',
        event._asList(id),
    );
  }

android原生代码接受channel事件处理

PlatformViewsController
       @Override
        public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
          ensureValidAndroidVersion();

          float density = context.getResources().getDisplayMetrics().density;
          PointerProperties[] pointerProperties =
              parsePointerPropertiesList(touch.rawPointerPropertiesList)
                  .toArray(new PointerProperties[touch.pointerCount]);
          PointerCoords[] pointerCoords =
              parsePointerCoordsList(touch.rawPointerCoords, density)
                  .toArray(new PointerCoords[touch.pointerCount]);

          if (!vdControllers.containsKey(touch.viewId)) {
            throw new IllegalStateException(
                "Sending touch to an unknown view with id: " + touch.viewId);
          }
          View view = vdControllers.get(touch.viewId).getView();

          MotionEvent event =
              MotionEvent.obtain(
                  touch.downTime.longValue(),
                  touch.eventTime.longValue(),
                  touch.action,
                  touch.pointerCount,
                  pointerProperties,
                  pointerCoords,
                  touch.metaState,
                  touch.buttonState,
                  touch.xPrecision,
                  touch.yPrecision,
                  touch.deviceId,
                  touch.edgeFlags,
                  touch.source,
                  touch.flags);

          view.dispatchTouchEvent(event);
        }

总结:flutter的AndroidView实现原理是将渲染内容渲染到flutter提供的SurfaceTexture中,然后事件传递是flutter事件传递到原生view实现的,双端的事件冲突在flutter端处理。

由于这种实现方式导致频繁的channel调用性能较差,另外如果嵌入NestedScrollView页面会频繁创建VirtualDisplay,性能会很差

上一篇下一篇

猜你喜欢

热点阅读