android启动流程分析_android启动分析

android启动流程分析

Android Startup provides an application startup that can more simple and efficient way to initialize components. Developers can use Android Startup to simplify the Startup sequence, and explicitly set the initialization sequence and the dependencies between components. Meanwhile, Android Startup support synchronous and asynchronous wait, rely on manual control execution time and directed acyclic graph topological sort way to ensure that the internal depends on the initialization of the component order.

Android启动提供了应用程序启动功能,可以通过更简单有效的方式初始化组件。 开发人员可以使用Android启动来简化启动顺序,并显式设置初始化顺序和组件之间的依赖关系。 同时, Android Startup支持同步和异步等待,依靠手动控制执行时间和有向无环图拓扑排序方式来确保内部依赖于组件顺序的初始化。

Android Startup after several rounds of iteration has to be more perfect, support the function of the scene is more diversity, if you want to use Android Startup new features, will depend on the upgrade to the latest version

Android Startup经过几轮迭代必须更加完善,支持场景的功能更加多样化,如果要使用Android Startup的新功能,将取决于升级到最新版本

dependencies {
    implementation 'com.rousetime.android:android-startup:latest release'
}

In the previous why I abandoned the Jetpack App Startup? are provided in the article a comparison chart with App Startup, now has been a change.

在前面的文章中,为什么我放弃了Jetpack App Startup ? 文章中提供了与App Startup的比较表,现在已更改。

Image for post

Core content in the contrast diagram, detailed analysis according to the comparison chart below the Android implementation principle of Startup.

核心内容在对比图中,根据比较图详细分析,下面是Android的Startup实现原理。

组态 (Configuration)

手动配置(Manual configuration)

Manual configuration is through StartupManager Builder(), nature is very simple, use Builder mode to initialize some necessary parameters, and then to get the StartupManager instance, and then start Android Startup.

手动配置是通过StartupManager Builder()进行的,本质很简单,使用Builder模式初始化一些必要的参数,然后获取StartupManager实例,然后启动Android Startup。

val config = StartupConfig.Builder()
    .setLoggerLevel(LoggerLevel.DEBUG)
    .setAwaitTimeout(12000L)
    .setListener(object : StartupListener {
        override fun onCompleted(totalMainThreadCostTime: Long, costTimesModels: List<CostTimesModel>) {
            // can to do cost time statistics.
            costTimesLiveData.value = costTimesModels
            Log.d("StartupTrack", "onCompleted: ${costTimesModels.size}")
        }
    })
    .build()
 
StartupManager.Builder()
    .setConfig(config)
    .addStartup(SampleFirstStartup())
    .addStartup(SampleSecondStartup())
    .addStartup(SampleThirdStartup())
    .addStartup(SampleFourthStartup())
    .build(this)
    .start()
    .await()

自动配置(Automatic Configuration)

Another way is automatically configured, developers do not need to manually invoke.

另一种方法是自动配置的,开发人员无需手动调用。

<provider
    android:name="com.rousetime.android_startup.provider.StartupProvider"
    android:authorities="${applicationId}.android_startup"
    android:exported="false">


    <meta-data
        android:name="com.rousetime.sample.startup.SampleStartupProviderConfig"
        android:value="android.startup.provider.config" />


    <meta-data
        android:name="com.rousetime.sample.startup.SampleFourthStartup"
        android:value="android.startup" />


</provider>

To implement the principle of this configuration is: Android Startup interior is via a ContentProvider to realize the automatic configuration, in Android ContentProvider initialization time between Application of attachBaseContext and onCreate.

实现此配置的原理是:Android Startup内部是通过ContentProvider来实现自动配置的,在Android ContentProvider的初始化时间之间,Application的attachBaseContext和onCreate之间。

So Android Startup using this feature will initialize logic is encapsulated into a custom StartupProvider.

因此,Android Startup使用此功能将初始化逻辑封装到自定义的StartupProvider中

class StartupProvider : ContentProvider() {


    override fun onCreate(): Boolean {
        context.takeIf { context -> context != null }?.let {
            val store = StartupInitializer.instance.discoverAndInitialize(it)
            StartupManager.Builder()
                .setConfig(store.config?.getConfig())
                .addAllStartup(store.result)
                .build(it)
                .start()
                .await()
        } ?: throw StartupException("Context cannot be null.")


        return true
    }
    ...
    ...
}

After a StartupProvider, need to do is to parse the next AndroidManife.xml provider label under the configured Startup and Config.

在StartupProvider之后,需要做的是解析配置的Startup和Config下的下一个AndroidManife.xml提供程序标签。

Of the resolution were part of StartupInitializer() class, through its discoverAndInitialize() method can obtain the data to parse.

该解决方案属于StartupInitializer()类的一部分,可以通过其discoverAndInitialize()方法获取要解析的数据。

internal fun discoverAndInitialize(context: Context): StartupProviderStore {
 
    TraceCompat.beginSection(StartupInitializer::class.java.simpleName)
 
    val result = mutableListOf<AndroidStartup<*>>()
    val initialize = mutableListOf<String>()
    val initialized = mutableListOf<String>()
    var config: StartupProviderConfig? = null
    try {
        val provider = ComponentName(context.packageName, StartupProvider::class.java.name)
        val providerInfo = context.packageManager.getProviderInfo(provider, PackageManager.GET_META_DATA)
        val startup = context.getString(R.string.android_startup)
        val providerConfig = context.getString(R.string.android_startup_provider_config)
        providerInfo.metaData?.let { metaData ->
            metaData.keySet().forEach { key ->
                val value = metaData[key]
                val clazz = Class.forName(key)
                if (startup == value) {
                    if (AndroidStartup::class.java.isAssignableFrom(clazz)) {
                        doInitialize((clazz.getDeclaredConstructor().newInstance() as AndroidStartup<*>), result, initialize, initialized)
                    }
                } else if (providerConfig == value) {
                    if (StartupProviderConfig::class.java.isAssignableFrom(clazz)) {
                        config = clazz.getDeclaredConstructor().newInstance() as? StartupProviderConfig
                        // save initialized config
                        StartupCacheManager.instance.saveConfig(config?.getConfig())
                    }
                }
            }
        }
    } catch (t: Throwable) {
        throw StartupException(t)
    }
 
    TraceCompat.endSection()
 
    return StartupProviderStore(result, config)
}

The core logic is:

核心逻辑是:

  1. Through the ComponentName() for specified StartupProvider

    通过ComponentName()为指定的StartupProvider
  2. Through getProviderInfo() to obtain corresponding StartupProvider meta-data under data

    通过getProviderInfo()获取数据下对应的StartupProvider元数据
  3. Traverse meta-data array

    遍历元数据数组
  4. According to the predetermined value beforehand to match the corresponding name

    根据预先确定的值来匹配对应的名称
  5. Finally through the reflection to obtain the corresponding name instance

    最后通过反射获得相应的名称实例

In the parsing Startup process, in order to reduce Startup configuration, use doInitialize() method to automatically create dependent Startup, and inspection on circular dependencies in advance.

在解析启动过程中,为了减少启动配置,请使用doInitialize()方法自动创建依赖的启动,并预先检查循环依赖。

依靠支持 (Depend on the support)

/**
 * Returns a list of the other [Startup] objects that the initializer depends on.
 */
fun dependencies(): List<Class<out Startup<*>>>?


/**
 * Called whenever there is a dependency completion.
 *
 * @param [startup] dependencies [startup].
 * @param [result] of dependencies startup.
 */
fun onDependenciesCompleted(startup: Startup<*>, result: Any?)

Initialization of the component is initialized before the dependent components must pass dependencies() are stated. Stating will be in the subsequent parsing, after a dependent component; priority has been completed at the same time will depend on the component has been completed the callback onDependenciesCompleted() method. The execution order is decided by directed graph topological sort.

在声明从属组件必须通过dependencies()之前,先初始化组件的初始化。 声明将在从属组件之后的后续解析中进行; 优先级是否已完成,同时取决于组件已完成的回调onDependenciesCompleted()方法。 执行顺序由有向图拓扑排序决定。

闭环处理 (The closed-loop processing)

Upon processing of the closed-loop, on the one hand, in the automatic configuration link doInitialize() method will be processed.

一方面,在处理闭环后,将在自动配置链接中处理doInitialize()方法。

private fun doInitialize(
    startup: AndroidStartup<*>,
    result: MutableList<AndroidStartup<*>>,
    initialize: MutableList<String>,
    initialized: MutableList<String>
) {
    try {
        val uniqueKey = startup::class.java.getUniqueKey()
        if (initialize.contains(uniqueKey)) {
            throw IllegalStateException("have circle dependencies.")
        }
        if (!initialized.contains(uniqueKey)) {
            initialize.add(uniqueKey)
            result.add(startup)
            startup.dependencies()?.forEach {
                doInitialize(it.getDeclaredConstructor().newInstance() as AndroidStartup<*>, result, initialize, initialized)
            }
            initialize.remove(uniqueKey)
            initialized.add(uniqueKey)
        }
    } catch (t: Throwable) {
        throw StartupException(t)
    }
}

The current Startup joining initializes, at the same time traverse dependencies() rely on an array, recursive calls doInitialize().

当前的Startup联接进行初始化,同时遍历Dependencies()依赖于数组,递归调用doInitialize()。

In the process of recursion, if in initialize exist in the corresponding uniqueKey (here for the Startup of a unique identifier) is sent on behalf of depending on each other, is dependent on the ring.

在递归过程中,如果在initialize中存在对应的uniqueKey(此处为Startup的唯一标识符),则代表彼此依赖发送,取决于环。

Again, on the other hand, the subsequent digraph topological sort optimization will ring processing.

同样,另一方面,后续的有向图拓扑排序优化将响起处理。

fun sort(startupList: List<Startup<*>>): StartupSortStore {
    ...
 
    if (mainResult.size + ioResult.size != startupList.size) {
        throw StartupException("lack of dependencies or have circle dependencies.")
    }


}

In the process of sorting, optimization will be executed with the main thread in the main thread of Startup classification, and will not be in the process of classification on heavy processing, focus on the current Startup whether the main thread to perform again. So the last as long as the two classifications are not equal to the sum of the size of the Startup combined means ring, which depends on each other.

在排序过程中,优化将在Startup分类的主线程中使用主线程执行,而不会在分类过程中进行繁重的处理,着眼于当前的Startup是否再次执行主线程。 因此,只要两个分类的最后一个不等于Startup组合均值环的大小之和,后者就相互依赖。

依靠回调 (Relying on the callback)

Before relying on the callback to recognize an interface ManagerDispatcher

依靠回调来识别接口ManagerDispatcher之前

interface ManagerDispatcher {
 
    /**
     * dispatch prepare
     */
    fun prepare()
 
    /**
     * dispatch startup to executing.
     */
    fun dispatch(startup: Startup<*>, sortStore: StartupSortStore)
 
    /**
     * notify children when dependency startup completed.
     */
    fun notifyChildren(dependencyParent: Startup<*>, result: Any?, sortStore: StartupSortStore)
}

In ManagerDispatcher has three interface methods, respectively, used to manage Startup execution logic, guarantee the preparing work before execution, distribution in the process of execution with execution after the callback. So dependent on the callback nature also among them.

在ManagerDispatcher中有三种接口方法,分别用于管理Startup执行逻辑,保证执行前的准备工作,执行过程中的分配与回调后的执行。 因此,其中也取决于回调的性质。

Call logic is encapsulated to notifyChildren() method.The final call Startup onDependenciesCompleted() method.

调用逻辑封装为notifyChildren()方法。最后调用Startup onDependenciesCompleted()方法。

So we can be rewritten in the initialize components onDependenciesCompleted() method, so as to get the results returned after the completion of the dependent components. For example Sample of SampleSyncFourStartup.

这样我们就可以在初始化组件的onDependenciesCompleted()方法中进行重写,以获取依赖组件完成后返回的结果。 例如SampleSyncFourStartup的样本。

class SampleSyncFourStartup: AndroidStartup<String>() {
 
    private var mResult: String? = null
 
    override fun create(context: Context): String? {
        return "$mResult + sync four"
    }
 
    override fun callCreateOnMainThread(): Boolean = true
 
    override fun waitOnMainThread(): Boolean = false
 
    override fun dependencies(): List<Class<out Startup<*>>>? {
        return listOf(SampleAsyncTwoStartup::class.java)
    }
 
    override fun onDependenciesCompleted(startup: Startup<*>, result: Any?) {
        mResult = result as? String?
    }
}

This is, of course, in the current components depend on the component returns results, Android Startup has offered at any time to query execution of arbitrary components, and support for any returns the result of the components has been completed.

当然,这是当前组件依赖于组件返回的结果, Android Startup随时提供了查询任意组件执行情况的功能,并且对任何返回组件的结果的支持都已经完成。

Provide Android Startup StartupCacheManager to realize these functions. The specific ways used by looking at the Sample to obtain.

提供Android Startup StartupCacheManager来实现这些功能。 通过查看样本获得的具体方法。

手册告知 (Manual to inform)

The above depends on the callback is introduced, it is automatically after completion of calls to rely on a series of operations. Android Startup also offers a manual notify dependent tasks completed.

上面取决于回调的介绍,它是在调用完成后自动依靠一系列操作。 Android启动还提供了手动通知相关任务已完成的功能。

Notification Settings manually by manualDispatch() method open.It will cooperate with onDispatch() done together.

通过手动打开Dispatch()方法手动设置通知设置,它将与一起完成的onDispatch()配合使用。

In ManagerDispatcher interface implementation class notifyChildren() method, if open the manual notification, the automatic notification process will not go, call toNotify() method, but the current component will be the Dispatcher is added to the registry.Waiting for onDispatche() manual call to awaken toNotify() execution.

在ManagerDispatcher接口实现类notifyChildren()方法中,如果打开手动通知,则自动通知过程将不会继续,请调用toNotify()方法,但当前组件将Dispatcher添加到注册表中。调用以唤醒toNotify()执行。

override fun notifyChildren(dependencyParent: Startup<*>, result: Any?, sortStore: StartupSortStore) {
    // immediately notify main thread,Unblock the main thread.
    if (dependencyParent.waitOnMainThread()) {
        needAwaitCount.incrementAndGet()
        awaitCountDownLatch?.countDown()
    }
 
     sortStore.startupChildrenMap[dependencyParent::class.java.getUniqueKey()]?.forEach {
        sortStore.startupMap[it]?.run {
            onDependenciesCompleted(dependencyParent, result)
 
            if (dependencyParent.manualDispatch()) {
                dependencyParent.registerDispatcher(this)
            } else {
                toNotify()
            }
        }
    }
    ...
}

Specific implementation examples can see SampleManualDispatchStartup

具体的实现示例可以参见SampleManualDispatchStartup

拓扑优化 (Topology optimization)

Android Startup initialization in the relationship between component and component is this directed acyclic graph.

Android Startup中组件和组件之间的关系初始化是有向无环图。

To Sample in a demo, for example:

要在演示中进行采样,例如:

Image for post

We will each Startup edge point to target for a degree. According to this rule is easy to work out the four Startup into degrees.

我们将每个Startup边缘点定位到一个目标。 根据此规则,很容易将四个Start分为度数。

  1. SampleFirstStartup: 0

    SampleFirstStartup:0
  2. SampleSecondStartup: 1

    SampleSecondStartup:1
  3. SampleThirdStartup: 2

    SampleThirdStartup:2
  4. SampleFourthStartup: 3

    SampleFourthStartup:3

So what’s the use of this into the degree? According to the topological sort of AOV net structure topology sequence algorithm mainly performs the following two steps, until there is no into the vertex degree is 0.

那么这个学位有什么用? 根据AOV网络结构的拓扑排序,拓扑序列算法主要执行以下两个步骤,直到没有进入顶点的程度为0。

  1. Select a vertex and output into the degree of 0;

    选择一个顶点并输出为0度;
  2. Is removed from the network all the vertices and the edges

    从网络中删除所有顶点和边缘

End of the cycle, if the vertices of the output are less than the number of vertices in the net, then output “loop” information, otherwise the output sequence of the vertex is a kind of topological sequence.

循环结束时,如果输出的顶点少于网络中的顶点数,则输出“循环”信息,否则顶点的输出序列是一种拓扑序列。

According to the steps above, can be concluded that the above four Startup output order:

根据以上步骤,可以得出以上四个启动输出的命令:

SampleFirstStartup -> SampleSecondStartup -> SampleThirdStartup -> SampleFourthStartup

The output of the above order is an initialized execution sequence between components. Such guarantee normal execution of the dependence between components, also ensures that initializes the component order of execution of the optimal solution, which depends on the shortest waiting time between components, as well as to check if there is a link between the dependent components.

上面命令的输出是组件之间的初始化执行序列。 这样保证了组件之间依赖关系的正常执行,还确保初始化最优解决方案的组件执行顺序,该顺序取决于组件之间的最短等待时间,以及检查从属组件之间是否存在链接。

Now that we have the solutions and implementation steps, the next thing to do is to use code out.

现在我们有了解决方案和实现步骤,下一步是使用代码。

fun sort(startupList: List<Startup<*>>): StartupSortStore {
    TraceCompat.beginSection(TopologySort::class.java.simpleName)


    val mainResult = mutableListOf<Startup<*>>()
    val ioResult = mutableListOf<Startup<*>>()
    val temp = mutableListOf<Startup<*>>()
    val startupMap = hashMapOf<String, Startup<*>>()
    val zeroDeque = ArrayDeque<String>()
    val startupChildrenMap = hashMapOf<String, MutableList<String>>()
    val inDegreeMap = hashMapOf<String, Int>()


    startupList.forEach {
        val uniqueKey = it::class.java.getUniqueKey()
        if (!startupMap.containsKey(uniqueKey)) {
            startupMap[uniqueKey] = it
            // save in-degree
            inDegreeMap[uniqueKey] = it.dependencies()?.size ?: 0
            if (it.dependencies().isNullOrEmpty()) {
                zeroDeque.offer(uniqueKey)
            } else {
                // add key parent, value list children
                it.dependencies()?.forEach { parent ->
                    val parentUniqueKey = parent.getUniqueKey()
                    if (startupChildrenMap[parentUniqueKey] == null) {
                        startupChildrenMap[parentUniqueKey] = arrayListOf()
                    }
                    startupChildrenMap[parentUniqueKey]?.add(uniqueKey)
                }
            }
        } else {
            throw StartupException("$it multiple add.")
        }
    }


    while (!zeroDeque.isEmpty()) {
        zeroDeque.poll()?.let {
            startupMap[it]?.let { androidStartup ->
                temp.add(androidStartup)
                // add zero in-degree to result list
                if (androidStartup.callCreateOnMainThread()) {
                    mainResult.add(androidStartup)
                } else {
                    ioResult.add(androidStartup)
                }
            }
            startupChildrenMap[it]?.forEach { children ->
                inDegreeMap[children] = inDegreeMap[children]?.minus(1) ?: 0
                // add zero in-degree to deque
                if (inDegreeMap[children] == 0) {
                    zeroDeque.offer(children)
                }
            }
        }
    }


    if (mainResult.size + ioResult.size != startupList.size) {
        throw StartupException("lack of dependencies or have circle dependencies.")
    }


    val result = mutableListOf<Startup<*>>().apply {
        addAll(ioResult)
        addAll(mainResult)
    }
    printResult(temp)


    TraceCompat.endSection()


    return StartupSortStore(
        result,
        startupMap,
        startupChildrenMap
    )
}

With the above steps, I believe this code to be able to understand.

通过上述步骤,我相信这段代码是可以理解的。

In addition to the above-described functions, Android Startup also supports the Systrace pile, to provide users with a systematic analysis of the initialization time-consuming process in detail; Initializes the component’s accurate time consuming to collect statistics, convenient for users to download and uploaded to the specified server and so on.

除了上述功能外,Android Startup还支持Systrace桩,为用户提供详细的初始化耗时过程的系统分析; 初始化组件的准确消耗时间来收集统计信息,方便用户下载并上传到指定的服务器等。

The analysis of the core function of Android Startup temporarily over here, hope to be able to help you.

暂时在这里对Android Startup的核心功能进行分析,希望能对您有所帮助。

Of course, I sincerely invite you to join in the construction of the Android Startup, if you have any good suggestions please feel free to comment.

当然,我诚挚地邀请您加入Android Startup的建设,如果您有任何好的建议,请随时发表评论。

翻译自: https://medium.com/swlh/android-startup-analysis-8ce7560f3672

android启动流程分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值