Skip to content

Commit 0c6820a

Browse files
committed
feat: 详细更新readme文档
1 parent 973e788 commit 0c6820a

3 files changed

Lines changed: 360 additions & 2 deletions

File tree

app/src/main/java/com/fee/start/LocalApp.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.fee.start
33
import android.app.Application
44
import com.fee.start.tasks.*
55
import com.github.androidstartup.StartupTasksManager
6+
import com.github.androidstartup.StartupTasksOrganizer
67
import java.util.concurrent.Executor
78
import java.util.concurrent.SynchronousQueue
89
import java.util.concurrent.ThreadPoolExecutor
@@ -39,5 +40,22 @@ class LocalApp : Application() {
3940
.withTask(Task2())
4041
.withTask(BuglyInitTask())
4142
.startUp() //开始启动任务
43+
44+
//分组模式下的代码示例:
45+
//第一组:
46+
StartupTasksOrganizer.TasksBuilder()
47+
.withTask(Task1())
48+
.withTask(Task2())
49+
.withTask(Task3())
50+
.build(this)
51+
.startUp()
52+
//第二组:
53+
StartupTasksOrganizer.TasksBuilder()
54+
.withTask(Task4())
55+
.withTask(Task5())
56+
.withTask(BuglyInitTask())
57+
.build(this)
58+
.startUp()
59+
4260
}
4361
}

readme.md

Lines changed: 341 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+

theAndroidStartup/src/main/java/com/github/androidstartup/StartupTasksManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class StartupTasksManager private constructor(): ITaskListener{
2626
private var mAppContext: Context? = null
2727

2828
/**
29-
* 启动任务的执行器
29+
* 启动任务的执行器(在各启动任务未提供执行器时使用给本类设置的公用执行器,最好是全局共用的)
3030
*/
3131
private var mTaskExecutor: Executor? = null
3232

0 commit comments

Comments
 (0)