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