Dart learning tutorial for Android developers

Preface

Last Saturday, I ate the wrong food, suddenly dizzy, fever, vomiting suddenly in the middle of the night, diarrhea, the whole person was tossed enough. I went to the hospital for an examination and said it was caused by xx enteritis and eating the wrong food. I lay at home and rested for four days.

Today, it finally came over. Update the last article in the Android startup optimization directed acyclic graph series. Recently, articles in this area will not be updated for the time being. The series of articles are summarized as follows:

Android startup optimization (1)-directed acyclic graph

Android startup optimization (two)-the principle of topological sorting and problem-solving ideas

Android startup optimization (3)-AnchorTask instructions

Android startup optimization (4)-teach you how to implement AnchorTask

Release Notes

  1. Pre-configured version prior to 0.1.0 dependent tasks, by AnchorTask getDependsTaskListthe way, he is through classNameto find AnchorTaskand cohesion in the current AnchorTask, from a global point of view, this approach is not very intuitive, 1.0.0 gave up ways, Ali reference Alphaway throughaddTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)
  2. 1.0.0 version adds Project class, and increase OnProjectExecuteListenerlistening
  3. New version 1.0.0 OnGetMonitorRecordCallbackmonitor, facilitate the statistics of each task takes

Description

Android startup optimization, you may think of asynchronous loading for the first time. Put time-consuming tasks on the sub-thread to load, and then enter the home page after all loading tasks are loaded.

The multi-threaded asynchronous loading scheme is indeed ok. But what if you encounter a dependency relationship. For example, task 2 depends on task 1. How to solve it at this time?

Suppose we have such task dependency

How do we use it

        val project =
            AnchorProject.Builder().setContext(context).setLogLevel(LogUtils.LogLevel.DEBUG)
                .setAnchorTaskCreator(ApplicationAnchorTaskCreator())
                .addTask(TASK_NAME_ZERO)
                .addTask(TASK_NAME_ONE)
                .addTask(TASK_NAME_TWO)
                .addTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)
                .addTask(TASK_NAME_FOUR).afterTask(TASK_NAME_ONE, TASK_NAME_TWO)
                .addTask(TASK_NAME_FIVE).afterTask(TASK_NAME_THREE, TASK_NAME_FOUR)
                .build()
        project.start().await()
复制代码
class ApplicationAnchorTaskCreator : IAnchorTaskCreator {
    override fun createTask(taskName: String): AnchorTask? {
        when (taskName) {
            TASK_NAME_ZERO -> {
                return AnchorTaskZero()
            }

            TASK_NAME_ONE -> {
                return AnchorTaskOne()
            }
            TASK_NAME_TWO -> {
                return AnchorTaskTwo()
            }
            TASK_NAME_THREE -> {
                return AnchorTaskThree()
            }
            TASK_NAME_FOUR -> {
                return AnchorTaskFour()
            }
            TASK_NAME_FIVE -> {
                return AnchorTaskFive()
            }
        }
        return null
    }

}
复制代码

When the demo runs, you can see the expected effect.

Basic use

Step 1: Configure remote dependencies in moulde build.gradle

implementation 'com.xj.android:anchortask:1.0.0'
复制代码

The latest version number can be found here lastedt version

Step two: custom AnchorTaskZero, inheritance AnchorTask, and specify taskName, attention taskNamemust be unique, because we will be in accordance with taskNamethe corresponding find AnchorTaskthe appropriate override method

class AnchorTaskZero() : AnchorTask(TASK_NAME_ZERO) {
    override fun isRunOnMainThread(): Boolean {
        return false
    }

    override fun run() {
        val start = System.currentTimeMillis()
        try {
            Thread.sleep(300)
        } catch (e: Exception) {
        }
        LogUtils.i(
            TAG, "AnchorTaskOne: " + (System.currentTimeMillis() - start)
        )
    }
}
复制代码

If task three depends on task two and task one, you can write like this

addTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)
复制代码

Finally, the project.start()method starts, if necessary block waiting, call await () method

AnchorProject.Builder().setContext(context).setLogLevel(LogUtils.LogLevel.DEBUG)
                .setAnchorTaskCreator(ApplicationAnchorTaskCreator())
                .addTask(TASK_NAME_ZERO)
                .addTask(TASK_NAME_ONE)
                .addTask(TASK_NAME_TWO)
                .addTask(TASK_NAME_THREE).afterTask(TASK_NAME_ZERO, TASK_NAME_ONE)
                .addTask(TASK_NAME_FOUR).afterTask(TASK_NAME_ONE, TASK_NAME_TWO)
                .addTask(TASK_NAME_FIVE).afterTask(TASK_NAME_THREE, TASK_NAME_FOUR)
                .build()
project.start().await()
复制代码

Monitor task callback

project.addListener(object : OnProjectExecuteListener {

            // project 开始执行的时候
            override fun onProjectStart() {
                com.xj.anchortask.LogUtils.i(MyApplication.TAG, "onProjectStart ")
            }

            // project 执行一个 task 完成的时候
            override fun onTaskFinish(taskName: String) {
                com.xj.anchortask.LogUtils.i(
                    MyApplication.TAG,
                    "onTaskFinish, taskName is $taskName"
                )
            }

            // project 执行完成的时候
            override fun onProjectFinish() {
                com.xj.anchortask.LogUtils.i(MyApplication.TAG, "onProjectFinish ")
            }

        })
复制代码

Add time-consuming callback for each task execution

project.onGetMonitorRecordCallback = object : OnGetMonitorRecordCallback {

            // 所有 task 执行完毕会调用这个方法,Map 存储了 task 的执行时间, key 是 taskName,value 是时间,单位毫秒
            override fun onGetTaskExecuteRecord(result: Map<String?, Long?>?) {
                onGetMonitorRecordCallback?.onGetTaskExecuteRecord(result)
            }

            // 所有 task 执行完毕会调用这个方法,costTime 执行时间
            override fun onGetProjectExecuteTime(costTime: Long) {
                onGetMonitorRecordCallback?.onGetProjectExecuteTime(costTime)
            }

        }
复制代码

AnchorProject introduction

  1. AnchorTaskDispatcher start The method must be called in the main thread, and the sub-thread calls will throw an exception.
  2. await Block the current thread, wait for all tasks to be executed, and then go down automatically, the await method carries a parameter, timeOutMillion represents the timeout waiting time
  3. await() Method must be called after the start method
  4. Add a task by AnchorProject.Builder().addTaskadding a typical configuration mode
  5. Set the thread pool for execution, you can pass AnchorProject.Builder().setThreadPoolExecutor(TaskExecutorManager.instance.cpuThreadPoolExecutor)

Introduction to AnchorTask

AnchorTask implements the IAnchorTask interface, there are several main methods

  • isRunOnMainThread(): BooleanIndicates whether to run on the main thread, the default value is false
  • priority(): Int The method indicates the priority level of the thread, the default value is Process.THREAD_PRIORITY_FOREGROUND
  • needWait()Means that when we call AnchorTaskDispatcher awaitupon, whether to wait, return true, expressed the need to wait for the end to change the task execution, AnchorTaskDispatcher awaitthe method can continue down the implementation.
  • fun run() Method, which means when the task is executed
interface IAnchorTask : IAnchorCallBack {

    /**
     * 是否在主线程执行
     */
    fun isRunOnMainThread(): Boolean

    /**
     * 任务优先级别
     */
    @IntRange(
        from = Process.THREAD_PRIORITY_FOREGROUND.toLong(),
        to = Process.THREAD_PRIORITY_LOWEST.toLong()
    )
    fun priority(): Int

    /**
     * 调用 await 方法,是否需要等待改任务执行完成
     * true 不需要
     * false 需要
     */
    fun needWait(): Boolean

    /**
     * 任务被执行的时候回调
     */
    fun run()

}
复制代码
class AnchorTaskOne : AnchorTask() {
    override fun isRunOnMainThread(): Boolean {
        return false
    }

    override fun run() {
        val start = System.currentTimeMillis()
        try {
            Thread.sleep(300)
        } catch (e: Exception) {
        }
        LogUtils.i(
            TAG, "AnchorTaskOne: " + (System.currentTimeMillis() - start)
        )
    }

}
复制代码

The callback of the monitoring task

val anchorTask = AnchorTaskTwo()
        anchorTask.addCallback(object : IAnchorCallBack {
            override fun onAdd() {
                com.xj.anchortask.LogUtils.i(TAG, "onAdd: $anchorTask")
            }

            override fun onStart() {
                com.xj.anchortask.LogUtils.i(TAG, "onStart:$anchorTask ")
            }

            override fun onFinish() {
                com.xj.anchortask.LogUtils.i(TAG, "onFinish:$anchorTask ")
            }

        })
复制代码

to sum up

The principle of AnchorTask is not complicated, and the essence is the combination of directed acyclic graph and multithreaded knowledge.

  1. Construct a directed acyclic graph according to BFS, and get its topological sort
  2. In the process of multi-threaded execution, we ensure the sequential execution relationship through the task's sub-task relationship and CounDownLatch
    1. If the predecessor task has not been executed, wait, if the execution is completed, go down
    2. Perform task
    3. Notify the subtask that the current task is completed, and the corresponding counter (in degrees) should be reduced by one.

More android development welcome to join our Android advanced learning circle

Guess you like

Origin blog.csdn.net/weixin_43901866/article/details/114371517