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
为空。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| public class MyApplication implements ReactApplication { private ReactContext mReactContext; public ReactContext getReactContext() { return mReactContext; } private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new MyReactPackage(), new OtherReactPackage() ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } private void registerReactInstanceEventListener() { mReactNativeHost.getReactInstanceManager().addReactInstanceEventListener(mReactInstanceEventListener); } private void unRegisterReactInstanceEventListener() { mReactNativeHost.getReactInstanceManager().removeReactInstanceEventListener(mReactInstanceEventListener); } private final ReactInstanceManager.ReactInstanceEventListener mReactInstanceEventListener = new ReactInstanceManager.ReactInstanceEventListener() { @Override public void onReactContextInitialized(ReactContext context) { mReactContext = context; } }; @Override public void onCreate() { registerReactInstanceEventListener(); } }
|
在 Application
的 onCreate
方法里注册一个 ReactInstanceEventListener
,用于初始化后获取到 ReactContext
。
2. ReactInstanceManager
通过 ReactNativeHost#getReactInstanceManager
可以获取 ReactInstanceManager
这个抽象类,它提供了 ReactInstanceEventListener
接口及相应的添加和删除方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| * Add a listener to be notified of react instance events. */ public abstract void addReactInstanceEventListener(ReactInstanceEventListener listener); * Remove a listener previously added with {@link #addReactInstanceEventListener}. */ public abstract void removeReactInstanceEventListener(ReactInstanceEventListener listener); * Listener interface for react instance events. */ public interface ReactInstanceEventListener { * Called when the react context is initialized (all modules registered). Always called on the * UI thread. */ void onReactContextInitialized(ReactContext context); }
|
3. BaseReactFragment
BaseReactFragment
继承自自己封装的 Fragment
基类 BaseFragment
,这里需要用到 ReactRootView
和 ReactInstanceManager
。
它们在 Fragment
的 onAttach
方法中获取,并在 onCreateView
方法中返回该 ReactRootView
。
在 onActivityCreated
方法中即可使用我们的 React Native 组件,这里需要子类实现 getMainPageName
抽象方法,获取到对应的 React Native 组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public abstract class BaseReactFragment extends BaseFragment { private ReactRootView mReactRootView; private ReactInstanceManager mReactInstanceManager; @Override public void onAttach(Activity activity) { super.onAttach(activity); mReactRootView = new ReactRootView(activity); mReactInstanceManager = ((MyApplication) getActivity().getApplication()).getReactNativeHost().getReactInstanceManager(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); return mReactRootView; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mReactRootView.startReactApplication(mReactInstanceManager, getMainPageName(), null); } protected abstract String getMainPageName(); protected void sendEvent(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 组件
1 2 3 4 5 6
| public class MyFragment extends BaseReactFragment { @Override public String getMainPageName() { return "MyComponent"; } }
|
4. BaseReactActivity
BaseReactFragment
所在的 Activity
必须实现 DefaultHardwareBackBtnHandler
,用于绑定 React Native 组件的生命周期。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class BaseReactActivity extends BaseActivity implements DefaultHardwareBackBtnHandler { * 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 */ private ReactInstanceManager mReactInstanceManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); * Get the reference to the ReactInstanceManager */ mReactInstanceManager = ((MyApplication) getActivity().getApplication()).getReactNativeHost().getReactInstanceManager(); } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } * Any activity that uses the ReactFragment or ReactActivty * Needs to call onHostPause() on the ReactInstanceManager */ @Override protected void onPause() { super.onPause(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostPause(); } } * Same as onPause - need to call onHostResume * on our ReactInstanceManager */ @Override protected void onResume() { super.onResume(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostResume(this, this); } } }
|
本文是 慌不要慌 原创,发表于 https://danke77.github.io/,请阅读原文支持原创 https://danke77.github.io/2016/11/23/react-native-inside-fragment/,版权归作者所有,转载请注明出处。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!