ReactNative源码分析之UI事件分发

本文深入探讨ReactNative的事件分发机制,从ReactRootView的onInterceptTouchEvent和onTouchEvent开始,分析如何通过JSTouchDispatcher将事件传递到JavaScript层。详细梳理了从事件触发到JS线程处理的完整流程,包括事件目标定位、事件队列合并以及避免阻塞JS线程的策略。
摘要由CSDN通过智能技术生成

ReactNative用的版本: 0.61.5

原生层事件的触发入口主要有两个类:
1. ReactRootView
2. 自定义的ViewManager对应的viewGroup

今天我们主要梳理ReactRootView事件传递

一、ReactRootView

JavaScript中加载的View最终会依附在ReactRootView上,而该类正是Activity创建后,加载的ContentView, 我们看下源码

public class ReactRootView extends 
	FrameLayout implements RootView, ReactRoot {
   
}

我们看到ReactRootView继承FrameLayout,本身是个ViewGroup,再看看它的拦截方法:

// An highlighted block
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
   
    dispatchJSTouchEvent(ev);
    return super.onInterceptTouchEvent(ev);
  }

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
   
    dispatchJSTouchEvent(ev);
    super.onTouchEvent(ev);
    return true;
  }
  

这两个方法都由dispatchJSTouchEvent拦截处理,我们再看看dispatchJSTouchEvent实现:

private void dispatchJSTouchEvent(MotionEvent event) {
   
    if (mReactInstanceManager == null
        || !mIsAttachedToInstance
        || mReactInstanceManager.getCurrentReactContext() == null) {
   
      FLog.w(
          ReactConstants.TAG,
          "Unable to dispatch touch to JS as the catalyst instance has not been attached");
      return;
    }
    if (mJSTouchDispatcher == null) {
   
      FLog.w(
          ReactConstants.TAG, "Unable to dispatch touch to JS before the dispatcher is available");
      return;
    }
    ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
    EventDispatcher eventDispatcher =
        reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
    mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher);
  }
  

该方法核心逻辑如下:
1.通过ReactInstanceManager获取ReactContext。
2.通过ReactContext获取NativeModule(UIManagerModule)里的EventDispatcher。
3.调用JSTouchDispatcher的handleTouchEvent方法

我们看到dispatchJSTouchEvent方法最终会调用JSTouchDispatcher的handleTouchEvent方法,传入event和eventDispatcher。

二、JSTouchDispatcher

我们看到不管onInterceptTouchEvent还是onTouchEvent最终都交由 JSTouchDispatcher代理,调用handleTouchEvent方法,那JSTouchDispatcher在哪里初始化呢?

  public void onAttachedToReactInstance() {
   
    mJSTouchDispatcher = new JSTouchDispatcher(this);
    if (mRootViewEventListener != null) {
   
      mRootViewEventListener.onAttachedToReactInstance(this);
    }
  }

我们看到onAttachedToReactInstance方法会初始化JSTouchDispatcher,并且把ViewGroup传递到该类里。

那么onAttachedToReactInstance方法又是在哪里调用?

我们看下该方法的调用堆栈,发现在ReactRootView的onMeasure方法会触发。

整个调用流程为如下:
1.onMeasure (ReactRootView)
2.attachToReactInstanceManager (ReactRootView)
3.attachRootView (ReactInstanceManager)
4.attachRootViewToInstance (ReactInstanceManager)
5.onStage (ReactRootView)
6.onAttachedToReactInstance (ReactRootView)

看看JSTouchDispatcher内部实现:

/**
   * Main catalyst view is responsible for collecting and sending touch events to JS. This method
   * reacts for an incoming android native touch events ({@link MotionEvent}) and calls into {@link
   * com.facebook.react.uimanager.events.EventDispatcher} when appropriate. It uses {@link
   * com.facebook.react.uimanager.TouchTargetHelper#findTouchTargetView} helper method for figuring
   * out a react view ID in the case of ACTION_DOWN event (when the gesture starts).
   */
  public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) {
   
    int action = ev.getAction() & MotionEvent.ACTION_MASK;
    if (action == MotionEvent.ACTION_DOWN) {
   
      if (mTargetTag != -1) {
   
        FLog.e(
            ReactConstants.TAG, "Got DOWN touch before receiving UP or CANCEL from last gesture");
      }

      // First event for this gesture. We expect tag to be set to -1, and we use helper method
      // {@link #findTargetTagForTouch} to find react view ID that will be responsible for handling
      // this gesture
      mChildIsHandlingNativeGesture = false;
      mGestureStartTime = ev.getEventTime();
      mTargetTag = findTargetTagAndSetCoordinates(ev);
      eventDispatcher.dispatchEvent(
          To
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值