专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
开发者全社区  ·  情人节的时间管理大师,凉了 ·  23 小时前  
开发者全社区  ·  交易媛载歌载舞 ·  昨天  
开发者全社区  ·  果然,DeepSex来了 ·  昨天  
开发者全社区  ·  月薪八万的中金员工被祭旗了 ·  2 天前  
开发者全社区  ·  大S的5亿遗产如何分配? ·  2 天前  
51好读  ›  专栏  ›  安卓开发精选

React Native 0.31 Bundle 预加载优化

安卓开发精选  · 公众号  · android  · 2016-08-30 08:13

正文

(点击 上方公众号 ,可快速关注)


来源:伯乐在线专栏作者 - markzhai

链接:http://android.jobbole.com/84313/

点击 → 了解如何加入专栏作者


使用 React Native 开发混合应用的过程中,我们在打完 bundle 进 release 包后,会发现第一次进入页面(React 的 Activity)会有一个短暂的白屏过程(在真机上近 1秒 ,在模拟器上比较快,在 200毫秒 左右),而且在完全退出后再进入,仍然会有这个白屏。


仔细查看加载过程(其实猜猜都能知道)后可以发现,这个过程就是在加载我们的 js bundle,通常即便是一个小的 RN 应用(混合应用中的子业务),也会动辄到 1MB 的大小,除非是完整的 RN 应用,可以把这个当做是启动速度,否则这样的加载速度都是对用户体验的很大伤害。


于是我们决定进行 Bundle 预加载的优化。


项目源码上传在:markzhai/react-native-preloader,稍后会上传到 maven,版本号会和 rn 保持一致。

https://github.com/markzhai/react-native-preloader


耗时操作


见 ReactActivity 的 onCreate 方法:


@Override

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

}

}

mReactRootView = createRootView ();

mReactRootView . startReactApplication (

getReactNativeHost (). getReactInstanceManager (),

getMainComponentName (),

getLaunchOptions ());

setContentView ( mReactRootView );

mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer ();

}


打点后可以发现耗时的其实是


  • createRootView();

  • startReactApplication();


这两个操作,所以考虑只需要提前创建 ReactRootView 进行 render,之后直接挂载该 view 上去即可。


预加载


创建预加载类 ReactPreLoader:


/**

* React Native Bundle Pre-loader.

*

* @author markzhai on 16/8/20

* @version 1.3.0

*/

public class ReactPreLoader {

private static final String TAG = "ReactPreLoader" ;

private static final Map String , ReactRootView > CACHE_VIEW_MAP =

new ArrayMap ();

/**

* Get { @link ReactRootView} with corresponding { @link ReactInfo}.

*/

public static ReactRootView getRootView ( ReactInfo reactInfo ) {

return CACHE_VIEW_MAP . get ( reactInfo . getMainComponentName ());

}

/**

* Pre-load { @link ReactRootView} to local { @link Map}, you may want to

* load it in previous activity.

*/

public static void init ( Activity activity , ReactInfo reactInfo ) {

if ( CACHE_VIEW_MAP . get ( reactInfo . getMainComponentName ()) != null ) {

return ;

}

ReactRootView rootView = new ReactRootView ( activity );

rootView . startReactApplication (

(( ReactApplication ) activity . getApplication ()). getReactNativeHost (). getReactInstanceManager (),

reactInfo . getMainComponentName (),

reactInfo . getLaunchOptions ());

CACHE_VIEW_MAP . put ( reactInfo . getMainComponentName (), rootView );

}

/**

* Remove { @link ReactRootView} from parent.

*/

public static void onDestroy ( ReactInfo reactInfo ) {

try {

ReactRootView rootView = getRootView ( reactInfo );

ViewGroup parent = ( ViewGroup ) rootView . getParent ();

if ( parent != null ) {

parent . removeView ( rootView );

}

} catch ( Throwable e ) {

Logger . e ( TAG , e );

}

}

}


在 init 操作中,我们通过 ReactInfo 缓存把 view 缓存在本地的 ArrayMap。


值得注意的是 onDestroy,在 ReactActivity 销毁后,我们需要把 view 从 parent 上卸载下来。


使用预加载的 view


使用预加载的 View,就需要侵入 activity 的创建过程,我们无法再使用 RN 库提供的 ReactActivity,只能建立自己的,以下列出修改的方法,其他方法照抄 ReactActivity:


/**

* Base Activity for React Native applications.

*

* @author markzhai on 16/7/28

* @version 1.3.0

*/

public abstract class MrReactActivity extends Activity

implements DefaultHardwareBackBtnHandler , PermissionAwareActivity {

@Override

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

}

}

mReactRootView = ReactPreLoader . getRootView ( getReactInfo ());

if ( mReactRootView != null ) {

Logger . i ( TAG , "use pre-load view" );

} else {

Logger . i ( TAG , "createRootView" );

mReactRootView = createRootView ();

if ( mReactRootView != null ) {

mReactRootView . startReactApplication (

getReactNativeHost (). getReactInstanceManager (),







请到「今天看啥」查看全文


推荐文章
开发者全社区  ·  情人节的时间管理大师,凉了
23 小时前
开发者全社区  ·  交易媛载歌载舞
昨天
开发者全社区  ·  果然,DeepSex来了
昨天
开发者全社区  ·  月薪八万的中金员工被祭旗了
2 天前
开发者全社区  ·  大S的5亿遗产如何分配?
2 天前
不止读书  ·  生如蚁而美如神的27个瞬间
7 年前
夏一可死毒舌  ·  《守望先锋》联赛选手年薪至少5万美金
7 年前