美文网首页
flutter androidView实现原理

flutter androidView实现原理

作者: ben大福 | 来源:发表于2020-08-05 17:57 被阅读0次

    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,性能会很差

    相关文章

      网友评论

          本文标题:flutter androidView实现原理

          本文链接:https://www.haomeiwen.com/subject/ngtorktx.html