剑客
关注科技互联网

在 Fragment 中使用 React Native

React Native 官网提供了在 Activity 中使用 React Native 的方法,最近项目中需要在 Fragment 中使用 React Native,参考 http://stackoverflow.com/questions/35221447/react-native-inside-a-fragment
及各种尝试摸索后总结方法如下。

1. MyApplication

MyApplication
除了实现 ReactApplication
的抽象方法 getReactNativeHost
外,还需要获取到 ReactContext
并提供 get
接口,因为在 Fragment
里无法获取到 ReactContext
,只能获取 Context
,而原生调用 js 时使用 sendEvent
又需要用到 ReactContext

Fragment 中通过 ReactInstanceManager#getCurrentReactContext
获取到的 ReactContext
为空。

publicclassMyApplicationimplementsReactApplication{
// ...

privateReactContext mReactContext;

publicReactContextgetReactContext(){
returnmReactContext;
 }

privatefinalReactNativeHost mReactNativeHost =newReactNativeHost(this) {
@Override
protectedbooleangetUseDeveloperSupport(){
returnBuildConfig.DEBUG;
 }

@Override
protectedList<ReactPackage>getPackages(){
returnArrays.<ReactPackage>asList(
newMainReactPackage(),
newMyReactPackage(),
newOtherReactPackage()
// ...
 );
 }
 };

@Override
publicReactNativeHostgetReactNativeHost(){
returnmReactNativeHost;
 } 

privatevoidregisterReactInstanceEventListener(){
 mReactNativeHost.getReactInstanceManager().addReactInstanceEventListener(mReactInstanceEventListener);
 }

privatevoidunRegisterReactInstanceEventListener(){
 mReactNativeHost.getReactInstanceManager().removeReactInstanceEventListener(mReactInstanceEventListener);
 }

privatefinalReactInstanceManager.ReactInstanceEventListener mReactInstanceEventListener =newReactInstanceManager.ReactInstanceEventListener() {
@Override
publicvoidonReactContextInitialized(ReactContext context){
 mReactContext = context;
 }
 };

@Override
publicvoidonCreate(){
// ...

 registerReactInstanceEventListener();
 }
}

Application
onCreate
方法里注册一个 ReactInstanceEventListener
,用于初始化后获取到 ReactContext

2. ReactInstanceManager

通过 ReactNativeHost#getReactInstanceManager
可以获取 ReactInstanceManager
这个抽象类,它提供了 ReactInstanceEventListener
接口及相应的添加和删除方法。

/**
 * Add a listener to be notified of react instance events.
 */
publicabstractvoidaddReactInstanceEventListener(ReactInstanceEventListener listener);

/**
 * Remove a listener previously added with {@link#addReactInstanceEventListener}.
 */
publicabstractvoidremoveReactInstanceEventListener(ReactInstanceEventListener listener);

/**
 * Listener interface for react instance events.
 */
publicinterfaceReactInstanceEventListener{
/**
 * Called when the react context is initialized (all modules registered). Always called on the
 * UI thread.
 */
voidonReactContextInitialized(ReactContext context);
}

3. BaseReactFragment

BaseReactFragment
继承自自己封装的 Fragment
基类 BaseFragment
,这里需要用到 ReactRootView
ReactInstanceManager

它们在 Fragment
onAttach
方法中获取,并在 onCreateView
方法中返回该 ReactRootView

onActivityCreated
方法中即可使用我们的 React Native 组件,这里需要子类实现 getMainPageName
抽象方法,获取到对应的 React Native 组件。

publicabstractclassBaseReactFragmentextendsBaseFragment{

privateReactRootView mReactRootView;
privateReactInstanceManager mReactInstanceManager;

@Override
publicvoidonAttach(Activity activity){
super.onAttach(activity);
 mReactRootView = newReactRootView(activity);
 mReactInstanceManager = ((MyApplication) getActivity().getApplication()).getReactNativeHost().getReactInstanceManager();
 }

@Nullable
@Override
publicViewonCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){
super.onCreateView(inflater, container, savedInstanceState);
returnmReactRootView;
 }

@Override
publicvoidonViewCreated(View view, Bundle savedInstanceState){
 }

@Override
publicvoidonActivityCreated(@Nullable Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
 mReactRootView.startReactApplication(mReactInstanceManager, getMainPageName(), null);
 }

protectedabstractStringgetMainPageName();

protectedvoidsendEvent(String eventName,
 @Nullable WritableMap params) {
if(((MyApplication) getActivity().getApplication()).getReactContext() !=null) {
 ((MyApplication) getActivity().getApplication()).getReactContext()
 .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
 .emit(eventName, params);
 }
 }
}

sendEvent
方法用于原生调用 js 的接口,需要获取到 ReactContext
对象,通过 ReactInstanceManager#getCurrentReactContext
获取到的 ReactContext
为空,这里从 Application
中获取。

创建一个 BaseReactFragment
的子类用于装载 React Native 组件

publicclassMyFragmentextendsBaseReactFragment{
@Override
publicStringgetMainPageName(){
return"MyComponent";// name of our React Native component we've registered
 }
}

4. BaseReactActivity

BaseReactFragment
所在的 Activity
必须实现 DefaultHardwareBackBtnHandler
,用于绑定 React Native 组件的生命周期。

publicclassBaseReactActivityextendsBaseActivityimplementsDefaultHardwareBackBtnHandler{
/*
 * Get the ReactInstanceManager, AKA the bridge between JS and Android
 * We use a singleton here so we can reuse the instance throughout our app
 * instead of constantly re-instantiating and re-downloading the bundle
 */
privateReactInstanceManager mReactInstanceManager;

@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);

/**
 * Get the reference to the ReactInstanceManager
 */
 mReactInstanceManager =
 ((MyApplication) getActivity().getApplication()).getReactNativeHost().getReactInstanceManager();
 }

@Override
publicvoidinvokeDefaultOnBackPressed(){
super.onBackPressed();
 }

/*
 * Any activity that uses the ReactFragment or ReactActivty
 * Needs to call onHostPause() on the ReactInstanceManager
 */
@Override
protectedvoidonPause(){
super.onPause();

if(mReactInstanceManager !=null) {
 mReactInstanceManager.onHostPause();
 }
 }

/*
 * Same as onPause - need to call onHostResume
 * on our ReactInstanceManager
 */
@Override
protectedvoidonResume(){
super.onResume();

if(mReactInstanceManager !=null) {
 mReactInstanceManager.onHostResume(this,this);
 }
 }

}
分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址