ReactNative安卓首屏白屏优化

前言

公司现有app中部分模块使用reactnative开发,之前使用的都是webview来加载H5页面,在实施的过程中,reactnative良好的兼容性,极佳的加载、动画性能,提升了我们的开发、测试效率,提升了用户体验。

但是,在android中,当点击某个rn模块的入口按钮,弹出rn的activity到rn的页面展现出来的过程中,会有很明显的白屏现象,不同的机型不同(cpu好的白屏时间短),大概1s到2s的时间。这是因为每次加载reactAcivity都是会去重新加载js资源包,初始化,导致加载时间过长。

分析问题

一般优化速度问题,首先就是要找到时间分布,然后根据二八原则,先优化耗时最长的部分。android集成rn都会继承官方提供的ReactActivity。

public class MainActivity extends ReactActivity {

然后只在自己的activity中覆盖一些配置项。

在官方的ReactActivity中的onCreate方法中

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
      // Get permission to show redbox in dev builds.
      if (!Settings.canDrawOverlays(this)) {
        Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
        startActivity(serviceIntent);
        FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
        Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
      }
    }

    mReactInstanceManager = createReactInstanceManager();
    ReactRootView mReactRootView = createRootView();
    mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());
    setContentView(mReactRootView);
  }

最慢的就是这三行代码,占了90%以上的时间。

mReactInstanceManager = createReactInstanceManager();
    ReactRootView mReactRootView = createRootView();
    mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());

第一行是创建React管理的实例 把jsbundle文件读入到内存中。

第二行是创建React页面。

第三行是初始化React页面。

解决方案

优化思路:内存换取时间, 在app启动时候,就将mReactRootView初始化出来,并缓存起来,在用的时候直接setContentView(mReactRootView),达到秒开,但是由于每次页面都是继承ReactActivity,页面不同,每次都要重新初始化新的页面,我们把ReactInstanceManager写成单例的模式,创建一次,加载jsbundle文件缓存在内存中,不需要每次都去加载资源,减少加载时间。
创建RNCacheManager:
package com.haier.hairy.react;

import android.app.Activity;

import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.framework.util.Preferences;
import com.microsoft.codepush.react.CodePush;

import java.util.Arrays;

/**
 * React管理缓存类
 * Created by fww
 * date 16/6/20.
 */
public class RNCacheManager {
    private static ReactInstanceManager mManager = null;
    private static RNCacheManager mInstance;
    private static CodePush codePush;


    public static RNCacheManager getInstance(Activity activity){
        if(mInstance==null){
            mInstance = new RNCacheManager();
            codePush = new CodePush(Preferences.DEBUG?/*"1RMMWRaTi1WhB8z1CEjH3B5aRztnEJTjrzq6l"*/"iTJagF-2Ox8EJAp6kfQ5JO7hHoM8EJTjrzq6l":"GYGm87k_sh4ObCJwrI5qNH-i_9f9EJTjrzq6l", activity, Preferences.DEBUG);
            mManager = createReactInstanceManager(activity);
        }

        return mInstance;
    }
    public ReactInstanceManager getManager(Activity activity){
        if(mManager==null){
            mManager = createReactInstanceManager(activity);
        }

        return mManager;
    }
    private static ReactInstanceManager createReactInstanceManager(Activity act) {

        ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
                .setApplication(act.getApplication())
                .setJSMainModuleName("")
                .setUseDeveloperSupport(Preferences.DEBUG)
                .setInitialLifecycleState(LifecycleState.BEFORE_RESUME);

        for (ReactPackage reactPackage : Arrays.<ReactPackage>asList(
                new MainReactPackage(),
                new SpringBoardPackage(),
                codePush.getReactPackage()
        )) {
            builder.addPackage(reactPackage);
        }

        String jsBundleFile = codePush.getBundleUrl("main.jsbundle");;

        if (jsBundleFile != null) {
            builder.setJSBundleFile(jsBundleFile);
        } else {
            builder.setBundleAssetName("main.jsbundle");
        }
        return builder.build();
    }
}
重写ReactActivity:

将官方的ReactActivity粘出来,重写2个方法,onCreate和onDestroy,其余代码不动。

onCreate方法中使用缓存ReactInstanceManager管理器来获得ReactInstanceManager对象,而不是重新创建。

这里曾尝试继承ReactActivity,而不是重写这个类,但是子类覆盖onCreate方法时候,必须要调用super.onCreate,否则编译会报错,但是super.onCreate方法会重新创建rootview,所以实在是绕不过去了。

这里的CodePush是微软的CodePush包,用于更新资源包的,可以不加注释掉,感兴趣的同学可以了解下。

  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
            // Get permission to show redbox in dev builds.
            if (!Settings.canDrawOverlays(this)) {
                Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                startActivity(serviceIntent);
                FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
                Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
            }
        }
        RNCacheManager rnCacheManager = RNCacheManager.getInstance(this);
        mReactInstanceManager = rnCacheManager.getManager(this);
        ReactRootView mReactRootView = createRootView();
        mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());
        setContentView(mReactRootView);
    }

onDestroy方法中,不能再调用原有的mReactInstanceManager.destroy()方法了,否则rn初始化出来的对象会被销毁,下次就用不了了。可以把它注释掉,试了不会报错,最好的办法就是做个标记,最好一个的时候destroy()。

      protected void onDestroy() {
            super.onDestroy();
    
            if (mReactInstanceManager != null) {
    //            mReactInstanceManager.onDestroy();
            }
        }

亲测,第一次加载时间长点,以后的加载使用 缓存都是秒开的。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值