DSAppTeam / Anchors

:white_check_mark: Anchors 是一个基于图结构,支持同异步依赖任务初始化 Android 启动框架。其锚点提供 "勾住" 依赖的功能,能灵活解决初始化过程中复杂的同步问题。参考 alpha 并改进其部分细节, 更贴合 Android 启动的场景, 同时支持优化依赖初始化流程, 自动选择较优的路径进行初始化。
Apache License 2.0
820 stars 79 forks source link
android starter startup

Anchors

图片名称

Language Language

README: English | 中文

new version update

Introduction

Anchors is a graph-based structure that supports the asynchronous startup task to initialize the Android startup framework. Its anchor provides a "hook" dependency function that provides flexibility in solving complex synchronization problems during initialization. Refer to alpha and improve some of its details, which is more suitable for Android-initiated scenarios. It also supports optimizing the dependency initialization process and selecting a better path for initialization.

For the thinking about alpha, please see 关于Android异步启动框架alpha的思考

Advantages over alpha

Need to know

  1. Anchors are designed for efficient and convenient completion of complex initialization tasks when the app is launched, not for initializing certain dependencies in business logic.
  2. Setting the anchor in the api will block and wait until the anchor is completed before continuing to walk the code block after AnchorsManager # start. The reason why the application can handle this is because there are no frequent UI operations. The tasks after the anchor will be autonomously scheduled by the framework, the synchronous tasks will be sent to the main thread for processing via handler # post, and the asynchronous tasks will be driven by the thread pool in the framework.
  3. The wait function is used in scenarios where anchor is not set. If anchor is set, the waiting task should be placed behind the anchor to avoid uiThead blocking.
  4. In combination with the asynchronous hybrid chain and anchor function, it can flexibly handle many complex initialization scenarios, but it is necessary to fully understand the thread background when using the function.

Use

  1. Add the JitPack repository to the project root path, and no longer use JCenter

    allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }
  2. Add dependencies under the app module

    implementation 'com.github.DSAppTeam:Anchors:v1.1.8'
  3. Add dependency graph and start

    The framework supports java and kotlin languages. For the two languages, JDatas is built in the Demo to implement the java scene logic, and the Datas class is used to implement the kotlin logic. The start-up dependency set is received in the form of a "graph", and the link to the construction node of the graph is realized.

     ==>  Take java as an example, the code can refer to the JDatas class
    
     To construct a task, the first parameter specifies the name and unique id, and the second parameter specifies whether the task runs asynchronously
     Task task = new Task("name",false) {
         @Override
         protected void run(@NotNull String s) {
             //todo
         }
     };
    
     Build a Project. Project is a Task subclass, used to describe multiple Task scenarios. Because of the use of <TaskName> to build, pass a factory for unified processing
     The following constructs the logic of task1 <- task2 <- task3 <- task4, A -> B means A depends on B
     TestTaskFactory testTaskFactory = new TestTaskFactory();
     Project.Builder builder = new Project.Builder("name", testTaskFactory);
     builder9.add("task1Name");
     builder9.add("task2Name").dependOn("task1Name");
     builder9.add("task3Name").dependOn("task2Name");
     builder9.add("task4Name").dependOn("task4Name");
     Project project = builder.build();
    
     Combination, in fact, the above project#dependOn is a combination method
     project.dependOn(task);
         ...
     You can build a dependency graph through various combinations, and then call start to pass the graph head node to start
     AnchorsManager.getInstance()
         .start(task);
    
     When debugging is needed
     AnchorsManager.getInstance()
         .debuggable(true)
         .start(task);
    
     When the anchor needs to be set, <anchorYouNeed> represents some tasks, and these tasks need to be guaranteed to be initialized before the end of Application#onCreate
     AnchorsManager.getInstance()
         .addAnchors(anchorYouNeed)
         .start(task);
    
     For some scenarios, you may need to monitor the running status of a task, you can use the block blocking function. After blocking and waiting, you can release/destroy the waiting according to the business logic. WaitTaskYouNeed is the task you need to wait for
     AnchorsManager anchorsManager = AnchorsManager.getInstance();
     LockableAnchor lockableAnchor = anchorsManager.requestBlockWhenFinish(waitTaskYouNeed); 
     lockableAnchor.setLockListener(...){
         //lockableAnchor.unlock() Release the waiting and continue the task chain
         //lockableAnchor.smash() Destroy waiting and terminate the task chain
     }
     anchorsManager.start(task);
    
     ==> koltin also supports all the above processes, and also provides a dsl build form to build a dependency graph, the code can refer to the Datas class
     Describe a dependency graph by calling the graphics method, use <TaskName> to build, and pass a factory for unified processing
     AnchorsManager.getInstance()
         .debuggable { true }
         .taskFactory { TestTaskFactory() }     //The factory that generates task according to id
         .anchors { arrayOf(TASK_93, TASK_10) } //task id corresponding to anchor
         .block("TASK_10000") {                // The task id of the block scene and the lambda that handles the monitoring
             //According to business  it.smash() or it.unlock()
         }
         .graphics {                                  // Build dependency graph
             UITHREAD_TASK_A.sons(
                     TASK_10.sons(
                             TASK_11.sons(
                                     TASK_12.sons(
                                             TASK_13))),
                     TASK_20.sons(
                             TASK_21.sons(
                                     TASK_22.sons(TASK_23))),
    
                     UITHREAD_TASK_B.alsoParents(TASK_22),
    
                     UITHREAD_TASK_C
             )
             arrayOf(UITHREAD_TASK_A)
         }
         .startUp()
     Where anchorYouNeed is the anchor you need to add, waitTaskYouNeed is the task you need to wait for, and dependencyGraphHead is the head of the dependency graph.

Sample

For code logic, please refer to the sample case under the app module.

The following describes the main scenarios involved in the demo.

Debug information

debuggale mode can print logs of different dimensions as debugging information output, and do Trace tracking for each dependent task. You can output trace.html for performance analysis by python systrace.py .

Anchors defines different TAG for filtering logs, you need to open Debug mode.

Effect comparison

Below is the execution time given by Trace without using anchor points and using anchor points in the scene

图片名称

The dependency graph has a UITHREAD_TASK_A -> TASK_90 -> TASK_92 -> Task_93 dependency. Assuming that our dependency path is a precondition for subsequent business, we need to wait for the business to complete before proceeding with its own business code. If not then we don't care about their end time. When using the anchor function, we hook TASK_93, and the priority from the beginning to the anchor will be raised. As you can see from the above figure, the time to execute the dependency chain is shortened.

The dependency graph is used to resolve the dependencies between tasks when the task is executed, and the anchor setting is used to resolve the synchronization relationship between the execution dependencies and the code call points.

Expectation

The project was written only to improve the efficiency of day-to-day development and focus on the business. If you have a better practice or suggestions, please write to yummyl.lau@gmail.com, ask Issues or initiate Pull requests, any problems will be resolved in the first time.