Skip to content

Commit 42d552d

Browse files
committed
添加 task 依赖解决方案
1 parent c53a4d2 commit 42d552d

18 files changed

+949
-1
lines changed

graph-task/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

graph-task/build.gradle

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
plugins {
2+
id 'com.android.library'
3+
}
4+
5+
android {
6+
compileSdkVersion 30
7+
buildToolsVersion "30.0.2"
8+
9+
defaultConfig {
10+
minSdkVersion 21
11+
targetSdkVersion 30
12+
versionCode 1
13+
versionName "1.0"
14+
15+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16+
consumerProguardFiles "consumer-rules.pro"
17+
}
18+
19+
buildTypes {
20+
release {
21+
minifyEnabled false
22+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23+
}
24+
}
25+
compileOptions {
26+
sourceCompatibility JavaVersion.VERSION_1_8
27+
targetCompatibility JavaVersion.VERSION_1_8
28+
}
29+
}
30+
31+
dependencies {
32+
33+
implementation 'androidx.appcompat:appcompat:1.2.0'
34+
implementation 'com.google.android.material:material:1.2.1'
35+
testImplementation 'junit:junit:4.+'
36+
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
37+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
38+
}

graph-task/consumer-rules.pro

Whitespace-only changes.

graph-task/proguard-rules.pro

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.aprz.graph.task;
2+
3+
import android.content.Context;
4+
5+
import androidx.test.platform.app.InstrumentationRegistry;
6+
import androidx.test.ext.junit.runners.AndroidJUnit4;
7+
8+
import org.junit.Test;
9+
import org.junit.runner.RunWith;
10+
11+
import static org.junit.Assert.*;
12+
13+
/**
14+
* Instrumented test, which will execute on an Android device.
15+
*
16+
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
17+
*/
18+
@RunWith(AndroidJUnit4.class)
19+
public class ExampleInstrumentedTest {
20+
@Test
21+
public void useAppContext() {
22+
// Context of the app under test.
23+
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24+
assertEquals("com.aprz.graph.task.test", appContext.getPackageName());
25+
}
26+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.aprz.graph.task">
4+
5+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
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

Comments
 (0)