本方案适用于Android原生项目集成React Native框架。
问题描述
我们公司的APP部分模块使用了react native进行开发,使用react native开发确实很爽,一次编写到处运行,前端的开发体验,高效的开发效率,但是我们进入react native模块的时候,会有明显的白屏,时间大概是1-2s,这是很差的用户体验,我们今天的这篇文章就是为了解决这个痛点。
已有方案
我相信很多同学可能都看过react native中文网推荐的ReactNative安卓首屏白屏优化这篇文章,这篇文章方案很给力!作者采用了内存换时间的方案,缓存了ReactInstanceManager和ReactRootView对象,我们只需要在应用启动的时候初始化,之后进入react native模块都是调用缓存里的数据,所以速度非常快。
此方案存在的小问题
但是试过的同学可能知道这个方案有个小问题:第一次进入react native模块之后,再次进入react native模块,react native 页面的生命周期都不会执行(render, componentDidMount等),因为我们拿的都是已经缓存好的数据,假如我们在react native页面请求数据更新页面,只有第一次进入的时候是有效的。
改进方案
因为发现了这个问题,所以在github上面向作者提了issue,作者给了耐心解答,所以把改进方案分享给大家,省的大家走弯路。这篇文章还是原作者cnsnake11的智力成果,我只是做个分享以及简化了一点点代码。
我们这篇文章的重点是Android白屏优化,关于Android原生项目集成react native,请看我另一篇文章Android原生集成react native。
我们现在的方案就是只缓存ReactInstanceManager,每次进入ReactActivity的时候新建一个ReactRootView对象。具体代码如下:
public class RNCacheViewManager {
private static ReactInstanceManager mManager = null;
//init
public static void init(Context context) {
mManager = createReactInstanceManager();
ReactRootView mRootView = new ReactRootView(context);
mRootView.startReactApplication(mManager, "test", null);
}
public static ReactInstanceManager getReactInstanceManager() {
return mManager;
}
private static ReactInstanceManager createReactInstanceManager() {
return ReactInstanceManager.builder()
.setApplication(SHApplication.getInstance())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(true) //开发者支持,开发的时候要设置为true,不然无法使用开发者菜单
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
}
}
我们这个类主要负责初始化ReactInstanceManager对象,我们可以在APP启动的时候进行初始化(调用init函数),然后我们在自己的ReactActivity中进行调用。
public class ReactRootActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = RNCacheViewManager.getReactInstanceManager();
Bundle bundle = getIntent().getExtras();
mReactRootView.startReactApplication(mReactInstanceManager, "test", bundle);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy(this);
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
}
总结
这个问题耽误了我很长的时间,所以我想把我的心路历程分享给大家,这样大家遇到这个问题的时候就可以分分钟搞定,如果我有说的什么不清楚的地方,尽管提问。