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

總結

這個問題耽誤了我很長的時間,因此我想把個人心路歷程分享給你們,這樣你們遇到這個問題的時候就能夠分分鐘搞定,若是我有說的什麼不清楚的地方,儘管提問。函數

相關文章
相關標籤/搜索