关于React Native 安卓首屏白屏优化

简介: 问题描述在android中,当点击某个rn模块的入口按钮,弹出rn的activity到rn的页面展现出来的过程中,会有很明显的白屏现象,不同的机型不同(cpu好的白屏时间短),大概1s到2s的时间。注意,只有在真机上才会有此现象,在模拟器上没有此现象完全是秒开。优化分析通过工具分析,问题主要在下面的代码上,ReactRootView mReactRootView = createR

问题描述

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




目录
相关文章
|
2月前
|
存储 缓存 JavaScript
如何优化React或Vue应用的性能
需要注意的是,性能优化是一个持续的过程,需要根据具体的应用场景和性能问题进行针对性的优化。同时,不同的项目和团队可能有不同的优化重点和方法,要结合实际情况灵活运用这些优化策略,以达到最佳的性能效果。
113 51
|
24天前
|
前端开发 UED 开发者
React 选项卡组件 Tabs:从基础到优化
本文详细介绍了如何在React中构建一个功能丰富的选项卡组件,包括基础实现、样式美化、常见问题及解决方法。通过逐步讲解,从简单的选项卡组件结构开始,逐步引入样式、性能优化、动态内容加载、键盘导航支持和动画效果,最后讨论了自定义样式的实现。旨在帮助开发者在React项目中高效构建高质量的选项卡组件。
62 18
|
29天前
|
前端开发 UED
React 文本区域组件 Textarea:深入解析与优化
本文介绍了 React 中 Textarea 组件的基础用法、常见问题及优化方法,包括状态绑定、初始值设置、样式自定义、性能优化和跨浏览器兼容性处理,并提供了代码案例。
55 8
|
2月前
|
前端开发 JavaScript API
探究 React Hooks:如何利用全新 API 优化组件逻辑复用与状态管理
本文深入探讨React Hooks的使用方法,通过全新API优化组件逻辑复用和状态管理,提升开发效率和代码可维护性。
|
4月前
|
定位技术 Android开发 iOS开发
引入百度地图,安卓出现白屏问题
引入百度地图,安卓出现白屏问题
194 57
|
4月前
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
78 20
Android经典面试题之图片Bitmap怎么做优化
|
3月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
72 4
|
3月前
|
前端开发 JavaScript 算法
React 渲染优化策略
【10月更文挑战第6天】React 是一个高效的 JavaScript 库,用于构建用户界面。本文从基础概念出发,深入探讨了 React 渲染优化的常见问题及解决方法,包括不必要的渲染、大量子组件的渲染、高频事件处理和大量列表渲染等问题,并提供了代码示例,帮助开发者提升应用性能。
62 6
|
2月前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。
|
3月前
|
JSON 前端开发 JavaScript
【简单粗暴】如何使用 React 优化 AG 网格性能
【简单粗暴】如何使用 React 优化 AG 网格性能
37 3