您的位置:首页 > Web前端 > React

[置顶] Android布局加载React Native视图

2017-06-30 12:32 1141 查看
刚创建的React Native 微信公众号,欢迎微信扫描关注订阅号,每天定期会分享react
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布局了。

三、效果图



点击查看源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: