[置顶] Android布局加载React Native视图
2017-06-30 12:32
1141 查看
刚创建的React Native 微信公众号,欢迎微信扫描关注订阅号,每天定期会分享react
native 技术文章,移动技术干货,精彩文章技术推送。同时可以扫描我的微信加入react-native技术交流微信群。欢迎各位大牛,React
Native技术爱好者加入交流!
本篇博客围绕的依然是如何加载RN界面,在JsBundle加载优化这篇博客中,我们从源码角度分析了如何实现快速加载RN界面,RN界面的加载在ReactActivity的onCreate中完成,实则是通过ReactDelegate委托类的onCreate来实现。在ReactDelegate的onCreate方法中,系统调用loadApp来加载RN根视图,在loadApp方法中通过createRootView创建视图(new ReactRootView()),并启动设置到Activity的ContentView(DecoerView)上。
此时当我们加载出ReactRootView后,就可以将其添加到我们Activity或者Fragment布局。但是此时会发现一个问题,如果RN中视图控件有交互功能,例如单击事件,此时这些功能都失效了。百思不得姐后,查看源码会发现交互的功能都由ReactDelegate来实现,所以我们单纯加载ReactRootView只是显示了视图,但是交互是不行的。如何解决呢?
三、功能实现
上面我们分析了整个RN视图加载的流程,那么如何在现有Activity布局中加载RN界面呢?原理依然要从创建设置ReactRootView来解决。RN的新版本对设置创建ReactRootView进行了封装,使得我们只需要重写getMainComponentName方法返回RN注册名称即可。这就使得我们不能直接控制ReactRootView的创建和设置。所以依然要采用重写ReactDelegate的方式来解决。
核心依然是修改了onCreate中方法,我们在设置根布局时,不是直接设置ReactRootView,而是加载我们自己的Activity布局,然后将RN布局作为子布局添加到Activity布局,这样就可以实现在现有Activity布局中嵌入RN布局了。
三、效果图
点击查看源码
native 技术文章,移动技术干货,精彩文章技术推送。同时可以扫描我的微信加入react-native技术交流微信群。欢迎各位大牛,React
Native技术爱好者加入交流!
一、需求分析
前几篇博客中,和大家分享了关于React Native For Android 的一系列内容,以及React Native第三方库的使用技巧。今天和大家分享的内容可以算是React Native基于最新版本实现JsBundle预加载,界面秒开优化功能延伸。本篇博客围绕的依然是如何加载RN界面,在JsBundle加载优化这篇博客中,我们从源码角度分析了如何实现快速加载RN界面,RN界面的加载在ReactActivity的onCreate中完成,实则是通过ReactDelegate委托类的onCreate来实现。在ReactDelegate的onCreate方法中,系统调用loadApp来加载RN根视图,在loadApp方法中通过createRootView创建视图(new ReactRootView()),并启动设置到Activity的ContentView(DecoerView)上。
二、视图加载
在React Native基于最新版本实现JsBundle预加载,界面秒开优化博客中,我们介绍到了如何去预先加载ReactRootView。ReactRootView rootView = new ReactRootView(activity); rootView.startReactApplication( ((ReactApplication) activity.getApplication()).getReactNativeHost().getReactInstanceManager(), componentName, null);
此时当我们加载出ReactRootView后,就可以将其添加到我们Activity或者Fragment布局。但是此时会发现一个问题,如果RN中视图控件有交互功能,例如单击事件,此时这些功能都失效了。百思不得姐后,查看源码会发现交互的功能都由ReactDelegate来实现,所以我们单纯加载ReactRootView只是显示了视图,但是交互是不行的。如何解决呢?
三、功能实现
上面我们分析了整个RN视图加载的流程,那么如何在现有Activity布局中加载RN界面呢?原理依然要从创建设置ReactRootView来解决。RN的新版本对设置创建ReactRootView进行了封装,使得我们只需要重写getMainComponentName方法返回RN注册名称即可。这就使得我们不能直接控制ReactRootView的创建和设置。所以依然要采用重写ReactDelegate的方式来解决。public class MyReactDelegate { private final Activity mActivity; private ReactRootView mReactRootView; private Callback mPermissionsCallback; private final String mMainComponentName; private PermissionListener mPermissionListener; private final int REQUEST_OVERLAY_PERMISSION_CODE = 1111; private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; public PreLoadReactDelegate(Activity activity, @Nullable String mainComponentName) { this.mActivity = activity; this.mMainComponentName = mainComponentName; } public void onCreate() { 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(mActivity)) { needsOverlayPermission = true; Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + mActivity.getPackageName())); mActivity.startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE); } } if (mMainComponentName != null && !needsOverlayPermission) { mReactRootView = new ReactRootView(mActivity); mReactRootView.startReactApplication( getReactInstanceManager(), mMainComponentName, null); } // 3.将RootView设置到Activity布局 mActivity.setContentView(R.layout.acty_rn); ((FrameLayout)mActivity.findViewById(R.id.rn_contaner)).addView(mReactRootView); } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } public void onResume() { if (getReactNativeHost().hasInstance()) { getReactInstanceManager().onHostResume(mActivity, (DefaultHardwareBackBtnHandler)mActivity); } if (mPermissionsCallback != null) { mPermissionsCallback.invoke(); mPermissionsCallback = null; } } public void onPause() { if (getReactNativeHost().hasInstance()) { getReactInstanceManager().onHostPause(mActivity); } } public void onDestroy() { if (mReactRootView != null) { mReactRootView.unmountReactApplication(); mReactRootView = null; } if (getReactNativeHost().hasInstance()) { getReactInstanceManager().onHostDestroy(mActivity); } } public boolean onNewIntent(Intent intent) { if (getReactNativeHost().hasInstance()) { getReactInstanceManager().onNewIntent(intent); return true; } return false; } public void onActivityResult(int requestCode, int resultCode, Intent data) { if (getReactNativeHost().hasInstance()) { getReactInstanceManager().onActivityResult(mActivity, requestCode, resultCode, data); } else { // Did we request overlay permissions? if (requestCode == REQUEST_OVERLAY_PERMISSION_CODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOverlays(mActivity)) { if (mMainComponentName != null) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = new ReactRootView(mActivity); mReactRootView.startReactApplication( getReactInstanceManager(), mMainComponentName, null); mActivity.setContentView(mReactRootView); } } } } } public boolean onBackPressed() { if (getReactNativeHost().hasInstance()) { getReactInstanceManager().onBackPressed(); return true; } return false; } public boolean onRNKeyUp(int keyCode) { if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) { if (keyCode == KeyEvent.KEYCODE_MENU) { getReactInstanceManager().showDevOptionsDialog(); return true; } boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer) .didDoubleTapR(keyCode, mActivity.getCurrentFocus()); if (didDoubleTapR) { getReactInstanceManager().getDevSupportManager().handleReloadJS(); return true; } } return false; } public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) { mPermissionListener = listener; mActivity.requestPermissions(permissions, requestCode); } public void onRequestPermissionsResult(final int requestCode, final String[] permissions, final int[] grantResults) { mPermissionsCallback = new Callback() { @Override public void invoke(Object... args) { if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { mPermissionListener = null; } } }; } /** * 获取 Application中 ReactNativeHost * @return */ private ReactNativeHost getReactNativeHost() { return MainApplication.getInstance().getReactNativeHost(); } /** * 获取 ReactInstanceManager * @return */ private ReactInstanceManager getReactInstanceManager() { return getReactNativeHost().getReactInstanceManager(); } }
核心依然是修改了onCreate中方法,我们在设置根布局时,不是直接设置ReactRootView,而是加载我们自己的Activity布局,然后将RN布局作为子布局添加到Activity布局,这样就可以实现在现有Activity布局中嵌入RN布局了。
三、效果图
点击查看源码
相关文章推荐
- React-Native系列Android——SoLoader加载动态链接库
- React Native 小实例 采用View布局如下视图
- ReactNative Android 实现加载本地图片
- [置顶] Android Fragment中加载,嵌套Unity视图
- ReactNative基础(八)了解FlatList的使用、添加头尾布局、下拉刷新、上拉加载
- [android] React Native reload 重加载 失效解决方案【RN 0.29 or RN 0.32版本】
- Android recyclerView网格布局上拉加载更多视图的设计
- [置顶] 【Android】AndroidStudio开发工具布局xml文件不显示视图。提示:The following classes could not be instantiated:
- Android React Native加载图片资源的正确姿势
- [置顶] android源码分析——由SetContentView串起来的布局加载机制
- React Native之ViewPagerAndroid仿淘宝首页顶部分类布局效果实现
- 好用的ReactNative下拉刷新上拉加载的组件,支持iOS和Android
- React-native 热更新(1) 脚本与图片更新+图片加载源码分析 android部分
- React Native一款Android端的开源图片加载控件
- Android React Native加载图片资源的正确姿势
- [置顶] React-Native开发之原生模块封装(Android)升级版
- React-Native系列Android——Javascript文件加载过程分析
- React Native之ViewPagerAndroid仿淘宝首页顶部分类布局效果实现
- [置顶] React-Native修改应用名称(Android)
- Android最佳实践性能(三)提高性能布局(按需加载视图)