React-Native系列Android源码分析

使用了一段时间的react-native,它的UI设计方式真是酷炫,原来我是学android的,由于有android的开发基础,所以我打算从java上学习react-native在原生代码上的设计,并且写下该文章笔记作为以后的知识回顾。

  • react-native版本 0.33.0

AndroidManifest.xml

    ...
    <application
      android:name=".MainApplication" //使用自己的Application
      android:allowBackup="true"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity" // 初始Activity
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"> // 添加配置监听
        <intent-filter> // 隐式intent配置
            <action android:name="android.intent.action.MAIN" /> // 决定应用程序最先启动的Activity
            <category android:name="android.intent.category.LAUNCHER" /> // 决定应用程序是否显示在程序列表里
        intent-filter>
      activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> // debug模式下react-native的工具Activity
    application>

manifest>

MainApplication.java

// ReactApplication接口定义getReactNativeHost方法
public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    // 开发者模式开关
    @Override
    protected boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG; // 全局类BuildConfig,判断是否为debug模式
    }
    // 返回ReactPackage对象数组,
    // ReactPackage定义基本的原生模块和视图管理
    @Override
    protected List getPackages() {
      return Arrays.asList(
          new MainReactPackage()
      );
    }
  };

  // ReactNativeHost控制一个ReactInstanceManager对象
  @Override
  public ReactNativeHost getReactNativeHost() {
      return mReactNativeHost;
  }
}

MainActivity继承com.facebook.react.ReactActivity,ReactActivity实现DefaultHardwareBackBtnHandler(机器返回按钮接口,触发JS中返回按钮监听事件),PermissionAwareActivity两个接口,使用ReactActivityDelegate封装主干代码的

com.facebook.react.ReactActivityDelegate

/**
 * MainActivity的初始化
 */
public class ReactActivityDelegate {
  private static final String REDBOX_PERMISSION_MESSAGE =
    "Overlay permissions needs to be granted in order for react native apps to run in dev mode";

  private final @Nullable Activity mActivity;
  private final @Nullable FragmentActivity mFragmentActivity;
  private final @Nullable String mMainComponentName; // app名

  private @Nullable ReactRootView mReactRootView; // 根视图
  private @Nullable DoubleTapReloadRecognizer  mDoubleTapReloadRecognizer; // 双击'R'键Reload JS
  private @Nullable PermissionListener mPermissionListener;
  ...
  protected void onCreate(Bundle savedInstanceState) {
    if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
      // Get permission to show redbox in dev builds.
      if (!Settings.canDrawOverlays(getContext())) {
        Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
        getContext().startActivity(serviceIntent);
        FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
        Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
      }
    }

    if (mMainComponentName != null) {
      loadApp(mMainComponentName); // 创建ReactRootView
    }
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
  }

  protected void loadApp(String appKey) {
    if (mReactRootView != null) {
      throw new IllegalStateException("Cannot loadApp while app is already running.");
    }
    mReactRootView = createRootView();
    mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(),
      appKey,
      getLaunchOptions());
    getPlainActivity().setContentView(mReactRootView);
  }
  ...
  private Context getContext() {
    if (mActivity != null) {
      return mActivity;
    }
    return Assertions.assertNotNull(mFragmentActivity);
  }

  // 返回Activity或FragmentActivity转换后的Activity
  private Activity getPlainActivity() {
    return ((Activity) getContext());
  }

}

ReactRootView继承SizeMonitoringFrameLayout,基础父类为FrameLayout。

ReactRootView

...
/**
 * 监听窗口大小变化改变内部布局,获取触摸事件遍历子视图触发JSTouchDispatcher中的响应事件
 * 重写ViewGroup方法:
 *   onInterceptTouchEvent
 *   requestDisallowInterceptTouchEvent
 * 重写View方法:
 *   onTouchEvent
 */
public class ReactRootView extends SizeMonitoringFrameLayout implements RootView {
  ...
  /**
   * 获取所有的屏幕触摸事件
   */
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    dispatchJSTouchEvent(ev);
    return super.onInterceptTouchEvent(ev);
  }

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    dispatchJSTouchEvent(ev);
    super.onTouchEvent(ev);
    // 当没有子类触发时返回true
    // 从而允许后续的触摸
    return true;
  }

  private void dispatchJSTouchEvent(MotionEvent event) {
    ...
    // 所有事件统一通过JSTouchDispatcher发送触摸事件给JS
    mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher);
  } 
  ...
} 

JSTouchDispatcher

/**
 * 触摸事件和JS事件连接
 */
public class JSTouchDispatcher {
  ...
  // 找出触发事件的视图ID
  public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) {

    //MotionEvent.ACTION_POINTER_DOWN 多点按下
    int action = ev.getAction() & MotionEvent.ACTION_MASK; // 获取action,添加&...支持多点触摸
    if (action == MotionEvent.ACTION_DOWN) {
      // mTargetTag按钮事件标识符,-1为初始
      if (mTargetTag != -1) {
        FLog.e(
          ReactConstants.TAG,
          "Got DOWN touch before receiving UP or CANCEL from last gesture");
      }

      // 是否取消原生手势
      mChildIsHandlingNativeGesture = false;
      // 查找触发手势的视图ID
      mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch(
        ev.getX(),
        ev.getY(),
        mRootViewGroup,
        mTargetCoordinates, // 储存ev的x,y
        null);
      // 处罚获取到的子类视图ID,处罚内部的JS事件
      eventDispatcher.dispatchEvent(
        TouchEvent.obtain(
          mTargetTag,
          TouchEventType.START, // 说明是按下事件
          ev,
          mTargetCoordinates[0],
          mTargetCoordinates[1],
          mTouchEventCoalescingKeyHelper));
    }  
    ...后面的结构基本相同,主要是通过eventDispatcher.dispatchEvent触发不同的JS事件
  }
  ...
}

touch部分这里只是简单的介绍了下,详细解析可以参考React-Native系列Android——Touch事件原理及状态效果

你可能感兴趣的:(Android,RN,java,源码,react)