1.Startup组件是什么

Startup组件是Google Jetpack推出的,它供给了一种直接高效的办法用来在运用程序发动的时分对多个组件进行初始化,开发者能够依靠它来显示地设置多个组件间的初始化次序,并优化运用的发动时刻。在没有Startup组件之前,许多的三方库为了简化开发者的运用本钱,常常会界说一个ContentProvider获取Context的目标,然后主动完结库的初始化,也就是咱们之前运用库的时分,总是需求在Application中调用下某某库的:XXXLib.init(Context)办法,主要是将咱们的Context传递给三方库。因为ContentProvider会在Application的onCreate()之前调用,所以能够通过界说ContentProvider的办法提早获取到Context。可是这样做会有问题的,因为假如每个三方库都界说一个自己的ContentProvider,而且在拿Context的时分都做了耗时操作,这样就会导致运用的发动变慢和长时刻黑屏的问题。因此,Google就推出了Startup组件,Startup组件允许库的开发者和App的开发者同享一个ContentProvider,用于完结各自的初始化逻辑,而且支持设置组件之间的初始化次序。这样运用就能够选择先初始化需求立刻运用到的库,其他的不需求立刻运用的库后面再初始化。然后到达缩短运用的发动时刻。

2.Startup组件能做啥

2.1 startup组件能够简化用户运用咱们供给的库的流程。

比方咱们非常了解的内存泄漏检测工具LeakCarry,在没有运用Startup组件之前,运用它需求在Application中初始化一下,如下所示:

Jetpack Startup 高雅完结库的初始化和办法接口简化
也就是说用户不仅需求引进依靠,还需求做初始化工作。可是引进了startup组件后,运用LeakCanary就能够只引进依靠了。LeakCanary库会通过startup组件供给的API拿到想要的Context,然后进行内存泄漏的检测工作。下面是LeakCanary库运用startup组件的截图: 首先是Manifest中

Jetpack Startup 高雅完结库的初始化和办法接口简化
初始化类:
Jetpack Startup 高雅完结库的初始化和办法接口简化
然后咱们就能够看到在LeakCanary库中就能拿到了Context并进行初始化了。所以咱们运用的时分,只需求引进依靠:

dependencies {
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}

就能够运用LeakCanary库检测内存泄漏了。

2.2 简化库供给给运用者的API接口

现在的VR眼镜基本上都是基于Android体系的,而3D场景的烘托都依靠于Unity和OpenGL,Unity和OpenGL烘托时的数据有一部分是需求Android体系供给的,所以就需求Android开发接口供给给Unity或者是OpenGL调用。可是许多的时分接口都需求运用单例的办法供给而且需求传递Context,如下所示:

Jetpack Startup 高雅完结库的初始化和办法接口简化
这样调用者在调用的时分就需求运用LoadAllAPIEngine.getInstance(context).getInfo()的办法去运用咱们供给的服务,而且还需求调用下LoadAllAPIEngine.getInstance(context).init()办法让咱们供给接口的库做一些初始化的动作。在开发的过程中发现运用接口的同事会常常多次调用init()办法,或者是忘记调用release()办法,导致呈现一些未知的问题。而且假如是OpenGL调用咱们的接口时,往往需求反射获取Android的Context,然后再每次调用接口时传递给供给服务的sdk库。这些都增加了SDK运用者的负担,同时也让咱们查问题时显得很费劲。

而运用Startup组件能够能够处理这个问题,运用了startup组件后,运用者只要引进咱们的库依靠,就能够运用咱们的供给的接口办法获取到想要的信息了,运用startup组件后,调用接口就能够变成。 LoadAllAPIEngine.getInstance().getInfo()了,而且不必调用LoadAllAPIEngine.getInstance(context).init()办法,直接运用接口即可。

3.怎么运用Startup组件

3.1 引进依靠

implementation("androidx.startup:startup-runtime:1.1.1")

3.2 创建一个初始化的类继承Initializer

然后重写create()办法和dependencies()办法。然后在create()办法中就能够拿到引用咱们库的APP的Context了。

class StartupInitializer : Initializer<StartupInitializer>{
    override fun create(context: Context): StartupInitializer = apply {
        val application = context.applicationContext as Application
        application.registerActivityLifecycleCallbacks(object 
        :ActivityLifecycleCallbacks{
            override fun onActivityCreated(activity: Activity, 
            savedInstanceState: Bundle?) {
                FMSdk.getInstance().init(activity)
                Log.d(TAG,"onActivityCreated")
            }
            override fun onActivityStarted(activity: Activity) {
            }
            override fun onActivityResumed(activity: Activity) {
                FMSdk.getInstance().resume()
                Log.d(TAG,"onActivityResumed")
            }
            override fun onActivityPaused(activity: Activity) {
            }
            override fun onActivityStopped(activity: Activity) {
                FMSdk.getInstance().pause()
                Log.d(TAG,"onActivityStopped")
            }
            override fun onActivitySaveInstanceState(activity: Activity, 
            outState: Bundle) {
            }
            override fun onActivityDestroyed(activity: Activity) {
                FMSdk.getInstance().release()
                Log.d(TAG,"onActivityDestroyed")
            }
        })
    }
    //获取在初始化本身之前需求先初始化的其他Initializer 列表 ,
    // 这儿有助于咱们办理库的依靠次序,比方咱们的库依靠其他的库A,而且需求在
    // A之后进行初始化,就能够在这儿装备
    //假如不需求依靠于其它组件,则能够回来一个空列表
    override fun dependencies()  = emptyList<Class<out Initializer<*>>>()
}

3.3 在咱们库的AndroidManifest.xml中加入装备

界说好初始化的类后,咱们需求在咱们的库项目中声明一个provider,装备authorities为引用咱们库的app的包名+”.androidx-startup”,然后界说一个<meta-data ../>节点,将咱们界说的初始化类引用装备上去,这儿我界说的类引用为:com.nolovr.core.fmsdk.engine.StartupInitializer。具体装备参考下面代码。

<application>
    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <meta-data
            android:name="com.nolovr.core.fmsdk.engine.StartupInitializer"
            android:value="androidx.startup"
            />
    </provider>    
</application>

上面的步骤装备完后,开发者接入咱们的库时就能够直接引进依靠,然后直接调用咱们的库中的对应办法,不必再去Application下去做啥初始化操作啦

4.运用Startup组件的注意点

(1)运用Startup咱们需求注意不能在StartupInitializer 的create()办法中做耗时操作,因为create办法是在主线程被调用的,假如做耗时操作会导致初始化时刻变长,导致运用呈现发动慢,黑白屏的问题。 (2)在引用库的主项目中不能运用tools:node=”remove” 的语句要求在合并 AndroidManifest 文件时移除本身否则主动初始化的功用就无法运用了。例如不能在主项目中做如下装备:

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">
    <meta-data
        android:name="com.nolovr.core.fmsdk.engine.StartupInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
</provider>

或者是:

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove" />

因为这样会导致咱们的startup组件不收效,当然,假如是想自己手动初始化库的情况下除外。