@@ -56,4 +56,344 @@ dependencies {
5656}
5757```
5858
59- AS提示需要 同步工程,同步成功后,即依赖成功
59+ AS提示需要 同步工程,同步成功后,即依赖成功。
60+
61+ # 核心类、APIs
62+
63+ 初始化任务被定义为 启动任务接口,所有的启动初始化任务皆为该接口的子类:
64+
65+ ``` kotlin
66+ interface IStartupTask <T > : ITaskStateIndicate {
67+
68+ /* *
69+ * 执行任务
70+ * @return [T] 执行了启动任务可能的 返回数据
71+ */
72+ fun doStartupTask (context : Context ): T
73+
74+ /* *
75+ * 本启动任务所依赖的其他 task的数量,本任务所依赖的其他任务数量小于1时(即没有依赖其他任务)则优先执行
76+ */
77+ fun getDependentTaskCount (): Int
78+
79+
80+ /* *
81+ * 本启动任务所依赖的其他启动任务的 Class数据集
82+ * 作用为:在本启动任务执行前,需要在所依赖其他任务执行完后再执行
83+ */
84+ fun dependentTask (): List <Class <out IStartupTask <* >>>?
85+
86+
87+ }
88+ ```
89+
90+ 其中类范型<T > 表示启动任务的执行时 ** fun doStartupTask(context: Context): T** 可能需要返回执行结果,而 ** ITaskStateIndicate** 接口意义为 启动任务的状态指示,为了让各任务子类对外标示优先级、运行需求的线程是否为主线程、提供自定义的任务执行器 ** Executor(线程池)** 等:
91+
92+ ``` kotlin
93+ interface ITaskStateIndicate {
94+ /* *
95+ * 标识任务的执行优先级
96+ * def = Process.THREAD_PRIORITY_DEFAULT == 0
97+ */
98+ fun indicateTaskPriority (): Int = android.os.Process .THREAD_PRIORITY_DEFAULT
99+
100+ /* *
101+ * 标识启动任务是否依赖主线程的执行
102+ */
103+ fun isDependonMainThread (): Boolean
104+
105+ /* *
106+ * 启动任务所依赖的任务 执行器 [Executor]
107+ */
108+ fun dependonTaskExecutor (): Executor ? = null
109+
110+ /* *
111+ * 标记当前启动任务先等一等
112+ */
113+ fun letHoldOn ()
114+
115+ /* *
116+ * 当当前任务的上游任务完成时通知当前任务将可以执行、动作
117+ */
118+ fun letWillAction ()
119+ }
120+ ```
121+
122+ 进而为了方便开发者编写自定义的启动任务类,框架有必要默认提供一个抽象的启动任务类,以提供通用的接口实现
123+
124+ ``` kotlin
125+ abstract class AStartupTask <T >: IStartupTask <T > {
126+ protected val mTag: String by lazy(LazyThreadSafetyMode .NONE ) {
127+ javaClass.simpleName
128+ }
129+
130+ /* *
131+ * 本启动任务所依赖的上游任务在完成后的 CountDown,当所有依赖的上游任务都完成后才通知本任务执行
132+ */
133+ private val mDependentTaskCountDown by lazy(LazyThreadSafetyMode .NONE ){
134+ CountDownLatch (getDependentTaskCount())
135+ }
136+
137+ /* *
138+ * 本启动任务所依赖的其他启动任务的数量
139+ * 之所以增加这个属性,避免在调用[getDependentTaskCount]时每次都去调用[dependentTask]
140+ * 重复生成 List<>
141+ * def = -1,子类可以赋值,本父类默认会调用[dependentTask] 来查询一次
142+ */
143+ protected var mDependentTaskCount = - 1
144+
145+ /* *
146+ * 本启动任务所依赖的其他 task的数量,本任务所依赖的其他任务数量小于1时(即没有依赖其他任务)则优先执行
147+ */
148+ override fun getDependentTaskCount (): Int {
149+ if (mDependentTaskCount == - 1 ) {
150+ mDependentTaskCount = dependentTask()?.size ? : 0
151+ }
152+ return mDependentTaskCount
153+ }
154+
155+ /* *
156+ * 本启动任务所依赖的其他启动任务的 Class数据集
157+ * 作用为:在本启动任务执行前,需要在所依赖其他任务执行完后再执行
158+ */
159+ override fun dependentTask (): List <Class <out IStartupTask <* >>>? {
160+ return null
161+ }
162+
163+ // ----------------
164+ /* *
165+ * 标记当前启动任务先等一等
166+ */
167+ override fun letHoldOn () {
168+ try {
169+ mDependentTaskCountDown.await()
170+ }catch (ex: InterruptedException ){
171+ ex.printStackTrace()
172+ }
173+ }
174+
175+ /* *
176+ * 当当前任务的上游任务完成时通知当前任务将可以执行、动作
177+ */
178+ override fun letWillAction () {
179+ mDependentTaskCountDown.countDown()
180+ }
181+ // ----------------
182+
183+ override fun toString (): String {
184+ return " task: $mTag ,mDependentTaskCount = $mDependentTaskCount "
185+ }
186+ }
187+ ```
188+
189+ 开发使用本框架基本上只需要 继承 以上该抽象启动类。
190+
191+ # 编写自定义的启动任务类
192+
193+ 简单示例,项目中需要对 ** Bugly** 此类第三方SDK的初始化,我们取名为 BuglyInitTask:
194+
195+ ``` kotlin
196+ class BuglyInitTask : AStartupTask <String >() {
197+ /* *
198+ * 执行任务
199+ * @return [T] 执行了启动任务可能的 返回数据
200+ */
201+ override fun doStartupTask (context : Context ): String {
202+ // Bugly.init()
203+ return " bugly sdk init finish"
204+ }
205+
206+ /* *
207+ * 标识启动任务是否依赖主线程的执行
208+ */
209+ override fun isDependonMainThread (): Boolean {
210+ return true
211+ }
212+
213+ override fun dependentTask (): List <Class <out IStartupTask <* >>>? {
214+ return listOf (Task1 ::class .java)
215+ }
216+ }
217+ ```
218+
219+ 当然如果所自定义的启动任务还有其他的配置需求,可以查看其父类以重写实现。
220+
221+ # 单例模式启动任务组(简单)
222+
223+ 大多数情况下,我们的项目中把1个~N个启动初始化任务集只规划成一组即可,由框架中 ** StartupTasksManager** 懒汉式单例进行添加与管理:
224+
225+ ``` kotlin
226+ // API有节选:
227+ /* * <P>DESC:
228+ * 启动任务管理者(单例)
229+ * </p>
230+ * ******************(^_^)***********************
231+ */
232+ class StartupTasksManager private constructor(): ITaskListener{
233+ companion object Builder{
234+ private val mTasksManager: StartupTasksManager by lazy(LazyThreadSafetyMode .NONE ){
235+ StartupTasksManager ()
236+ }
237+
238+ /* *
239+ * 添加启动任务
240+ */
241+ fun withTask (startupTask : IStartupTask <* >): StartupTasksManager {
242+ return getTasksManager().withTask(startupTask)
243+ }
244+
245+ /* *
246+ * 获取 启动任务管理器
247+ */
248+ fun getTasksManager (): StartupTasksManager = mTasksManager
249+ }
250+
251+ /* *
252+ * 添加启动任务
253+ */
254+ @MainThread
255+ fun withTask (startupTask : IStartupTask <* >): StartupTasksManager {
256+ mAddedTasksList.add(startupTask)
257+ return this
258+ }
259+
260+ /* *
261+ * 开始启动、执行各启动任务
262+ */
263+ @MainThread
264+ fun startUp (){
265+ if (mAppContext == null || mAddedTasksList.isEmpty()) {
266+ return
267+ }
268+ sortStartupTasks(mAddedTasksList)
269+ mAddedTasksList.clear()// 这个数据集不需要了
270+ mSortedTasksList.forEach { task ->
271+ val taskRunner = TaskRunner (appContext = mAppContext!! , task, this )
272+ if (task.isDependonMainThread()){
273+ taskRunner.run ()
274+ } else {
275+ task.dependonTaskExecutor() ? : mTaskExecutor?.execute(taskRunner)
276+ }
277+ }
278+ }
279+ }
280+ ```
281+
282+ 再开发编写完各自定义的启动任务后,在相应的位置(一般为 ** Applicaton** 初始化的位置) 按照前方的 API 进行配置、启动:
283+
284+ ``` kotlin
285+ class LocalApp : Application () {
286+
287+ override fun onCreate () {
288+ super .onCreate()
289+ val gloabalExecutor: Executor = ThreadPoolExecutor (
290+ 1 ,
291+ 3 ,
292+ 1 ,
293+ TimeUnit .MINUTES ,
294+ SynchronousQueue ()
295+ )
296+ StartupTasksManager .getTasksManager()
297+ .withContext(this ) // 设置上下文 Context
298+ .withTaskExecutor(gloabalExecutor) // 配置启动任务的全局 Executor(线程池)
299+ .withTask(Task1 ())
300+ .withTask(Task5 ())
301+ .withTask(Task3 ())
302+ .withTask(Task4 ())
303+ .withTask(Task2 ())
304+ .withTask(BuglyInitTask ())
305+ .startUp() // 开始启动任务
306+ }
307+ }
308+ ```
309+
310+
311+
312+ # 分组模式启动任务组(启动任务再分组)
313+
314+ 这种模式即对应的项目中确实可能存在比较复杂的启动任务需求,比如我们需要把 Task1,Task2,Task3 看成一组启动任务集,另把 Task4,Task5,BuglyInitTask 看成另外一组任务集,然后再分别启动,可能这些分组的任务集之间又存在依赖顺序关系(框架中暂时还未实现),这个需求目前被 ** StartupTasksOrganizer** 类看成任务集的组织者来实现:
315+
316+ ``` kotlin
317+ // API代码有节选
318+ /* * <P>DESC:
319+ * 启动任务组织者(每个组织者组织一组启动任务)
320+ * </p>
321+ * ******************(^_^)***********************
322+ */
323+ class StartupTasksOrganizer (private val mAppContext : Context ? ,private val mAddedTaskList : List <IStartupTask <* >>):ITaskListener {
324+
325+ private var mTasksRelationMapper: StartupTasksRelationMapper ? = null
326+
327+
328+ /* *
329+ * 开始启动一组 启动任务
330+ */
331+ @MainThread
332+ fun startUp (){
333+ if (mAppContext == null || mAddedTaskList.isEmpty()) {
334+ return
335+ }
336+ // 排序
337+ mTasksRelationMapper = StartupTasksManager .sortStartupTasksAndResult(mAddedTaskList).apply {
338+ sortedTasks.forEach { task ->
339+ val taskRunner = TaskRunner (mAppContext,task,this @StartupTasksOrganizer)
340+ if (task.isDependonMainThread()){
341+ taskRunner.run ()
342+ } else {
343+ task.dependonTaskExecutor() ? : theSameTaskExecutor()?.execute(taskRunner)
344+ }
345+ }
346+ }
347+ }
348+
349+ /* *
350+ * 一组启动任务的构建者
351+ */
352+ companion object class TasksBuilder {
353+ private val mAddedTasks by lazy(LazyThreadSafetyMode .NONE ){
354+ mutableListOf<IStartupTask <* >>()
355+ }
356+
357+ private var mContext: Context ? = null
358+
359+ fun withTask (task : IStartupTask <* >): TasksBuilder {
360+ mAddedTasks.add(task)
361+ return this
362+ }
363+
364+ fun build (context : Context ): TasksBuilder {
365+ this .mContext = context
366+ return this
367+ }
368+
369+ fun startUp (){
370+ StartupTasksOrganizer (mContext,mAddedTasks).startUp()
371+ }
372+ }
373+ }
374+ ```
375+
376+ 可见由 构建者模式的 ** TasksBuilder** 来进行构建,则分组模式代码示例:
377+
378+ ``` kotlin
379+ // 分组模式下的代码示例:
380+ // 第一组:
381+ StartupTasksOrganizer .TasksBuilder ()
382+ .withTask(Task1 ())
383+ .withTask(Task2 ())
384+ .withTask(Task3 ())
385+ .build(this )
386+ .startUp()
387+ // 第二组:
388+ StartupTasksOrganizer .TasksBuilder ()
389+ .withTask(Task4 ())
390+ .withTask(Task5 ())
391+ .withTask(BuglyInitTask ())
392+ .build(this )
393+ .startUp()
394+ ```
395+
396+ 至此,本启动任务框架基本上介绍完了,具体可以翻阅源码精读(有着较良好的代码注释),感谢提供任何建议,为谢!
397+
398+
399+
0 commit comments