RN之ReactActivity源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fox_wei_hlz/article/details/79056426

我们来分析一下ReactActivity这个类

import android.app.Activity;   1
import android.content.Intent; 2
import android.os.Bundle;  2
import android.view.KeyEvent;  3

import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.PermissionAwareActivity;  4
import com.facebook.react.modules.core.PermissionListener;   5

1:是我们android的activity

2:是我们的intent以及bundle

3:是按键

4:是权限的确认等类

5:权限的监听

下面来分析一下我们类的头部是什么

public abstract class ReactActivity extends Activity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity

这俩个,第一个是我们的物理键,第二个是权限的

在这边我们没看到什么东西,我们继续看下面的:

  private final ReactActivityDelegate mDelegate;

这个类,我们进去看一下:

public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
  mActivity = activity;
  mMainComponentName = mainComponentName;
  mFragmentActivity = null;
}

public ReactActivityDelegate(
  FragmentActivity fragmentActivity,
  @Nullable String mainComponentName) {
  mFragmentActivity = fragmentActivity;
  mMainComponentName = mainComponentName;
  mActivity = null;
}

看到这边,我们是不是应该醒悟了- -!!,马丹的,人家facebook特地给我们做了FragmentActivity这个类的,不单单是activity。

继续看下去

protected @Nullable Bundle getLaunchOptions() {
  return null;
}

这个玩意?What?Null值,我使用过,其实这个是作为提前传值到bundle,而不是走异步!!

继续看下去:

protected ReactRootView createRootView() {
  return new ReactRootView(getContext());
}

创建ReactRootView,这个是干嘛的?我们看一下ReactRootView这个是什么鬼:

先看头部:

public class ReactRootView extends SizeMonitoringFrameLayout implements RootView

这个类:SizeMonitoringFrameLayout 里面的操作是什么呢?一起看一下:

一样的先看头部

public class SizeMonitoringFrameLayout extends FrameLayout

哎哟~继承了我们的FrameLayout。

然后我们来看一下方法体:

//这个是尺寸的宽高改变类,以及监听方法

public static interface OnSizeChangedListener {
  void onSizeChanged(int width, int height, int oldWidth, int oldHeight);
}

private @Nullable OnSizeChangedListener mOnSizeChangedListener;

public SizeMonitoringFrameLayout(Context context) {
  super(context);
}

public SizeMonitoringFrameLayout(Context context, AttributeSet attrs) {
  super(context, attrs);
}

public SizeMonitoringFrameLayout(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
}

public void setOnSizeChangedListener(OnSizeChangedListener onSizeChangedListener) {
  mOnSizeChangedListener = onSizeChangedListener;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);

  if (mOnSizeChangedListener != null) {
    mOnSizeChangedListener.onSizeChanged(w, h, oldw, oldh);
  }
}

继续往下走,看我们的RootView onChildStartedNativeGesture手势接口。

 

现在我们回归ReactRootView

我们看看里面讲了一些什么?

马上看到了一个root view的事件接口

public interface ReactRootViewEventListener {
  /**
   * Called when the react context is attached to a ReactRootView.
   */
  void onAttachedToReactInstance(ReactRootView rootView);
}

下面这个方法就是最外层的rootview的一些触摸事件传入js里面进行处理,从onTouchEvent和onInterceptTouchEvent调用handleTouchEvent。它将正确找到正确的视图处理触摸,并向JS发送适当的事件

private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this);

我们继续往下走,看到重写了onChildStartedNativeGesture这个手势方法

@Override
public void onChildStartedNativeGesture(MotionEvent androidEvent) {
  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;
  }
  ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
  EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class)
    .getEventDispatcher();
  mJSTouchDispatcher.onChildStartedNativeGesture(androidEvent, eventDispatcher);
}

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

@Override
public boolean onTouchEvent(MotionEvent ev) {
  dispatchJSTouchEvent(ev);
  super.onTouchEvent(ev);
  // In case when there is no children interested in handling touch event, we return true from
  // the root view in order to receive subsequent events related to that gesture
  return true;
}

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;
  }
  ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
  EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class)
    .getEventDispatcher();
  mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher);
}

@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
  // Override in order to still receive events to onInterceptTouchEvent even when some other
  // views disallow that, but propagate it up the tree if possible.
  if (getParent() != null) {
    getParent().requestDisallowInterceptTouchEvent(disallowIntercept);
  }

-------------------手势的,以及触摸的---------------------------------------

这里就不讲解了,有兴趣自己去看一下,下面看到这俩个方法,我就有点想法了,onAttachedToWindow()来防止多重的

@Override
protected void onAttachedToWindow() {
  super.onAttachedToWindow();
  if (mIsAttachedToInstance) {
    getViewTreeObserver().addOnGlobalLayoutListener(getCustomGlobalLayoutListener());
  }
}

@Override
protected void onDetachedFromWindow() {
  super.onDetachedFromWindow();
  if (mIsAttachedToInstance) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
      getViewTreeObserver().removeOnGlobalLayoutListener(getCustomGlobalLayoutListener());
    } else {
      getViewTreeObserver().removeGlobalOnLayoutListener(getCustomGlobalLayoutListener());
    }
  }
}

我们继续看下去,这个方法,看到了大家应该都明白了,这边就不多说了

private void sendEvent(String eventName, @Nullable WritableMap params) {
  if (mReactInstanceManager != null) {
    mReactInstanceManager.getCurrentReactContext()
        .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
        .emit(eventName, params);
  }
}

那么总结一下这个ReactRootView类里面控制了很多东西,手势,触摸事件,发送异步信息等,简单的说,这个就是一个视图容器,甚至是存放jsbundle的以及显示的。

现在我们回归ReactActivityDelegate这个类,看到了oncreate,必须停留的:

protected void onCreate(Bundle savedInstanceState) {
  boolean needsOverlayPermission = false;
  if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    // Get permission to show redbox in dev builds.
    if (!Settings.canDrawOverlays(getContext())) {
      needsOverlayPermission = true;
      Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName()));
      FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
      Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
      ((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE);
    }
  }

  if (mMainComponentName != null && !needsOverlayPermission) {
    loadApp(mMainComponentName);
  }
  mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
}

判断版本,以及权限,还有加载我们的app了

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);
}

看到了里面的东西首先是创建容器,不看了。看一下里面的一些东西,getReactNativeHost().getReactInstanceManager()这个是我们初始化的文件,appkey是我们注册的名称。getLaunchOptions()这个方法就是我们混合开发的时候需要使用的到的数据不要异步处理,达到我们需要的一些效果。

---------------------------小小的插入一下---------------------------

如何使用:getLaunchOptions,在我们继承的ReactActivity里面重写这个方法:

 

@Override
protected ReactActivityDelegate createReactActivityDelegate() {
    return new MyReactDelegate(this,getMainComponentName());
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

class MyReactDelegate extends ReactActivityDelegate {

    public MyReactDelegate(Activity activity, @Nullable String mainComponentName) {
        super(activity, mainComponentName);
    }

    @Nullable
    @Override
    protected Bundle getLaunchOptions() {
        Bundle bundle=new Bundle();
        bundle.putString("kkk","good");//注 key 是关键字 js会过滤掉  这个是大坑
        return bundle;
    }
}

其中在我们的js里面的该如何调用到呢,其实这个位子的good,我们可以使用我们安卓的getIntent.getString(),这个方式将我们的值传入。然后在我们的js里面,第一个注册的页面,使用this.props.kkk就可以获取到我们需要的值了。

-----------------------这边就ok了----------------------------

我们可以看到我们的ReactActivityDelegate类里面出现了很多oncreate这些生命周期。

继续往下看:

public boolean onBackPressed() {
  if (getReactNativeHost().hasInstance()) {
    getReactNativeHost().getReactInstanceManager().onBackPressed();
    return true;
  }
  return false;
}

看到了我们的返回键- -

 

然后。。。。。。木有太多了-----

再次插入东西,这个当我们界面方法变化的时候,我们可以作为一个预加载的方案

public void onWindowFocusChanged(boolean hasFocus);

到这边其实差不多了

展开阅读全文

没有更多推荐了,返回首页