React Native Android白屏优化终极方案

本方案适用于Android原生项目集成React Native框架。前端

问题描述

咱们公司的APP部分模块使用了react native进行开发,使用react native开发确实很爽,一次编写处处运行,前端的开发体验,高效的开发效率,可是咱们进入react native模块的时候,会有明显的白屏,时间大概是1-2s,这是不好的用户体验,咱们今天的这篇文章就是为了解决这个痛点。react

已有方案

我相信不少同窗可能都看过react native中文网推荐的ReactNative安卓首屏白屏优化这篇文章,这篇文章方案很给力!做者采用了内存换时间的方案,缓存了ReactInstanceManager和ReactRootView对象,咱们只须要在应用启动的时候初始化,以后进入react native模块都是调用缓存里的数据,因此速度很是快。android

此方案存在的小问题

可是试过的同窗可能知道这个方案有个小问题:第一次进入react native模块以后,再次进入react native模块,react native 页面的生命周期都不会执行(render, componentDidMount等),由于咱们拿的都是已经缓存好的数据,假如咱们在react native页面请求数据更新页面,只有第一次进入的时候是有效的。git

改进方案

由于发现了这个问题,因此在github上面向做者提了issue,做者给了耐心解答,因此把改进方案分享给你们,省的你们走弯路。这篇文章仍是原做者cnsnake11的智力成果,我只是作个分享以及简化了一点点代码。github

咱们这篇文章的重点是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中进行调用。ide

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);
    }
}

总结

这个问题耽误了我很长的时间,因此我想把个人心路历程分享给你们,这样你们遇到这个问题的时候就能够分分钟搞定,若是我有说的什么不清楚的地方,尽管提问。函数

相关文章
相关标签/搜索