Code Monkey home page Code Monkey logo

dsappteam / anchors Goto Github PK

View Code? Open in Web Editor NEW
817.0 12.0 79.0 5.25 MB

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

License: Apache License 2.0

Java 99.60% Kotlin 0.40%
android starter startup

anchors's Introduction

Anchors

图片名称

Language Language

README: English | 中文

new version update

  • 1.0.2 (2019/06/14) Added support for directly opening the project node
  • 1.0.3 (2019/12/11) Added support for node wait function
  • 1.0.4 (2019/12/31) Optimize the online feedback of multi-thread synchronization to notify the next node to start
  • 1.0.5 (2020/01/20) Added demo scenarios such as node release monitoring entry, multi-process / wait / restart new chain, etc. (see Sample example)
  • 1.1.0 (2020/05/13) Support kotlin and DSL features
  • 1.1.1 (2020/07/31) Optimize the DSL block API
  • 1.1.2 (2020/10/08) Optimize the traversal speed of the dependency tree, and fix the problem that the Log-TASK_DETAIL dependency task has no information.
  • 1.1.3 (2020/11/10) Support multiple block nodes, AnchorManager is no longer open as a singleton, supports custom thread pool, taskListener supports DSL selective coverage method
  • 1.1.4 (2021/04/28) Optimize log and optimize multi-threaded scenarios
  • 1.1.5 (2022/06/09) Optimize multi-threaded scenarios
  • 1.1.6 (2022/06/14) Support dynamic cutting of subsequent task chains
  • 1.1.7 (2022/07/19) Fix java.lang.UnsupportedOperationException for apps running on and targeting Android versions lower than Oreo (API level < 26)
  • 1.1.8 (2022/11/22) Fix java.lang.IllegalArgumentException

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

  • Support to configure anchors to wait for the task chain. It is often used before application # onCreate to ensure that some initialization tasks are completed before entering the activity lifecycle callback.
  • Supports active request blocking waiting tasks, which are commonly used for certain initialization tasks on the task chain that require user logic confirmation.
  • Supports synchronous and asynchronous task chains

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.

  • Multi-process initialization

    SampleApplication.class is implemented for multiple processes to meet most initialization scenarios. SampleApplication#onCreate will be called again when the business involving the new process is started, so the initialization scenarios for different processes can be customized based on the process name. The code can refer to the SampleApplication#initDependenciesCompatMultiProcess method. Reer to MainActivity#testPrivateProcess or MainActivity#testPublicProcess for triggering a new process.

  • An intermediate node in an initialization chain needs to wait for a response

    Some very demanding initialization chains may need to wait for certain conditions. (Note: The response here should be the response of the UI thread. If it is an asynchronous response, it can be actively initialized in advance as a node). Scenarios such as some apps require the user to select the "Interest Scenario" when initializing, and then initialize all logic of subsequent pages. The code can refer to MainActivity#testUserChoose .

  • After an initialization chain is completed, another new chain may be started

    This kind of function is also supported, but in fact the framework advocates unified management of all initialization chains in the application.Because the framework emphasizes that arbitrary initialization tasks should be business heavyweight initialization code or third-party SDK init . The code can refer to MainActivity#testRestartNewDependenciesLink.

  • The subsequent task chain needs to be modified according to the running result of a certain task

    When defining a task, you can override Task#modifySons to obtain the follow-up tasks of the current task, and you can return a new follow-up task id list after cutting according to your needs. (Note: It can only be deleted in the original task chain and cannot be added). The code can refer to MainActivity#testCutoutTask.

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.

  • Anchors, The most basic TAG

  • TASK_DETAIL, Filter details of dependent tasks

     2019-03-18 14:19:45.687 22493-22493/com.effective.android.sample D/TASK_DETAIL: TASK_DETAIL
     ======================= task (UITHREAD_TASK_A ) =======================
     | 依赖任务 :
     | 是否是锚点任务 : false
     | 线程信息 : main
     | 开始时刻 : 1552889985401 ms
     | 等待运行耗时 : 85 ms
     | 运行任务耗时 : 200 ms
     | 结束时刻 : 1552889985686
     ==============================================
    
  • ANCHOR_DETAIL, Filter output anchor task information

     2019-03-18 14:42:33.354 24719-24719/com.effective.android.sample W/ANCHOR_DETAIL: anchor "TASK_100" no found !
     2019-03-18 14:42:33.354 24719-24719/com.effective.android.sample W/ANCHOR_DETAIL: anchor "TASK_E" no found !
     2019-03-18 14:42:33.355 24719-24719/com.effective.android.sample D/ANCHOR_DETAIL: has some anchors!( "TASK_93" )
     2019-03-18 14:42:34.188 24719-24746/com.effective.android.sample D/ANCHOR_DETAIL: TASK_DETAIL
     ======================= task (TASK_93 ) =======================
     | 依赖任务 : TASK_92
     | 是否是锚点任务 : true
     | 线程信息 : Anchors Thread #7
     | 开始时刻 : 1552891353984 ms
     | 等待运行耗时 : 4 ms
     | 运行任务耗时 : 200 ms
     | 结束时刻 : 1552891354188
     ==============================================
     2019-03-18 14:42:34.194 24719-24719/com.effective.android.sample D/ANCHOR_DETAIL: All anchors were released!
    
  • LOCK_DETAIL, 过滤输出等待信息

     2019-12-11 14:53:11.784 6183-6437/com.effective.android.sample D/LOCK_DETAIL: Anchors Thread #9- lock( TASK_10 )
     2019-12-11 14:53:13.229 6183-6183/com.effective.android.sample D/LOCK_DETAIL: main- unlock( TASK_10 )
     2019-12-11 14:53:13.229 6183-6183/com.effective.android.sample D/LOCK_DETAIL: Continue the task chain...
     
    
  • DEPENDENCE_DETAIL, Filter dependency graph information

     2019-03-18 14:27:53.724 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_9_start(1552890473721) --> TASK_90 --> TASK_91 --> PROJECT_9_end(1552890473721)
     2019-03-18 14:27:53.724 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_9_start(1552890473721) --> TASK_90 --> TASK_92 --> TASK_93 --> PROJECT_9_end(1552890473721)
     2019-03-18 14:27:53.724 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_8_start(1552890473721) --> TASK_80 --> TASK_81 --> PROJECT_8_end(1552890473721)
     2019-03-18 14:27:53.724 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_8_start(1552890473721) --> TASK_80 --> TASK_82 --> TASK_83 --> PROJECT_8_end(1552890473721)
     2019-03-18 14:27:53.725 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_7_start(1552890473720) --> TASK_70 --> TASK_71 --> PROJECT_7_end(1552890473720)
     2019-03-18 14:27:53.725 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_7_start(1552890473720) --> TASK_70 --> TASK_72 --> TASK_73 --> PROJECT_7_end(1552890473720)
     2019-03-18 14:27:53.725 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_6_start(1552890473720) --> TASK_60 --> TASK_61 --> PROJECT_6_end(1552890473720)
     2019-03-18 14:27:53.725 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_6_start(1552890473720) --> TASK_60 --> TASK_62 --> TASK_63 --> PROJECT_6_end(1552890473720)
     2019-03-18 14:27:53.725 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_5_start(1552890473720) --> TASK_50 --> TASK_51 --> PROJECT_5_end(1552890473720)
     2019-03-18 14:27:53.725 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_5_start(1552890473720) --> TASK_50 --> TASK_52 --> TASK_53 --> PROJECT_5_end(1552890473720)
     2019-03-18 14:27:53.725 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_4_start(1552890473720) --> TASK_40 --> TASK_41 --> TASK_42 --> TASK_43 --> PROJECT_4_end(1552890473720)
     2019-03-18 14:27:53.726 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_3_start(1552890473720) --> TASK_30 --> TASK_31 --> TASK_32 --> TASK_33 --> PROJECT_3_end(1552890473720)
     2019-03-18 14:27:53.726 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_2_start(1552890473719) --> TASK_20 --> TASK_21 --> TASK_22 --> TASK_23 --> PROJECT_2_end(1552890473719)
     2019-03-18 14:27:53.726 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> PROJECT_1_start(1552890473719) --> TASK_10 --> TASK_11 --> TASK_12 --> TASK_13 --> PROJECT_1_end(1552890473719)
     2019-03-18 14:27:53.726 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> UITHREAD_TASK_B
     2019-03-18 14:27:53.726 22843-22843/com.effective.android.sample D/DEPENDENCE_DETAIL: UITHREAD_TASK_A --> UITHREAD_TASK_C
    

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 [email protected], ask Issues or initiate Pull requests, any problems will be resolved in the first time.

anchors's People

Contributors

hongdouhub avatar linyyy avatar xfront avatar yummylau avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

anchors's Issues

AnchorsManager#start()`的线程阻塞写法

AnchorsManager#start()的线程阻塞写法

while (AnchorsRuntime.hasAnchorTasks()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (AnchorsRuntime.hasRunTasks()) {
                AnchorsRuntime.tryRunBlockRunnable();
            }
        }

改成下面这样,会不会更好呢?会不会有问题呢

while (AnchorsRuntime.hasAnchorTasks()) {
            try {
               synchronized (mLock){
                   mLock.wait(10);
               }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (AnchorsRuntime.hasRunTasks()) {
                AnchorsRuntime.tryRunBlockRunnable();
            }
        }

请问一定要形成图吗?

不可以有一些任务是单独运行的,有一些是有依赖关系的吗?
单看API感觉是一定要有依赖关系,感觉有点强迫了。
个人感觉,API设计的有些复杂了,不是很容易上手。

removeAnchorTask 疑问

static void removeAnchorTask(String id) {
    if (!TextUtils.isEmpty(id)) {
        sAnchorTaskIds.remove(id);
    }
}

这个方法会多个线程调用,感觉存在线程安全问题

AnchorsRuntime.kt line 106 com.effective.android.anchors.AnchorsRuntime.tryRunBlockTask$anchors_release

此问题引发了 2 次 ANR 事件,影响了 2 位用户
设备
品牌:samsung
型号:Galaxy A52s 5G
屏幕方向: 未知
可用 RAM: Unknown
可用磁盘空间: Unknown
操作系统
版本:Android 12
屏幕方向: 未知
是否已取得 root 权限:否
ANR
日期:2022年11月9日 04:51:42
main (waiting):tid=1 systid=14263
at java.lang.Object.wait(Native method)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at com.effective.android.anchors.AnchorsRuntime.tryRunBlockTask$anchors_release(AnchorsRuntime.kt:106)
at com.effective.android.anchors.AnchorsManager.start(AnchorsManager.kt:111)
at com.包名.view.BaseApplication.onCreate(BaseApplication.java:189)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1211)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7506)
at android.app.ActivityThread.access$1600(ActivityThread.java:310)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2281)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8669)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)

Signal Catcher (runnable):tid=6 systid=14272
#00 pc 0x53a6e0 libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits >&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool) + 128)
#1 pc 0x6f0e04 libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits >&, bool, BacktraceMap*, bool) const + 236)
#2 pc 0x6fe690 libart.so (art::DumpCheckpoint::Run(art::Thread*) + 208)
#3 pc 0x364248 libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*) + 440)
#4 pc 0x6fce30 libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits >&, bool) + 280)
#5 pc 0x6fc824 libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits >&) + 292)
#6 pc 0x6d5974 libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits >&) + 184)
#7 pc 0x6e1994 libart.so (art::SignalCatcher::HandleSigQuit() + 468)
#8 pc 0x574230 libart.so (art::SignalCatcher::Run(void*) + 264)
#9 pc 0xb6d54 libc.so (__pthread_start(void*) + 264)
#10 pc 0x53370 libc.so (__start_thread + 68)

Jit thread pool worker thread 0 (native):tid=7 systid=14276
#00 pc 0x4dd70 libc.so (syscall + 32)
#1 pc 0x47cc80 libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*) + 140)
#2 pc 0x47cb18 libart.so (art::ThreadPool::GetTask(art::Thread*) + 120)
#3 pc 0x6199a4 libart.so (art::ThreadPoolWorker::Run() + 72)
#4 pc 0x6198c4 libart.so (art::ThreadPoolWorker::Callback(void*) + 160)
#5 pc 0xb6d54 libc.so (__pthread_start(void*) + 264)
#6 pc 0x53370 libc.so (__start_thread + 68)

ReferenceQueueDaemon (waiting):tid=8 systid=14278
at java.lang.Object.wait(Native method)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:232)
at java.lang.Daemons$Daemon.run(Daemons.java:140)
at java.lang.Thread.run(Thread.java:1012)

Binder:14263_1 (native):tid=9 systid=14281
#00 pc 0xa1fbc libc.so (__ioctl + 12)
#1 pc 0x5b988 libc.so (ioctl + 156)
#2 pc 0x46070 libbinder.so (android::IPCThreadState::talkWithDriver(bool) + 292)
#3 pc 0x46360 libbinder.so (android::IPCThreadState::getAndExecuteCommand() + 28)
#4 pc 0x46c98 libbinder.so (android::IPCThreadState::joinThreadPool(bool) + 72)
#5 pc 0x6e51c libbinder.so (android::PoolThread::threadLoop() + 384)
#6 pc 0x1358c libutils.so (android::Thread::_threadLoop(void*) + 264)
#7 pc 0xc0564 libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*) + 148)
#8 pc 0x12de8 libutils.so (thread_data_t::trampoline(thread_data_t const*) + 408)
#9 pc 0xb6d54 libc.so (__pthread_start(void*) + 264)
#10 pc 0x53370 libc.so (__start_thread + 68)

任务分支

如果有2种场景 :
taskA--->taskB--->taskC--->taskD--->taskE
taskA--->taskB--->taskC--->taskF--->taskG
能否taskC内根据任务结果进行任务分支切换?类似branchTaskC

java.lang.IllegalStateException: rhs must not be null

java.lang.RuntimeException: Unable to create application com.stub.StubApp: java.lang.IllegalStateException: rhs must not be null
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5758)
at android.app.ActivityThread.-wrap1(ActivityThread.java:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1659)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6518)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.IllegalStateException: rhs must not be null
at com.effective.android.anchors.AnchorsRuntime$taskComparator$1.compare(AnchorsRuntime.java:38)
at com.effective.android.anchors.AnchorsRuntime$taskComparator$1.compare(AnchorsRuntime.java:23)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.util.TimSort.sort(TimSort.java:220)
at java.util.Arrays.sort(Arrays.java:1498)
at java.util.ArrayList.sort(ArrayList.java:1470)
at java.util.Collections.sort(Collections.java:201)
at com.effective.android.anchors.AnchorsRuntime.tryRunBlockRunnable(AnchorsRuntime.java:92)
at com.effective.android.anchors.AnchorsManager.start(AnchorsManager.java:106)
at com.xxx.xxx.MainApplication.onCreate(MainApplication.java:167)
at com.stub.StubApp.onCreate(StubApp.java:118)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1120)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5755)
... 8 more

组件化中使用 报has no any anchor!

在lib _common 公共库中集成Anchors 并且在baseApplication 中初始化,然后再别的module 中引用lib _common,无法初始化,比如将ARouter 得初始化直接写在baseApplication 中就能正常初始化

循环依赖是怎么避免的?

看到有这么一段注释

 * project 的构建内部,避免了回环的发生。
 * 当出现project 内 task 循环依赖是,循环依赖会自动断开。

是怎么做到依赖自动断开的呢?
顺便想问一下,
如果使用如下build构建
builder1.add(TASK_11).dependOn(TASK_10);
builder1.add(TASK_12).dependOn(TASK_11);
builder1.add(TASK_13).dependOn(TASK_12);

从startTask就只能运行 START->FINISH 两个task

主线程Sleep 造成ANR

    implementation 'com.github.YummyLau:Anchors:v1.1.4'

主线程Sleep,其他线程中没有以 Anchors Thread # 开头的线程

主线程调用栈
  at java.lang.Thread.sleep (Native method)
  at java.lang.Thread.sleep (Thread.java:442)
  at java.lang.Thread.sleep (Thread.java:358)
  at com.effective.android.anchors.AnchorsRuntime.tryRunBlockTask$anchors_release (AnchorsRuntime.java:92)
  at com.effective.android.anchors.AnchorsManager.start (AnchorsManager.java:111)

首次安装耗时10秒以上

从Application.onCreate方法来看,使用Achors后,运行速度提升700ms左右,但是release包跑monkey测试,大部分机型安装后首次冷启动,速度在10s以上,后续冷启动速度均比较快。而优化前的release包并没有存在该问题,首次冷启动与后续冷启动速度相同。这个是什么原因导致的?

Caused by: java.lang.IllegalArgumentException

Caused by: java.lang.IllegalArgumentException
at java.util.concurrent.ThreadPoolExecutor.(ThreadPoolExecutor.java:1302)
at java.util.concurrent.ThreadPoolExecutor.(ThreadPoolExecutor.java:1224)
at com.effective.android.anchors.AnchorThreadPool.(AnchorThreadPool.kt:29)
at com.effective.android.anchors.AnchorsRuntime.(AnchorsRuntime.kt:51)
at com.effective.android.anchors.AnchorsManager.(AnchorsManager.kt:28)
at com.effective.android.anchors.AnchorsManager.(AnchorsManager.kt:19)
at com.effective.android.anchors.AnchorsManager$Companion.getInstance(AnchorsManager.kt:35)
at com.effective.android.anchors.AnchorsManager$Companion.getInstance$default(AnchorsManager.kt:34)
at com.effective.android.anchors.AnchorsManager.getInstance(Unknown Source:4)

耗时任务超过10秒

耗时某个任务超过10秒,这个框架在某些手机上有问题。
1.启动app,在任务没有完成情况下,手动杀死app。
2.重新启动app,直接崩溃

任务额外耗时问题

我发现执行一个Task的时候,整个执行流程会比Task本身多花费几十到100多ms, 这对于总共也就耗时不到1s的若干Task,速度提升不明显,请问是什么原因导致,能避免吗?

组件化

能不能每个组件初始化自己的,然后app启动的时候把所有组件的初始化整合一起重新排列去选择最优的初始化方式

ANR ,AnchorsRuntime.tryRunBlockTask$anchors_release ANR triggered by main thread waiting for too long

main (waiting):tid=1 systid=9911
at java.lang.Object.wait(Native method)
at java.lang.Object.wait(Object.java:442)
at java.lang.Object.wait(Object.java:568)
at com.effective.android.anchors.AnchorsRuntime.tryRunBlockTask$anchors_release(AnchorsRuntime.kt:106)
at com.effective.android.anchors.AnchorsManager.start(AnchorsManager.kt:111)
at com.chiquedoll.chiquedoll.view.BaseApplication.onCreate(BaseApplication.java:134)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1193)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6921)
at android.app.ActivityThread.access$1400(ActivityThread.java:244)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1931)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7888)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:981)

支持可选任务场景

目前场景是图上所有路径都会执行,能否支持这么一种场景,只支持图中某一条路径,因为实际场景中,比如游戏等级,如果你选了不同难度级别,中间碰到的难关是不一样的,选择高难度看到的怪物是不一样,中级难度掉落物品也会不一样,低级难度获取经验更少,甚至中间不同的任务执行也会不一样,如果该场景支持,该库的普及度会更广。

Originally posted by @lispking in #9 (comment)

反馈一个问题,从1.1.4升级到1.1.6,在OPPO R9s上出现崩溃。

机器: OPPO R9s,Android 6

Caused by: java.lang.UnsupportedOperationException
at java.util.concurrent.CopyOnWriteArrayList$CowIterator.set(CopyOnWriteArrayList.java:748)
at java.util.Collections.sort(Collections.java:1909)
at com.effective.android.anchors.task.Task.notifyBehindTasks(Task.kt:235)
at com.effective.android.anchors.task.Task.run(Task.kt:73)
at com.effective.android.anchors.AnchorsRuntime.tryRunBlockTask$anchors_release(AnchorsRuntime.kt:115)
at com.effective.android.anchors.AnchorsManager.start(AnchorsManager.kt:111)
at com.effective.android.anchors.AnchorsManagerKt.startUp(AnchorsManager.kt:279)
at com.jelenew.app.startup.StartupHelper.startup(StartupHelper.kt:13)
at com.jelenew.app.JelenewApplication.onCreate(JelenewApplication.kt:16)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1014)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4995)

java.util.ConcurrentModificationException

AnchorsRuntime#runBlockTask 存在多线程操作问题,tryRunBlockRunnable 主线程操作 addRunTasks 在主线程和工作现场都会操作,导致多线程问题。

Caused by: java.util.ConcurrentModificationException at java.util.ArrayList.sort(ArrayList.java:1472) at java.util.Collections.sort(Collections.java:201) at com.effective.android.anchors.AnchorsRuntime.tryRunBlockRunnable$anchors_release(AnchorsRuntime.kt:3) at com.effective.android.anchors.AnchorsManager.start(AnchorsManager.kt:17)

依赖关系不明朗的情况?

依赖关系不是很明确的情况,不太好处理?

比如广告SDK依赖OAID的获取,但是OAID获取时间比较耗时。可以在获取一次之后就保存下来,下次直接从本地读取数据就行,就不用依赖这个获取OAID的方法了,还能够提高启动速度。

这种情况,算是依赖吗?

AnchorThreadPool.kt line 29 com.effective.android.anchors.AnchorThreadPool.<init>

设备
品牌:LGE
型号:Nexus 5X
屏幕方向: 纵向
可用 RAM: 3.2 GB
可用磁盘空间: 2.49 GB
操作系统
版本:Android 6.0.1
屏幕方向: 纵向
是否已取得 root 权限:是
崩溃
日期:2022年11月22日 01:41:02

SDK为最新的版本号
Fatal Exception: java.lang.RuntimeException: Unable to create application 包名.view.BaseApplication: java.lang.IllegalArgumentException
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4714)
at android.app.ActivityThread.-wrap1(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5421)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Caused by java.lang.IllegalArgumentException:
at java.util.concurrent.ThreadPoolExecutor.(ThreadPoolExecutor.java:1278)
at java.util.concurrent.ThreadPoolExecutor.(ThreadPoolExecutor.java:1201)
at com.effective.android.anchors.AnchorThreadPool.(AnchorThreadPool.kt:29)
at com.effective.android.anchors.AnchorsRuntime.(AnchorsRuntime.kt:51)
at com.effective.android.anchors.AnchorsManager.(AnchorsManager.kt:28)
at com.effective.android.anchors.AnchorsManager.(AnchorsManager.kt:19)
at com.effective.android.anchors.AnchorsManager$Companion.getInstance(AnchorsManager.kt:35)
at com.effective.android.anchors.AnchorsManager$Companion.getInstance$default(AnchorsManager.kt:34)
at com.effective.android.anchors.AnchorsManager.getInstance(AnchorsManager.kt)
at 包名view.BaseApplication.onCreate(BaseApplication.java:173)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1013)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4711)
at android.app.ActivityThread.-wrap1(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5421)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

代码:
//延时加载
AnchorsManager.getInstance()
.debuggable(BuildConfig.DEBUG)
//设置锚点
.addAnchor(InitCaocConfig.TASK_ID,
InitMNCrashMonitor.TASK_ID,
InitAppsFlyer.TASK_ID,
InitFrontBack.TASK_ID,
InitFaceBook.TASK_ID,
InitAdId.TASK_ID,
InitKlarna.TASK_ID,
InitToast.TASK_ID
, InitForterPay.TASK_ID,
InitSmartRefreshLayout.TASK_ID

                    )
                    .start(new Project.Builder("chicmeapp", new AppTaskSdkFactory())
                            .add(InitCaocConfig.TASK_ID)
                            .add(InitMNCrashMonitor.TASK_ID)
                            .add(InitAppsFlyer.TASK_ID)
                            .add(InitFrontBack.TASK_ID)
                            .add(InitFaceBook.TASK_ID)
                            .add(InitAdId.TASK_ID)
                            .add(InitKlarna.TASK_ID)
                            .add(InitToast.TASK_ID)
                            .add(InitForterPay.TASK_ID)
                            .add(InitSmartRefreshLayout.TASK_ID)
                            .build()
                    );

动态权限申请要考虑吗

项目中用到了动态权限申请,在申请成功之后的回调里,有SDK的初始化逻辑。
问题:
1,请问这个动态权限申请能封装成任务吗?看代码,动态权限申请,要添加各种回调,还跟Activity的onRequestPermissionsResult回调有关。目前感觉不太好封装。
2,假设动态权限能封装成任务,那申请成功回调中的SDK初始化逻辑,和他算是依赖关系吗?

初始化依赖问题

你好,如果我想把一些公共初始化下沉到common层,然后在common层的application启动初始化任务。现在需要在Application中初始化相应task。但是这个task一定需要等待common中某些task初始化完成才可以继续进行,请问这个场景你有什么建议方式呢?

带有异步回调的方法被设定为锚定时无法运行到回调中

我有一段初始化代码,他本身没有同步方法,所以我用 CountDownLatch 去把它转变为同步的方法,在未把该任务设为锚定时这段运行完全没有问题,可以达到预期的效果,但当我把它设为锚定点时,运行后就无法再走到回调里了。

private static class TestTask extends Task {

        private final CountDownLatch countDownLatch = new CountDownLatch(1);

        TestTask() {
            super(TASK_TEST, true);
        }

        @Override
        protected void run(String name) {
            mTest.runAsync(mContext, new CallBack() {
                @Override
                public void callback() {
                    countDownLatch.countDown();
                }
            });
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
`

请求更新一份用法讲解的文档

Hi~~我下载了Demo想试着加到自己的项目里,发现Anchors库的用法有些看不懂。
比如 getInstance().taskFactory { TestTaskFactory() }.anchors { arrayOf(TASK_93, "TASK_E", TASK_10) }
的anchors是做什么用的呢?
追踪代码发现它在AnchorsManager.startUp()中把anchors: MutableList添加到了AnchorsManager.anchorTaskIds: MutableSet中,除了有一处clear(),都没有从列表中取出过,
那要它干什么呢?

还有相比alpha库的新功能Application.onCreate()能卡住等待初始化完成,我也没搞懂怎么用。

希望您能更新一下用法讲解文档。

java.lang.IllegalArgumentException

java.lang.IllegalArgumentException
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6784)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2132)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7892)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
//use sdk version: com.github.YummyLau:Anchors:v1.1.4

demo 代码报错


       Project.Builder builder1 = new Project.Builder(PROJECT_1, testTaskFactory);
        builder1.add(TASK_10);
        builder1.add(TASK_11).dependOn(TASK_10);
        builder1.add(TASK_12).dependOn(TASK_11);
        builder1.add(TASK_13).dependOn(TASK_12);
        Project project1 = builder1.build();

        AnchorsManager.getInstance().debuggable(true)
                .addAnchors(TASK_10)
                .start(project1);

start()方法如果传入的是project对象。那么运行起来会有报空指针,日志如下:

Attempt to invoke virtual method 'android.util.SparseArray com.effective.android.anchors.TaskRuntimeInfo.getStateTime()' on a null object reference
        at com.effective.android.anchors.LogTaskListener.logTaskRuntimeInfoString(LogTaskListener.java:28)
        at com.effective.android.anchors.LogTaskListener.onFinish(LogTaskListener.java:23)
        at com.effective.android.anchors.Task.toFinish(Task.java:140)
        at com.effective.android.anchors.Task.run(Task.java:101)

缺少任务暂停机制支持

看代码实现 ,貌似没办法支持任务暂停机制,实际上,有一些场景需要弹窗,等用户确认后才继续往后运行,取消后中断后续任务或继续运行。

java.lang.RuntimeException: can no run task task-lock again!

implementation 'com.effective.android:anchors:1.1.3'
这个问题是什么原因?
java.lang.RuntimeException: can no run task task-lock again!
at com.effective.android.anchors.task.Task.start(SourceFile:6)
at com.effective.android.anchors.task.Task.dependTaskFinish(SourceFile:5)
at com.effective.android.anchors.task.Task.notifyBehindTasks(SourceFile:7)
at com.effective.android.anchors.task.Task.run(SourceFile:6)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:263)
at android.app.ActivityThread.main(ActivityThread.java:8288)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)

java.lang.NullPointerException: Attempt to invoke interface method 'void java.lang.Runnable.run()' on a null object reference

java.lang.RuntimeException:Unable to create application com.stub.StubApp: java.lang.NullPointerException: Attempt to invoke interface method 'void java.lang.Runnable.run()' on a null object reference

2 android.app.ActivityThread.handleBindApplication(ActivityThread.java:6637)
3 ......
4 Caused by:
5 java.lang.NullPointerException:Attempt to invoke interface method 'void java.lang.Runnable.run()' on a null object reference
6 com.effective.android.anchors.e.g(AnchorsRuntime.kt:87)
7 com.effective.android.anchors.b.b(AnchorsManager.kt:118)
8 com.effective.android.anchors.d.a(AnchorsManager.kt:291)
9 com.xxx.xxx.managers.l.b(LaunchManager.kt:142)
10 com.xxx.xxx.managers.l.a(LaunchManager.kt:93)
11 com.xxx.xxx.app.MyApplication.onCreate(MyApplication.java:97)
12 com.stub.StubApp.onCreate(SourceFile:118)
13 android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1122)
14 android.app.ActivityThread.handleBindApplication(ActivityThread.java:6619)
15 android.app.ActivityThread.-wrap2(Unknown Source:0)
16 android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
17 android.os.Handler.dispatchMessage(Handler.java:108)
18 android.os.Looper.loop(Looper.java:166)
19 android.app.ActivityThread.main(ActivityThread.java:7529)
20 java.lang.reflect.Method.invoke(Native Method)
21 com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
22 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.