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/,版权归作者所有,转载请注明出处。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!