React Native带你从源码解决启动白屏(Android)
前言:最近有点迷茫,学的东西太多,然后感觉有点力不从心,也不知道还能坚持多久这样写博客,不说了~~ 烦!! 撸一下代码平复下心情~
React Native中我们都知道,所有的view摆在一个activity中(原谅我只能用android为例子),然后原生android启动的时候,如果后台进程比较多,或者手机比较渣一点的话,多多少少都会看到一个短暂的白屏现象,然后当自己的activity切换到rnactivity的时候,由于要去加载bundler.js里面的内容,如果rn页面比较多的话,我们会看到一个很长的白屏现象,有童鞋要说了:“我们加一个进度条提示一下”,是的!! 你可以这样做,但你面对一群吊炸天的产品,你不得不去研究下该怎么做~~~
思路:
1、解决android启动白屏,通过设置rnactivity的主题;
2、解决react native启动白屏:
方案一:
提前把rootview创建出来,然后提前加载jsbundler文件(程序入口)
方案二:
提前把rootview创建出来,然后提前加载jsbundler文件,把rootview的现实设置成“隐藏”,在rn的第一个页面加载完后通知原生,原生拿到通知回调给rnactivity,然后显示出rootview。
方案一的做法大家可以参考中文网的这篇博客:
ReactNative安卓首屏白屏优化
说一下方案二,当我尝试了方案一的做法后,确实app加载到rnactivity的白屏问题有所缓解,但是问题来了,按照方案一的做法因为我的rootview创建是在Aactivity,的rootview的context是跟Aactivity绑定的,比如你需要在rn中用到modal组件(对话框),我们都知道modal在native渲染的时候会被当成dialog使用,但是我们的modal是放在rootview上面的,所以modal显示的时候,也就是跟Aactivity绑定的,而此时我们Aactivity已经被我们干掉了,所以就会报错!!! 不知道官网的这哥们是没遇到这问题咋样,反正方案一肯定是不行的,所以我们只能把rootview的创建放在rnactivity,有小伙伴有要问了,“那怎么做到预加载呢?”,好啦!! 接下来就直接上代码了~~
首先我们看到android里面react native加载耗时的操作:
我们的项目可能是这样的:
package com.scrolltabdemo;public class MainActivity extends ReactActivity { /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */ @Override protected String getMainComponentName() { return "ScrollTabDemo"; }}
可以发现就一个activity,然后我们走进ReactActivity:
/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */package com.facebook.react;import javax.annotation.Nullable;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.KeyEvent;import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;import com.facebook.react.modules.core.PermissionAwareActivity;import com.facebook.react.modules.core.PermissionListener;/** * Base Activity for React Native applications. */public abstract class ReactActivity extends Activity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { private final ReactActivityDelegate mDelegate; protected ReactActivity() { mDelegate = createReactActivityDelegate(); } /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. * e.g. "MoviesApp" */ protected @Nullable String getMainComponentName() { return null; } /** * Called at construction time, override if you have a custom delegate implementation. */ protected ReactActivityDelegate createReactActivityDelegate() { return new ReactActivityDelegate(this, getMainComponentName()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDelegate.onCreate(savedInstanceState); } @Override protected void onPause() { super.onPause(); mDelegate.onPause(); } @Override protected void onResume() { super.onResume(); mDelegate.onResume(); } @Override protected void onDestroy() { super.onDestroy(); mDelegate.onDestroy(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { mDelegate.onActivityResult(requestCode, resultCode, data); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mDelegate.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); } @Override public void onBackPressed() { if (!mDelegate.onBackPressed()) { super.onBackPressed(); } } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } @Override public void onNewIntent(Intent intent) { if (!mDelegate.onNewIntent(intent)) { super.onNewIntent(intent); } } @Override public void requestPermissions( String[] permissions, int requestCode, PermissionListener listener) { mDelegate.requestPermissions(permissions, requestCode, listener); } @Override public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults) { mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); } protected final ReactNativeHost getReactNativeHost() { return mDelegate.getReactNativeHost(); } protected final ReactInstanceManager getReactInstanceManager() { return mDelegate.getReactInstanceManager(); } protected final void loadApp(String appKey) { mDelegate.loadApp(appKey); }}
把所有的操作都放在了ReactActivityDelegate这个代理类中,继续往下走:
// Copyright 2004-present Facebook. All Rights Reserved.package com.facebook.react;import android.annotation.TargetApi;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.net.Uri;import android.os.Build;import android.os.Bundle;import android.provider.Settings;import android.support.v4.app.FragmentActivity;import android.view.KeyEvent;import android.widget.Toast;import com.facebook.common.logging.FLog;import com.facebook.infer.annotation.Assertions;import com.facebook.react.bridge.Callback;import com.facebook.react.common.ReactConstants;import com.facebook.react.devsupport.DoubleTapReloadRecognizer;import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;import com.facebook.react.modules.core.PermissionListener;import javax.annotation.Nullable;/** * Delegate class for {@link ReactActivity} and {@link ReactFragmentActivity}. You can subclass this * to provide custom implementations for e.g. {@link #getReactNativeHost()}, if your Application * class doesn't implement {@link ReactApplication}. */public class ReactActivityDelegate { private final int REQUEST_OVERLAY_PERMISSION_CODE = 1111; private static final String REDBOX_PERMISSION_GRANTED_MESSAGE = "Overlay permissions have been granted."; private static final String REDBOX_PERMISSION_MESSAGE = "Overlay permissions needs to be granted in order for react native apps to run in dev mode"; private final @Nullable Activity mActivity; private final @Nullable FragmentActivity mFragmentActivity; private final @Nullable String mMainComponentName; private @Nullable ReactRootView mReactRootView; private @Nullable DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; private @Nullable PermissionListener mPermissionListener; private @Nullable Callback mPermissionsCallback; public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) { mActivity = activity; mMainComponentName = mainComponentName; mFragmentActivity = null; } public ReactActivityDelegate( FragmentActivity fragmentActivity, @Nullable String mainComponentName) { mFragmentActivity = fragmentActivity; mMainComponentName = mainComponentName; mActivity = null; } protected @Nullable Bundle getLaunchOptions() { return null; } protected ReactRootView createRootView() { return new ReactRootView(getContext()); } /** * Get the {@link ReactNativeHost} used by this app. By default, assumes * {@link Activity#getApplication()} is an instance of {@link ReactApplication} and calls * {@link ReactApplication#getReactNativeHost()}. Override this method if your application class * does not implement {@code ReactApplication} or you simply have a different mechanism for * storing a {@code ReactNativeHost}, e.g. as a static field somewhere. */ protected ReactNativeHost getReactNativeHost() { return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost(); } public ReactInstanceManager getReactInstanceManager() { return getReactNativeHost().getReactInstanceManager(); } protected void onCreate(Bundle savedInstanceState) { 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(getContext())) { needsOverlayPermission = true; Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName())); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); ((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE); } } if (mMainComponentName != null && !needsOverlayPermission) { loadApp(mMainComponentName); } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } protected void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions()); getPlainActivity().setContentView(mReactRootView); } protected void onPause() { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onHostPause(getPlainActivity()); } } protected void onResume() { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onHostResume( getPlainActivity(), (DefaultHardwareBackBtnHandler) getPlainActivity()); } if (mPermissionsCallback != null) { mPermissionsCallback.invoke(); mPermissionsCallback = null; } } protected void onDestroy() { if (mReactRootView != null) { mReactRootView.unmountReactApplication(); mReactRootView = null; } if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onHostDestroy(getPlainActivity()); } } public void onActivityResult(int requestCode, int resultCode, Intent data) { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager() .onActivityResult(getPlainActivity(), 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(getContext())) { if (mMainComponentName != null) { loadApp(mMainComponentName); } Toast.makeText(getContext(), REDBOX_PERMISSION_GRANTED_MESSAGE, Toast.LENGTH_LONG).show(); } } } } public boolean onKeyUp(int keyCode, KeyEvent event) { if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) { if (keyCode == KeyEvent.KEYCODE_MENU) { getReactNativeHost().getReactInstanceManager().showDevOptionsDialog(); return true; } boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer) .didDoubleTapR(keyCode, getPlainActivity().getCurrentFocus()); if (didDoubleTapR) { getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS(); return true; } } return false; } public boolean onBackPressed() { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onBackPressed(); return true; } return false; } public boolean onNewIntent(Intent intent) { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager().onNewIntent(intent); return true; } return false; } @TargetApi(Build.VERSION_CODES.M) public void requestPermissions( String[] permissions, int requestCode, PermissionListener listener) { mPermissionListener = listener; getPlainActivity().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; } } }; } private Context getContext() { if (mActivity != null) { return mActivity; } return Assertions.assertNotNull(mFragmentActivity); } private Activity getPlainActivity() { return ((Activity) getContext()); }}
ReactActivityDelegate类中的东西比较多,我们就直接看到一个叫o nCreate的方法:
protected void onCreate(Bundle savedInstanceState) { 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(getContext())) { needsOverlayPermission = true; Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName())); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); ((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE); } } if (mMainComponentName != null && !needsOverlayPermission) { loadApp(mMainComponentName); } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); }
protected void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions()); getPlainActivity().setContentView(mReactRootView); }
可看到这么两行代码:
mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions());
这就是比较耗时的操作了,mReactRootView.startReactApplication干了很多不可描述的东西,有兴趣的童鞋可以看看我之前写过的一篇文章:
React-Native 热更新尝试(Android)
好啦! 看到真凶后,我们就正法一下它,哈哈!! 说笑了~ 既然这两个方法很耗时,那我就等这两个方法都执行完毕后我再去setContentView,然后rn加载完毕页面后,我再去显示rootview。
首先我们拖一份ReactActivity的源码,然后叫ReactActivity2:
/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */
package com.scrolltabdemo;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.KeyEvent;import android.view.View;import com.facebook.react.ReactInstanceManager;import com.facebook.react.ReactNativeHost;import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;import com.facebook.react.modules.core.PermissionAwareActivity;import com.facebook.react.modules.core.PermissionListener;import javax.annotation.Nullable;/** * Base Activity for React Native applications. */public abstract class ReactActivity2 extends Activity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity { private final ReactActivityDelegate mDelegate; protected ReactActivity2() { mDelegate = createReactActivityDelegate(); } /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. * e.g. "MoviesApp" */ protected @Nullable String getMainComponentName() { return null; } /** * Called at construction time, override if you have a custom delegate implementation. */ protected ReactActivityDelegate createReactActivityDelegate() { return new ReactActivityDelegate(this, getMainComponentName()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDelegate.onCreate(savedInstanceState); } @Override protected void onPause() { super.onPause(); mDelegate.onPause(); } @Override protected void onResume() { super.onResume(); mDelegate.onResume(); } @Override protected void onDestroy() { super.onDestroy(); mDelegate.onDestroy(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { mDelegate.onActivityResult(requestCode, resultCode, data); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mDelegate.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); } @Override public void onBackPressed() { if (!mDelegate.onBackPressed()) { super.onBackPressed(); } } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } @Override public void onNewIntent(Intent intent) { if (!mDelegate.onNewIntent(intent)) { super.onNewIntent(intent); } } @Override public void requestPermissions( String[] permissions, int requestCode, PermissionListener listener) { mDelegate.requestPermissions(permissions, requestCode, listener); } @Override public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults) { mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); } protected final ReactNativeHost getReactNativeHost() { return mDelegate.getReactNativeHost(); } protected final ReactInstanceManager getReactInstanceManager() { return mDelegate.getReactInstanceManager(); } protected final void loadApp(String appKey) { mDelegate.loadApp(appKey); } public View getRootView() { return mDelegate.getRootView(); }}
什么都不需要动,然后把里面的ReactActivityDelegate换成我们自己的ReactActivityDelegate,于是我们继续copy一份ReactActivityDelegate的代码:
import javax.annotation.Nullable;..... protected void onCreate(Bundle savedInstanceState) { 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(getContext())) { needsOverlayPermission = true; Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName())); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); ((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE); } } if (mMainComponentName != null && !needsOverlayPermission) { loadApp(mMainComponentName); } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } protected void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions());// getPlainActivity().setContentView(mReactRootView); } public View getRootView() { return mReactRootView; }}
我们也什么都没动,就是加了一个方法:
public View getRootView() { return mReactRootView; }
然后注释了一行代码:
// getPlainActivity().setContentView(mReactRootView);
然后把我们的MainActivity改一下,让它继承我们的ReactActivity2:
package com.scrolltabdemo;public class MainActivity extends ReactActivity2 { /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */ @Override protected String getMainComponentName() { return "ScrollTabDemo"; }}
然后我们在我们的MainActivity中,停留三秒再展示我们的rootview:
package com.scrolltabdemo;import android.os.Bundle;import android.os.Handler;import android.view.View;public class MainActivity extends ReactActivity2 { private View mRootView; @Override protected void onCreate(Bundle savedInstanceState) { //初始化rnrootview super.onCreate(savedInstanceState); //获取rnrootview mRootView = getRootView(); //模拟loadding图片 new Handler().postDelayed(new Runnable() { @Override public void run() { setContentView(mRootView); } },3000); } /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */ @Override protected String getMainComponentName() { return "ScrollTabDemo"; }}
我们运行我们的app:
可以看到,我们一进app是白页面,然后过了三秒显示了我们的rn页面,
我们把一进去白页面改成一张引导图片:
找到android的AndroidManifest.xml文件:
然后给MainAcitivty一个主题叫AppLaunchTheme:
<application android:name=".MainApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:label="@string/app_name" android:theme="@style/AppLaunchTheme" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> intent-filter> activity> <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> <activity android:name=".TestActivity"> activity> application>manifest>
然后我们在style.xml中创建主题:
<resources> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> -- Customize your theme here. --> style> <style name="AppLaunchTheme" parent="AppTheme"> <item name="windowNoTitle">trueitem> <item name="android:windowBackground">@mipmap/bg_launcher style>resources>
背景为一张图片:
name="android:windowBackground">@mipmap/bg_launcheritem>
然后再次运行app:
可以看到,打开app先显示一张引导图片,然后三秒后显示rn页面,
好啦!! 写到这里小伙伴疑问了,那我怎么保证三秒后rn页面加载出来了呢? 是的! 这就是我们接下来需要解决的问题,
也就是我们现在在MainAcitivity中是延时了三秒模拟inittoken等一系列的操作,然后直接显示我们的rn页面,也就是rootview,我们需要的是在rn页面没加载出来的时候一直显示引导页面,那怎么做呢?我们怎么知道rn页面已经加载完毕了呢??
我们直接在rn页面的第一个页面的componentDidMount方法中通知原生页面告诉它我已经加载完毕了:
demo的第一个页面叫ScrollTabDemo.js:
export default class ScrollTabDemo extends Component { componentDidMount() { NativeModules.Notification.showContentView(); } ..... }
可以看到我在rn页面中调了一个:
NativeModules.Notification.showContentView();
方法,搞过rn与native交互的童鞋都知道,这是调native的方法,我简单的说一下怎么实现Notification.showContentView():
首先创建一个module文件,我们这里叫NotificationModule.java:
class NotificationModule extends ReactContextBaseJavaModule { public NotificationModule(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { return "Notification"; } @ReactMethod public void showContentView() { getCurrentActivity().sendBroadcast(new Intent("com.demo.show")); } }
然后创建一个NotificationPackage文件把module加进来:
public class NotificationPackage implements ReactPackage { @Override public List createNativeModules(ReactApplicationContext reactContext) { List modules = new ArrayList<>(); modules.add(new NotificationModule(reactContext)); return modules; } @Override public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); }}
最后吧package文件注册进rn:
package com.scrolltabdemo;import android.app.Application;import com.facebook.react.ReactApplication;import com.facebook.react.ReactNativeHost;import com.facebook.react.ReactPackage;import com.facebook.react.shell.MainReactPackage;import com.facebook.soloader.SoLoader;import java.util.Arrays;import java.util.List;public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List getPackages() { return Arrays.asList( new MainReactPackage(), new CustomerViewPackage(), new NotificationPackage() ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); }}
好啦!! 可以看到,我们rn页面调了native的:
@ReactMethod public void showContentView() { getCurrentActivity().sendBroadcast(new Intent("com.demo.show")); }
native的showContentView方法发了一个广播‘com.demo.show“通知MainActivity,MainActivity收到广播后显示出rooview:
package com.scrolltabdemo;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.os.Handler;import android.view.View;import android.widget.Toast;public class MainActivity extends ReactActivity2 { private View mRootView; @Override protected void onCreate(Bundle savedInstanceState) { //初始化rnrootview super.onCreate(savedInstanceState); //获取rnrootview mRootView = getRootView(); //模拟loadding图片 new Handler().postDelayed(new Runnable() { @Override public void run() { mRootView.setVisibility(View.INVISIBLE); setContentView(mRootView); } },3000); registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mRootView.setVisibility(View.VISIBLE); Toast.makeText(MainActivity.this, "显示页面了", Toast.LENGTH_SHORT).show(); } }, new IntentFilter("com.demo.show")); } /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */ @Override protected String getMainComponentName() { return "ScrollTabDemo"; }}
再次运行代码:
好啦!! 我们的android app启动白屏,然后react-native启动白屏已经被我们彻底解决了。
我们这样做有什么弊端呢? 那就是只是针对当前rn的版本,如果rn版本android的源码实现方式不一样的话,我们可能改的文件也可能不一样了,关键是要弄清楚实现的思路~~~
好啦!! 如果小伙伴有什么疑问的话,可以联系我~~
欢迎入群,欢迎交流
qq技术交流群链接:
更多相关文章
- 安全新手入坑——HTML标签
- Nginx系列教程(四)| 一文带你读懂Nginx的动静分离
- Android之——任意时刻从子线程切换到主线程的实现(插曲)
- Android事件分发机制学习笔记
- [置顶] Android6.0权限系统
- android onPause()和onStop()区别
- Android(安卓)WebView内容宽度自适应
- 使用HTML来生产Android界面
- Android开发之Serializable 和 Parcelable的区别(源代码分享)