|
| 1 | +package com.aprz.graph.task; |
| 2 | + |
| 3 | +import androidx.annotation.NonNull; |
| 4 | + |
| 5 | +import java.util.ArrayList; |
| 6 | +import java.util.List; |
| 7 | + |
| 8 | +public class GraphTask extends Task implements GraphTaskLifecycleListener { |
| 9 | + |
| 10 | + /** |
| 11 | + * 该任务图的起点 task |
| 12 | + */ |
| 13 | + private AnchorTask startTask; |
| 14 | + /** |
| 15 | + * 该任务图的终点 task |
| 16 | + */ |
| 17 | + private AnchorTask finishTask; |
| 18 | + |
| 19 | + /** |
| 20 | + * 该任务图的执行的开始时间 |
| 21 | + */ |
| 22 | + private long startTime; |
| 23 | + |
| 24 | + private final List<GraphTaskLifecycleListener> lifecycleListener = new ArrayList<>(); |
| 25 | + |
| 26 | + public GraphTask(String name) { |
| 27 | + super(name); |
| 28 | + } |
| 29 | + |
| 30 | + @Override |
| 31 | + public void run() { |
| 32 | + // do nothing |
| 33 | + } |
| 34 | + |
| 35 | + @Override |
| 36 | + public void start() { |
| 37 | + startTask.start(); |
| 38 | + } |
| 39 | + |
| 40 | + @Override |
| 41 | + synchronized void addSuccessor(Task task) { |
| 42 | + finishTask.addSuccessor(task); |
| 43 | + } |
| 44 | + |
| 45 | + @Override |
| 46 | + public void addTaskLifecycleListener(final TaskLifecycleListener listener) { |
| 47 | + finishTask.addTaskLifecycleListener(listener); |
| 48 | + } |
| 49 | + |
| 50 | + @Override |
| 51 | + public void onStart() { |
| 52 | + startTime = System.currentTimeMillis(); |
| 53 | + } |
| 54 | + |
| 55 | + @Override |
| 56 | + public void onTaskStart(Task task) { |
| 57 | + for (GraphTaskLifecycleListener listener : lifecycleListener) { |
| 58 | + listener.onTaskStart(task); |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + @Override |
| 63 | + public void onTaskFinish(Task task) { |
| 64 | + for (GraphTaskLifecycleListener listener : lifecycleListener) { |
| 65 | + listener.onTaskFinish(task); |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + @Override |
| 70 | + public void onFinish() { |
| 71 | + LogUtils.d("GraphTask: " + name + " 耗时 " + (System.currentTimeMillis() - startTime) + "ms"); |
| 72 | + for (GraphTaskLifecycleListener listener : lifecycleListener) { |
| 73 | + listener.onFinish(); |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * 设置 GraphTask 执行生命周期的回调,可以监听到 GraphTask 开始执行与结束执行,GraphTask 内部的 Task 执行结束. |
| 79 | + * |
| 80 | + * @param listener GraphTask执行生命周期的回调 |
| 81 | + */ |
| 82 | + public void addLifecycleListener(GraphTaskLifecycleListener listener) { |
| 83 | + lifecycleListener.add(listener); |
| 84 | + } |
| 85 | + |
| 86 | + void setStartTask(AnchorTask startTask) { |
| 87 | + this.startTask = startTask; |
| 88 | + } |
| 89 | + |
| 90 | + void setFinishTask(AnchorTask finishTask) { |
| 91 | + this.finishTask = finishTask; |
| 92 | + } |
| 93 | + |
| 94 | + @Override |
| 95 | + void recycle() { |
| 96 | + super.recycle(); |
| 97 | + lifecycleListener.clear(); |
| 98 | + } |
| 99 | + |
| 100 | + /** |
| 101 | + * <p>通过 Builder将多个 Task 组成一个 Project 。它可以单独拿出去执行,也可以作为 |
| 102 | + * 一个子 Task 嵌入到另外一个 Project 中。</p> |
| 103 | + */ |
| 104 | + public static class Builder { |
| 105 | + /** |
| 106 | + * 正在添加的目标任务 |
| 107 | + * 使用 add 方法添加任务,然后使用 dependsOn 或者 noDepends 来修饰该任务 |
| 108 | + */ |
| 109 | + private Task targetTask; |
| 110 | + |
| 111 | + private final AnchorTask finishTask; |
| 112 | + private final AnchorTask startTask; |
| 113 | + private TaskFactory taskFactory; |
| 114 | + private GraphTask graphTask; |
| 115 | + private String graphTaskName; |
| 116 | + |
| 117 | + public Builder() { |
| 118 | + startTask = new AnchorTask(true, "--> GraphTask-StartTask <--"); |
| 119 | + finishTask = new AnchorTask(false, "--> GraphTask-FinishTask <--"); |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + * 设置 graphTask 的名称 |
| 124 | + * |
| 125 | + * @param graphTaskName graphTask 的名称 |
| 126 | + * @return Builder 对象,可以继续添加属性或者组装 Task 。 |
| 127 | + */ |
| 128 | + public Builder name(String graphTaskName) { |
| 129 | + this.graphTaskName = graphTaskName; |
| 130 | + return Builder.this; |
| 131 | + } |
| 132 | + |
| 133 | + /** |
| 134 | + * 利用 TaskCreator,之后可以直接用 taskName 来操作 add 和 after 等逻辑。 |
| 135 | + */ |
| 136 | + public Builder taskCreator(ITaskCreator creator) { |
| 137 | + taskFactory = new TaskFactory(creator); |
| 138 | + return Builder.this; |
| 139 | + } |
| 140 | + |
| 141 | + |
| 142 | + /** |
| 143 | + * 用 Task 名称进行操作,需要提前调用{@link #taskCreator(ITaskCreator)} 创建名称对应的 task 实例 |
| 144 | + * |
| 145 | + * @param taskName 增加的 Task 对象的名称。 |
| 146 | + * @return Builder 对象,可以继续添加属性或者组装 Task 。 |
| 147 | + */ |
| 148 | + public Builder add(String taskName) { |
| 149 | + checkTaskFactory(); |
| 150 | + |
| 151 | + Task task = taskFactory.getTask(taskName); |
| 152 | + add(task); |
| 153 | + |
| 154 | + return Builder.this; |
| 155 | + } |
| 156 | + |
| 157 | + /** |
| 158 | + * 增加一个 Task,在调用该方法后,需要调用{@link #dependsOn(String...)} (Task)}来确定它在图中的位置, |
| 159 | + * 如果该 Task 没有依赖的任务,则需要调用 {@link #noDepends()} 方法。 |
| 160 | + * |
| 161 | + * @param task 增加的 Task 对象. |
| 162 | + */ |
| 163 | + private void add(Task task) { |
| 164 | + targetTask = task; |
| 165 | + targetTask.addSuccessor(finishTask); |
| 166 | + targetTask.addTaskLifecycleListener(new TaskLifecycleListener() { |
| 167 | + @Override |
| 168 | + public void onTaskStart(Task task) { |
| 169 | + graphTask.onTaskStart(task); |
| 170 | + |
| 171 | + } |
| 172 | + |
| 173 | + @Override |
| 174 | + public void onTaskFinish(Task task) { |
| 175 | + graphTask.onTaskFinish(task); |
| 176 | + } |
| 177 | + |
| 178 | + }); |
| 179 | + } |
| 180 | + |
| 181 | + /** |
| 182 | + * 指定紧前 Task,必须等这些指定的 Task 执行完后才能执行自己。 |
| 183 | + * 如果没有紧前 Task,必须调用 {@link #noDepends()} 方法 |
| 184 | + * |
| 185 | + * @param taskNames 所有的紧前 Task |
| 186 | + * @return Builder 对象,可以继续添加属性或者组装 Task 。 |
| 187 | + */ |
| 188 | + public Builder dependsOn(@NonNull String... taskNames) { |
| 189 | + checkTaskFactory(); |
| 190 | + checkTaskNames(taskNames); |
| 191 | + |
| 192 | + Task[] tasks = new Task[taskNames.length]; |
| 193 | + for (int i = 0, len = taskNames.length; i < len; i++) { |
| 194 | + String taskName = taskNames[i]; |
| 195 | + Task task = taskFactory.getTask(taskName); |
| 196 | + tasks[i] = task; |
| 197 | + } |
| 198 | + dependsOn(tasks); |
| 199 | + return Builder.this; |
| 200 | + } |
| 201 | + |
| 202 | + /** |
| 203 | + * 如果没有紧前 Task,必须调用该方法 |
| 204 | + * |
| 205 | + * @return Builder 对象,可以继续添加属性或者组装 Task 。 |
| 206 | + */ |
| 207 | + public Builder noDepends() { |
| 208 | + checkTaskFactory(); |
| 209 | + dependsOn(new Task[0]); |
| 210 | + return Builder.this; |
| 211 | + } |
| 212 | + |
| 213 | + private void dependsOn(Task... tasks) { |
| 214 | + if (tasks == null || tasks.length <= 0) { |
| 215 | + startTask.addSuccessor(targetTask); |
| 216 | + } |
| 217 | + for (Task task : tasks) { |
| 218 | + task.addSuccessor(targetTask); |
| 219 | + finishTask.removePredecessor(task); |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + public void checkTaskFactory() { |
| 224 | + if (taskFactory == null) { |
| 225 | + throw new IllegalAccessError("You should set a ITaskCreator with taskCreator() !!!"); |
| 226 | + } |
| 227 | + } |
| 228 | + |
| 229 | + private void checkTaskNames(String... taskNames) { |
| 230 | + if (taskNames.length <= 0) { |
| 231 | + throw new IllegalAccessError("taskNames should not be empty !!!"); |
| 232 | + } |
| 233 | + } |
| 234 | + |
| 235 | + public GraphTask build() { |
| 236 | + graphTask = new GraphTask(graphTaskName); |
| 237 | + finishTask.setLifecycleListener(graphTask); |
| 238 | + startTask.setLifecycleListener(graphTask); |
| 239 | + graphTask.setStartTask(startTask); |
| 240 | + graphTask.setFinishTask(finishTask); |
| 241 | + return graphTask; |
| 242 | + } |
| 243 | + } |
| 244 | + |
| 245 | + |
| 246 | + /** |
| 247 | + * <p>从图的执行角度来讲,应该要有唯一的开始位置和唯一的结束位置。这样就可以准确衡量一个图的开始和结束。并且可以 |
| 248 | + * 通过开始点和结束点,方便地将这个图嵌入到另外一个图中去。</p> |
| 249 | + * <p>但是从用户的角度来理解,他可能会有多个 task 可以同时开始,也可以有多个 task 作为结束点。</p> |
| 250 | + * <p>为了解决这个矛盾,框架提供一个默认的开始节点和默认的结束节点。并且将这两个点称为这个 GraphTak 的锚点。 |
| 251 | + * 用户添加的 task 都是添加在开始锚点后,用户的添加的 task 后也都会有一个默认的结束锚点。</p> |
| 252 | + * <p>如前面提到,锚点的作用有两个: |
| 253 | + * <li>标记一个 GraphTak 的开始和结束。</li> |
| 254 | + * <li>当 GraphTak 需要作为一个 task 嵌入到另外一个 GraphTak 里面时,锚点可以用来和其他 task |
| 255 | + * 进行连接。</li> |
| 256 | + * </p> |
| 257 | + */ |
| 258 | + private static class AnchorTask extends Task { |
| 259 | + private final boolean isStartTask; |
| 260 | + private GraphTaskLifecycleListener lifecycleListener; |
| 261 | + |
| 262 | + public AnchorTask(boolean isStartTask, String name) { |
| 263 | + super(name); |
| 264 | + this.isStartTask = isStartTask; |
| 265 | + } |
| 266 | + |
| 267 | + public void setLifecycleListener(GraphTaskLifecycleListener listener) { |
| 268 | + lifecycleListener = listener; |
| 269 | + } |
| 270 | + |
| 271 | + @Override |
| 272 | + public void run() { |
| 273 | + if (lifecycleListener != null) { |
| 274 | + if (isStartTask) { |
| 275 | + lifecycleListener.onStart(); |
| 276 | + } else { |
| 277 | + lifecycleListener.onFinish(); |
| 278 | + } |
| 279 | + } |
| 280 | + } |
| 281 | + |
| 282 | + } |
| 283 | + |
| 284 | +} |
0 commit comments