React Native 안드로이드 첫 화면 화이트 화면 최적화

8745 단어
문제 설명
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);
  }

문제가 발생한 원인을 알게 되면 우리는 어떻게 최적화에 착수하는지 알게 된다.우리가 먼저 생각한 건: - 메모리 교환 시간.
1단계:
캐시 루트 view 관리자는 주로 캐시 루트 view 대상을 초기화하고 캐시하는 데 사용됩니다.
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();
    }
}

단계 2
ReactActivity를 다시 쓰면 복사해서 고칠 수도 있고 계승해서 쓸 수도 있습니다. 주로 onCreate와 onDestroy를 다시 쓰면 나머지 코드가 움직이지 않습니다.onCreate 방법에서 캐시 루트 view 관리자를 사용하여 루트 view 대상을 다시 만들지 않고 가져옵니다.
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이 초기화한 대상은 소각되고 다음에는 사용할 수 없습니다.루트 뷰의parent 대상을 마운트 해제해야 합니다. 그렇지 않으면 다음에 set Content View에서 오류가 발생합니다.
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();
        }
    }

단계 3
앱이 시작될 때 캐시 루트 뷰 관리자를 초기화합니다.
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()
        );
    }
}

좋은 웹페이지 즐겨찾기