Android Flutter 页面启动以及绘制、输入事件传递流程

环境说明

Flutter 3.3.10
flutter android embedding 1.0.0

Flutter Android页面启动

关键类
FlutterActivity
FlutterFragment
FlutterFragmentActivity

FlutterView
FlutterEngine
FlutterRender
FlutterJNI

以FlutteryActivity为例

1.关键函数FlutterJNI#nativeSurfaceCreated

FlutterActivity#onCreate() 函数里创建FlutterView对象并setContentView

FlutterView里的成员变量renderSurface指向的是三种view的一种,FlutterSurfaceView、
FlutterTextureView、FlutterImageView

如果是FlutterSurfaceView则在SurfaceHolder.Callback#surfaceCreated()回调函数里最终调用native函数FlutterJNI#nativeSurfaceCreated(long nativeShellHolderId, @NonNull Surface surface)
实现给flutter engine送android应用端的Surface,这是获取SurfaceFlinger分配的GraphicBuffer代理类,属于图形缓冲区的生产者
在这里插入图片描述

2.关键函数FlutterJNI#nativeRunBundleAndSnapshotFromLibrary

如果FlutterView里的成员变量renderSurface指向的是FlutterSurfaceView类
FlutterActivity#onStart()最终会调用native方法FlutterJNI#nativeRunBundleAndSnapshotFromLibrary(
long nativeShellHolderId,
@NonNull String bundlePath,
@Nullable String entrypointFunctionName,
@Nullable String pathToEntrypointFunction,
@NonNull AssetManager manager,
@Nullable List entrypointArgs)

  执行dart应用主入口函数,默认是main.dart文件的main函数

在这里插入图片描述

3.总结

综上可以看出:

1.核心绘制逻辑是由FlutterView发起的(确切的说是FlutterView的成员变量renderSurface执行dart入口函数以及关联android应用端的Surface窗口,也就是绑定本地平台的窗口,android底层是ANativeWindow)

2.而FlutterActivity承接了组件生命周期方法回调

Flutter Android页面绘制

执行dart入口函数

源码文件 main.dart

void main() {
    
    
  runApp(const MyApp());
}

1.创建三棵树(Widget、Element、RenderObject树)并关联

flutter dart framework 源码文件 widgets\binding.dart

void runApp(Widget app) {
    
    
  WidgetsFlutterBinding.ensureInitialized()
    ..scheduleAttachRootWidget(app)
    ..scheduleWarmUpFrame();
}
  void scheduleAttachRootWidget(Widget rootWidget) {
    
    
    Timer.run(() {
    
    
      attachRootWidget(rootWidget);
    });
  }
  /// Takes a widget and attaches it to the [renderViewElement], creating it if
  /// necessary.
  ///
  /// This is called by [runApp] to configure the widget tree.
  ///
  /// See also:
  ///
  ///  * [RenderObjectToWidgetAdapter.attachToRenderTree], which inflates a
  ///    widget and attaches it to the render tree.
  void attachRootWidget(Widget rootWidget) {
    
    
    final bool isBootstrapFrame = renderViewElement == null;
    _readyToProduceFrames = true;
    _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
      container: renderView,
      debugShortDescription: '[root]',
      child: rootWidget,
    ).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
    if (isBootstrapFrame) {
    
    
      SchedulerBinding.instance.ensureVisualUpdate();
    }
  }

在attachRootWidget函数中入参rootWidget为app开发者传递的根widget树,而成员变量renderView为根RenderObject树

 /// Inflate this widget and actually set the resulting [RenderObject] as the
  /// child of [container].
  ///
  /// If `element` is null, this function will create a new element. Otherwise,
  /// the given element will have an update scheduled to switch to this widget.
  ///
  /// Used by [runApp] to bootstrap applications.
  RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {
    
    
    if (element == null) {
    
    
      owner.lockState(() {
    
    
        element = createElement();
        assert(element != null);
        element!.assignOwner(owner);
      });
      owner.buildScope(element!, () {
    
    
        element!.mount(null, null);
      });
    } else {
    
    
      element._newWidget = this;
      element.markNeedsBuild();
    }
    return element!;
  }

而在attachToRenderTree函数中创建了关联的根Element树,至此初始化逻辑里完成了三棵树的创建与关联

2.注册监听vsync信号,等待vsync信号到来发起绘制

注册Vsync信号监听

在这里插入图片描述
flutter dart framework 源码文件 scheduler\binding.dart

void scheduleFrame() {
    
    
    if (_hasScheduledFrame || !framesEnabled) {
    
    
      return;
    }
    assert(() {
      if (debugPrintScheduleFrameStacks) {
        debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
      }
      return true;
    }());
    ensureFrameCallbacksRegistered();
    platformDispatcher.scheduleFrame();
    _hasScheduledFrame = true;
  }

flutter dart framework 源码文件 platform_dispatcher.dart

/// Requests that, at the next appropriate opportunity, the [onBeginFrame] and
  /// [onDrawFrame] callbacks be invoked.
  ///
  /// See also:
  ///
  ///  * [SchedulerBinding], the Flutter framework class which manages the
  ///    scheduling of frames.
  void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';
Vsync回调执行
总结

整个注册和回调执行流程,可以看到是从dart->native->java->native->dart的调用流程

总的来说就是:

dart (注册vysnc回调)
->native flutter engine层(c c++实现)
->java (flutter embedding库FlutterJNI.java、android系统Choreographer类)
->native flutter engine层(c c++实现)
->dart (vsync回调执行)

3.Flutter Android绘制原理

Flutter Android端只是三棵树(确切说是RenderObject树)渲染到Android Surface本地窗口
图层合成以及送显仍然交给SurfaceFlinger,并不是替代了SF,之前以为android平台Flutter完全替代了SF的理解是错误的

监听处理Flutter Android输入事件(手势)

这里要提一下FlutterView为什么是FrameLayout子类,而不是直接用
FlutterSurfaceView、FlutterTextureView、FlutterImageView

因为只有非SurfaceView的普通view才能接受android系统ViewRootImpl派发的各种手势事件??这里用了一个AndroidTouchProcessor

1.FlutterView在由FlutterActivity#onCreate()间接调用FlutterView#attachToFlutterEngine初始化AndroidTouchProcessor

public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
    
    
。。。
androidTouchProcessor =
        new AndroidTouchProcessor(this.flutterEngine.getRenderer(), /*trackMotionEvents=*/ false);
。。。
}

在这里插入图片描述

2.FlutterVIew的touch事件全部委托给AndroidTouchProcessor处理

FlutterVIew.java

public boolean onTouchEvent(@NonNull MotionEvent event) {
    
    
    if (!isAttachedToFlutterEngine()) {
    
    
      return super.onTouchEvent(event);
    }

    // TODO(abarth): This version check might not be effective in some
    // versions of Android that statically compile code and will be upset
    // at the lack of |requestUnbufferedDispatch|. Instead, we should factor
    // version-dependent code into separate classes for each supported
    // version and dispatch dynamically.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    
    
      requestUnbufferedDispatch(event);
    }

    return androidTouchProcessor.onTouchEvent(event);
  }

AndroidTouchProcessor.java

  /**
   * Sends the given {
    
    @link MotionEvent} data to Flutter in a format that Flutter understands.
   *
   * @param event The motion event from the view.
   * @param transformMatrix Applies to the view that originated the event. It's used to transform
   *     the gesture pointers into screen coordinates.
   * @return True if the event was handled.
   */
  public boolean onTouchEvent(@NonNull MotionEvent event, @NonNull Matrix transformMatrix) {
    
    
    ...
    // Send the packet to Flutter.
    renderer.dispatchPointerDataPacket(packet, packet.position());
	...
    return true;
  }

FlutterRenderer.java

public void dispatchPointerDataPacket(@NonNull ByteBuffer buffer, int position) {
    
    
    flutterJNI.dispatchPointerDataPacket(buffer, position);
  }

FlutterJNI.java

@UiThread
  public void dispatchPointerDataPacket(@NonNull ByteBuffer buffer, int position) {
    
    
    ensureRunningOnMainThread();
    ensureAttachedToNative();
    nativeDispatchPointerDataPacket(nativeShellHolderId, buffer, position);
  }

这里的关键函数nativeDispatchPointerDataPacket就是通过flutter engine间接把各种touch事件分发给了dart widget树

参考资料

https://yanbober.blog.csdn.net/article/details/119086759

猜你喜欢

转载自blog.csdn.net/weixin_41548050/article/details/129928487
今日推荐