问题描述

在android中,当点击某个rn模块的入口按钮,弹出rn的activity到rn的页面展现出来的过程中,会有很明显的白屏现象,不同的机型不同(cpu好的白屏时间短),大概1s到2s的时间。

注意,只有在真机上才会有此现象,在模拟器上没有此现象完全是秒开。

优化分析

通过工具分析,问题主要在下面的代码上,
ReactRootView mReactRootView = createRootView();
mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());

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

知道了产生问题的原因,我们就知道怎么着手优化了。我们首先想到的:-内存换时间

步骤一:

缓存rootview管理器主要用于初始化和缓存rootview对象。

import android.app.Activity;
import android.os.Bundle;
import android.view.ViewParent;

import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactRootView;

import java.lang.reflect.Field;

/**
 * 缓存view管理
 */
public class RNCacheViewManager {

    private static ReactRootView mRootView = null;
    private static ReactInstanceManager mManager = null;
    private static AbsRnInfo mRnInfo = null;

    //初始化
    public static void init(Activity act, AbsRnInfo rnInfo) {
        init(act, rnInfo, null);
    }

    public static void init(Activity act, AbsRnInfo rnInfo, Bundle launchOptions) {
        if (mManager == null) {
            updateCache(act, rnInfo, launchOptions);
        }
    }

    public static void updateCache(Activity act, AbsRnInfo rnInfo) {
        updateCache(act, rnInfo, null);
    }

    //更新cache,适合于版本升级时候更新cache
    public static void updateCache(Activity act, AbsRnInfo rnInfo, Bundle launchOptions) {
        mRnInfo = rnInfo;
        mManager = createReactInstanceManager(act);
        mRootView = new ReactRootView(act);
        mRootView.startReactApplication(mManager, rnInfo.getMainComponentName(), launchOptions);
    }

//设置模块名称,因为是private,只能通过反射赋值
    public static void setModuleName(String moduleName) {
        try {
            Field field = ReactRootView.class.getDeclaredField("mJSModuleName");
            field.setAccessible(true);
            field.set(getReactRootView(), moduleName);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

//设置启动参数,因为是private,只能通过反射赋值
    public static void setLaunchOptions(Bundle launchOptions) {
        try {
            Field field = ReactRootView.class.getDeclaredField("mLaunchOptions");
            field.setAccessible(true);
            field.set(getReactRootView(), launchOptions);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static ReactRootView getReactRootView() {
        if(mRootView==null){
            throw new RuntimeException("缓存view管理器尚未初始化!");
        }
        return mRootView;
    }

    public static ReactInstanceManager getReactInstanceManager() {
        if(mManager==null){
            throw new RuntimeException("缓存view管理器尚未初始化!");
        }
        return mManager;
    }

    public static AbsRnInfo getRnInfo() {
        if(mRnInfo==null){
            throw  new RuntimeException("缓存view管理器尚未初始化!");
        }
        return mRnInfo;
    }

    public static void onDestroy() {
        try {
            ViewParent parent = getReactRootView().getParent();
            if (parent != null)
                ((android.view.ViewGroup) parent).removeView(getReactRootView());
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public static void clear() {
        try {
            if (mManager != null) {
                mManager.onDestroy();
                mManager = null;
            }
            if (mRootView != null) {
                onDestroy();
                mRootView = null;
            }
            mRnInfo = null;
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private static ReactInstanceManager createReactInstanceManager(Activity act) {

        ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
                .setApplication(act.getApplication())
                .setJSMainModuleName(getRnInfo().getJSMainModuleName())
                .setUseDeveloperSupport(getRnInfo().getUseDeveloperSupport())
                .setInitialLifecycleState(LifecycleState.BEFORE_RESUME);

        for (ReactPackage reactPackage : getRnInfo().getPackages()) {
            builder.addPackage(reactPackage);
        }

        String jsBundleFile = getRnInfo().getJSBundleFile();

        if (jsBundleFile != null) {
            builder.setJSBundleFile(jsBundleFile);
        } else {
            builder.setBundleAssetName(getRnInfo().getBundleAssetName());
        }
        return builder.build();
    }
}

步骤二

重写ReactActivity,可以拷贝出来改,也可以继承写,主要是重写onCreate和onDestroy,其余代码不动。onCreate方法中使用缓存rootview管理器来获得rootview对象,而不是重新创建。

onCreate()代码

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

        if (RNCacheViewManager.getRnInfo().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 = RNCacheViewManager.getReactInstanceManager();
        ReactRootView mReactRootView = RNCacheViewManager.getReactRootView();
        setContentView(mReactRootView);
    }

onDestroy方法中,不能再调用原有的mReactInstanceManager.destroy()方法了,否则rn初始化出来的对象会被销毁,下次就用不了了。同时,要卸载掉rootview的parent对象,否则下次再setContentView时候回报错。

protected void onDestroy() {
        RNCacheViewManager.onDestroy();
        super.onDestroy();
    }
RNCacheViewManager的onDeatory代码
public static void onDestroy() {
        try {
            ViewParent parent = getReactRootView().getParent();
            if (parent != null)
                ((android.view.ViewGroup) parent).removeView(getReactRootView());
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

步骤三

在app启动时候初始化缓存rootview管理器。
RNCacheViewManager.init((Activity) context, new RnInfo(moduleName, launchOptions));

RnInfo实体类代码:

public class RnInfo extends AbsRnInfo {

    private String mModuleName;
    private Bundle mLaunchOptions;

    public RnInfo(String moduleName) {
        this.mModuleName = moduleName;
    }

    public RnInfo(String moduleName, Bundle launchOptions) {
        this.mModuleName = moduleName;
        this.mLaunchOptions = launchOptions;
    }

    @Nullable
    @Override
    public Bundle getLaunchOptions() {
        return mLaunchOptions;
    }

    @Override
    public String getMainComponentName() {
        return mModuleName;
    }

    @Override
    public String getJSMainModuleName() {
        return RNKeys.Default.DEf_JS_MAIN_MODULE_NAME;
    }

    @Nullable
    @Override
    public String getJSBundleFile() {
        return RNManager.getJsBundlePath();
    }

    @Override
    public boolean getUseDeveloperSupport() {
        return true;
    }

    @Override
    public List<ReactPackage> getPackages() {
        return Arrays.asList(
                new MainReactPackage(),
                new BBReactPackage()
        );
    }
}


关于React Native 安卓首屏白屏优化的更多相关文章

  1. React Native 首次加载白屏优化

    RN首次加载都会有个白屏过程,一般都会有500ms+的白屏时间,原生页面开发同样的页面会能够快速显示而在RN页面中有个明显的等待过程,这个会影响用户体验. 1.使用过渡页面 简单处理可以在白屏过程中加 ...

  2. react native 完美解决启动白屏

    先讲下我的RN版本0.58.5 首先安装react-native-splash-screen(目前使用的版本是3.2.0) 项目地址https://github.com/crazycodeboy/re ...

  3. Android 启动APP时黑屏白屏的三个解决方案

    你会很奇怪,为什么有些app启动时,会出现一会儿的黑屏或者白屏才进入Activity的界面显示,但是有些app却不会如QQ手机端,的确这里要做处理一下.这里先了解一下为什么会出现这样的现象,其实很简单 ...

  4. Android 启动APP时黑屏白屏的三个解决方案(转载)

    你会很奇怪,为什么有些app启动时,会出现一会儿的黑屏或者白屏才进入Activity的界面显示,但是有些app却不会如QQ手机端,的确这里要做处理一下.这里先了解一下为什么会出现这样的现象,其实很简单 ...

  5. react history模式下的白屏问题

    近期,再用react的时候,由于不想用丑陋的hash,便将路由模式切换成history了,结果带来了一些问题,比如刷新白屏,还有图片加载不出来,这里我们说一下解决方案. 原因 首先,我们说一下造成这一 ...

  6. Android -- 距离感应器控制屏幕灭屏白屏

    权限                                                                                             <u ...

  7. Android 启动APP时黑屏白屏的解决方案

    在开发中,我们在启动app的时候,屏幕会出现一段时间的白屏或者黑屏,不同设备时间长短不同.很影响用户体验. 首先分析一下,产生这个现象的原因,当我们在启动一个应用时,系统会去检查是否已经存在这样一个进 ...

  8. 配置React Native 安卓开发环境

    配置主要分为以下几步: 安装node.js 安装AndroidStudio 安装React Native命令行工具 搭建React Native版本的Hello World,修改代码查看效果 第一步 ...

  9. React Native 安卓 程序运行报错: React Native version mismatch(转载)

    这个问题已经得到解决,参照stackoverflow上的问题:https://stackoverflow.com/que...这个问题的原因就处在Android工程中app/build.gradle中 ...

随机推荐

  1. 【模板】KMP字符串匹配

    题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. (如果你不知道这是什么意思也不要问,去百度 ...

  2. 洛谷mNOIP模拟赛Day1-分组

    传送门 首先是贪心的思路 从后向前选,能多选就多选, 理由:数字越少肯定越优,同时间隔尽量向前推,字典序尽量小 对于K==1,枚举1~512直接判断 对于K==2,需要用镜像并查集,来刻画" ...

  3. hdu 4352 数位dp + 状态压缩

    XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  4. 【BZOJ3685】【zkw权值线段树】普通van Emde Boas树

    原题传送门 因为马上要开始搞树套树了,所以学了一波权值线段树...毕竟是会点zkw线段树的,所以zkw线段树大法好! 解题思路: 介绍一下权值线段树吧,其实感觉就是线段树的本义,就是你用线段树维护了数 ...

  5. ●BZOJ 2149 拆迁队

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2149 题解: 斜率优化DP,栈维护凸包,LIS,分治(我也不晓得是不是CDQ分治...) 一 ...

  6. hihiocoder 1255(搜索)(2015ACM/ICPC北京站)

    题意: 给你四个矩形,判断能否从中选出3个组成一个矩形 思路: 1.搜索,如果两个能组成一个新的,则将他们合并,继续搜索 2.暴力判断 最开始没注意到3,一直以为要用4个,WR #include &l ...

  7. bzoj4596[Shoi2016]黑暗前的幻想乡 Matrix定理+容斥原理

    4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 464  Solved: 264[Submit][Sta ...

  8. Linux 基本概念和操作

    我们在使用Linux时,不是直接和系统打交道,而是通过shell的中间程序.在图形界面下为了实现窗口的输入和输出,linux系统为我们提供了终端模拟器Terminal,常见的终端模拟器有 gnome- ...

  9. Python类的定义

    Python笔记--类定义 一.类定义: class <类名>: <语句> 类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性 如果直接使用类名修改其属 ...

  10. P2P技术详解(三):P2P技术之STUN、TURN、ICE详解

    1.内容概述 在现实Internet网络环境中,大多数计算机主机都位于防火墙或NAT之后,只有少部分主机能够直接接入Internet.很多时候,我们希望网络中的两台主机能够直接进行通信,即所谓的P2P ...