Android启动优化之异步启动自定义启动器(二:基本逻辑)

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

到这里启动器的基本逻辑已实现,也已经能满足简单的启动流程。当然这也只是最核心基本的功能,看下面这张图就知道,还有很多地方可以扩展实现优化。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Resource Page Description 在以前的文章中,我曾多次强调应用程序中异步化的重要性。尤其对于IO密集型操作,异步执行对于应用程序的响应能力和伸缩性有非常关键的影响。正确使用异步编程能够使用尽可能少的线程来执行大量的IO密集型操作。可惜的是,即时异步编程有避免线程阻塞等诸多好处,但是这种编程方式至今没有被大量采用。其原因有很多,其中最主要的一点可能就是异步模型在编程较为困难,导致许多开发人员不愿意去做。 异步,则意味着一个任务至少要被拆分为“段式”的调用方式:一个方法用于发起异步请求,另一个方法用于异步任务完成后的回调。与传统方法调用方式相比,异步调用时的中间数据不能存放在线程栈上,方法之间的也不能简单地通过参数传递的方式来共享数据。此外,传统方法调用中的try…catch…finally,using等关键字都无法跨越方法边界,因此异步编程在处理异常,保护资源等方面也需要花更大的精力才行。如果一不小心,轻则造成资源泄露,重则使整个应用程序崩溃。 因此,无论是微软官方还是社区中都出现了一些简化异步编程方式的组件,例如微软并行与协调运行时和Wintellect's .NET Power Threading Library中的AsyncEnumerator。同时,我基于AsyncEnumerator构建了一个AsyncTaskDispatcher组件,使多个有依赖关系的异步操作之间的协作调用得以大大简化。 以上是引用,自己做了个更简单的demo

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜小徐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值