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