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

来源:互联网 发布:centos 安装php 编辑:程序博客网 时间:2024/05/02 01:09

问题描述

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




1 0
原创粉丝点击