Android启动优化之异步启动自定义启动器(一)
实现类说明
AppStartTaskExecutor(启动任务的线程类):这个类就是上篇说的根据CPU核数获取对应的线程类
AppStartTask(启动任务的基本):包含任务的基本参数和实现了任务的基本方法的基类
AppStartTaskDispatcher(启动任务的调度类):用于关联任务和处理任务间的执行逻辑
AppStartTaskRunnable(启动任务的流程执行类):用于处理单个任务的具体执行
类的具体实现
初步实现的逻辑并不复杂,代码不多就自己看吧
/**
* 线程提供类
*/
object AppStartTaskExecutor {
//获取CPU的核处理器数
private val CPU_COUNT = Runtime.getRuntime().availableProcessors()
//计算创建对应的线程池数量
private val CORE_POOL_SIZE = max(2, min(CPU_COUNT - 1, 4))
//线程池线程数的最大值
private val MAXIMUM_POOL_SIZE = CORE_POOL_SIZE
//线程空置回收时间
private const val KEEP_ALIVE_SECONDS = 5L
//线程池队列
private val mPoolWorkQueue: BlockingQueue<Runnable> by lazy { LinkedBlockingQueue() }
private val mHandler =
RejectedExecutionHandler { r, _ -> Executors.newCachedThreadPool().execute(r); }
//获取对应参数,创建CPU线程池
val sCPUThreadPoolExecutor = ThreadPoolExecutor(
CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE,
KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS,
mPoolWorkQueue,
Executors.defaultThreadFactory(),
mHandler
).apply {
allowCoreThreadTimeOut(true)
}
//创建IO线程池
val sIOThreadPoolExecutor: ExecutorService =
Executors.newCachedThreadPool(Executors.defaultThreadFactory())
}
/**
* 任务基类
* 定义定时器(用于等待父任务执行完成,数量=父任务的数量)
* 函数:父任务的列表
* 函数:让当前任务进入等待状态
* 函数:通知父任务完成,减少定时数
* 函数:执行线程
* 函数:线程的优先级
* 函数:是否需要等待
* 函数:是否执行在主线程
* 函数:任务执行内容
*/
abstract class AppStartTask {
//定义定时器(用于等待父任务执行完成,数量=父任务的数量)
private val countDownLatch = CountDownLatch(getDependsTaskList()?.size ?: 0);
/**
* 父任务的列表
*/
open fun getDependsTaskList(): List<Class<out AppStartTask>>? = null
/**
* 让当前任务进入等待状态
*/
fun waitToNotify() {
try {
countDownLatch.await()
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
/**
* 通知父任务完成,减少定时数
*/
fun notifyDependsTaskFinish() {
countDownLatch.countDown()
}
/**
* 执行线程
*/
open fun runOnExecutor(): Executor = AppStartTaskExecutor.sIOThreadPoolExecutor
/**
* 优先级的范围,可根据Task重要程度及工作量指定;之后根据实际情况决定是否有必要放更大
*/
@IntRange(
from = Process.THREAD_PRIORITY_FOREGROUND.toLong(),
to = Process.THREAD_PRIORITY_LOWEST.toLong()
)
open fun priority(): Int = Process.THREAD_PRIORITY_BACKGROUND
/**
* 是否需要等待
*/
open fun needWait(): Boolean = true
/**
* 是否执行在主线程
*/
abstract fun isRunOnMainThread(): Boolean
/**
* 执行的任务内容
*/
abstract fun run()
}
/**
* 启动任务调度类
* 1、添加必要参数(主线程判断,是否显示日志,等待总时长)
* 2、添加任务到列表
* 3、开启任务
* 3.1、前期判断,必须在主线程执行
* 3.2、任务列表拓扑排序
* 3.3、拆分线程任务
* 3.4、分线程执行任务
* 4、任务等待
* 5、其他调用
* 通知子任务,父任务已完成
* 标记任务完成
*/
object AppStartTaskDispatcher {
//是否调用过setContext
var callContext: Boolean = false
//是否显示日志
var mShowLog: Boolean = false
//等待总时长
var mAllTaskWaitTimeOut: Long = 10000
//判断当前是否在主线程
private var isInMainProgress = false
//用于等待需要等待的任务完成
private var mCountDownLatch: CountDownLatch? = null
//需要等待的数量
private val mNeedWaitCount = AtomicInteger()
//所有启动任务任务
private val mStartTaskList: ArrayList<AppStartTask> = ArrayList()
//存放每个Task (key= Class < ? extends AppStartTask>)
private val mTaskMap: HashMap<Class<out AppStartTask>, AppStartTask> = HashMap()
//每个Task的孩子 (key= Class < ? extends AppStartTask>)
private val mTaskChildMap: HashMap<Class<out AppStartTask?>, HashSet<Class<out AppStartTask>>> =
HashMap()
//拓扑排序后的主线程的任务
private val mSortMainThreadTaskList: ArrayList<AppStartTask> = ArrayList()
//拓扑排序后的子线程的任务
private val mSortThreadPoolTaskList: ArrayList<AppStartTask> = ArrayList()
//记录启动总时间
private var mStartTime: Long = 0L
fun setContext(context: Context): AppStartTaskDispatcher {
callContext = true
isInMainProgress = ProcessUtil.isMainProcess(context)
return this
}
fun setShowLog(showLog: Boolean): AppStartTaskDispatcher {
mShowLog = showLog
return this
}
fun setAllTaskWaitTimeOut(timeOut: Long): AppStartTaskDispatcher {
mAllTaskWaitTimeOut = timeOut
return this
}
/**
* 添加启动任务类
*/
fun addAppStartTask(task: AppStartTask?): AppStartTaskDispatcher {
task?.let {
//加入列表
mStartTaskList.add(task)
//如果需要等待执行,等待数量加1
if (task.needWait()) {
mNeedWaitCount.getAndIncrement()
}
} ?: throw RuntimeException("addAppStartTask() 传入的appStartTask为null")
return this
}
/**
* 开启任务
*/
fun start(): AppStartTaskDispatcher {
//前期判断准备
if (!callContext) throw RuntimeException("调用start()方法前必须调用setContext()方法")
if (Looper.getMainLooper() != Looper.myLooper()) throw RuntimeException("start方法必须在主线程调用")
if (!isInMainProgress) {
AppStartTaskLogUtil.showLog("当前进程非主进程")
return this
}
//开始点(start和await连着用才有效)
mStartTime = System.currentTimeMillis()
//获取拓扑排序后的列表
val sortAppStartTask =
AppStartTaskSortUtil.sortAppStartTask(mStartTaskList, mTaskMap, mTaskChildMap)
//打印列表日志
printSortTask(sortAppStartTask)
//拆分主线程任务和子线程任务
initRealSortTask(sortAppStartTask)
//创建计数器
mCountDownLatch = CountDownLatch(mNeedWaitCount.get())
//对应线程执行任务
dispatchAppStartTask()
return this
}
//等待,阻塞主线程
fun await() {
try {
mCountDownLatch?.await(mAllTaskWaitTimeOut, TimeUnit.MILLISECONDS)
?: throw java.lang.RuntimeException("在调用await()之前,必须先调用start()")
AppStartTaskLogUtil.showLog("启动耗时:${System.currentTimeMillis() - mStartTime}")
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
/**
* 输出排好序的Task
*/
private fun printSortTask(sortTask: ArrayList<AppStartTask>) {
val sb = StringBuilder()
sb.append("当前所有任务排好的顺序为:")
sortTask.forEachIndexed { i, task ->
val taskName: String = task::class.java.simpleName
if (i == 0) {
sb.append(taskName)
} else {
sb.append("--->")
sb.append(taskName)
}
}
AppStartTaskLogUtil.showLog(sb.toString())
}
/**
* 分别处理主线程和子线程的任务
*/
private fun initRealSortTask(sortTask: ArrayList<AppStartTask>) {
mSortMainThreadTaskList.clear()
mSortThreadPoolTaskList.clear()
for (appStartTask in sortTask) {
if (appStartTask.isRunOnMainThread()) {
mSortMainThreadTaskList.add(appStartTask)
} else {
mSortThreadPoolTaskList.add(appStartTask)
}
}
}
/**
* 分线程执行任务
*/
private fun dispatchAppStartTask() {
mSortThreadPoolTaskList.forEach { threadTask ->
threadTask.runOnExecutor().execute(AppStartTaskRunnable(threadTask, this))
}
mSortMainThreadTaskList.forEach { mainTask ->
AppStartTaskRunnable(mainTask, this).run()
}
}
/**
* 通知子任务,父任务完成了
*/
fun setNotifyChildren(appStartTask: AppStartTask) {
mTaskChildMap[appStartTask::class.java]?.forEach { cls ->
mTaskMap[cls]?.notifyDependsTaskFinish()
}
}
/**
* 标识需要等待的任务完成
*/
fun markAppStartTaskFinish(appStartTask: AppStartTask) {
AppStartTaskLogUtil.showLog("任务完成了:" + appStartTask::class.java.simpleName)
//如果是需要等待的任务
if (ifNeedWait(appStartTask)) {
//等待数量-1
mCountDownLatch?.countDown()
mNeedWaitCount.getAndDecrement()
}
}
/**
* 是否需要等待,主线程的任务本来就是阻塞的,所以不用管
*/
private fun ifNeedWait(task: AppStartTask): Boolean {
return !task.isRunOnMainThread() && task.needWait()
}
}
/**
* 任务任务类
* 执行流程:
* 1、设置优先级
* 2、设置任务等待
* 3、执行任务内容
* 4、通知子任务完成
* 5、标记任务完成
*/
class AppStartTaskRunnable(
private val task: AppStartTask,
private val dispatcher: AppStartTaskDispatcher? = null
) :
Runnable {
override fun run() {
//设置优先级
Process.setThreadPriority(task.priority())
//任务等待
task.waitToNotify()
//执行内容
task.run()
//通知子任务完成
dispatcher?.setNotifyChildren(task)
//标记任务结束
dispatcher?.markAppStartTaskFinish(task)
}
}
启动器的调用
1、新建任务类
class AppStartTaskOne : AppStartTask() {
override fun isRunOnMainThread(): Boolean = false
override fun run() {
AppStartTaskLogUtil.showLog("任务一")
}
override fun getDependsTaskList(): List<Class<out AppStartTask>>? {
return arrayListOf(AppStartTaskTwo::class.java)
}
}
2、调用
AppStartTaskDispatcher.setContext(this).setShowLog(true).addAppStartTask(AppStartTaskOne())
.addAppStartTask(AppStartTaskTwo()).addAppStartTask(AppStartTaskThree())
.addAppStartTask(AppStartTaskFour()).addAppStartTask(AppStartTaskFive())
.start().await()
附上项目Demo:https://github.com/caixiaoxu/SyncLauncherDemo
到这里启动器的基本逻辑已实现,也已经能满足简单的启动流程。当然这也只是最核心基本的功能,看下面这张图就知道,还有很多地方可以扩展实现优化。