背景
很早之前接觸了RxJava的任務(wù)流操作,覺得這種將復(fù)雜業(yè)務(wù)流通過一個個操作符拆解開來,形成一條條條理清晰的function, 讓人寫起來直呼過癮.其實這就是責(zé)任鏈模式的一種應(yīng)用.
但是RxJava的功能實在是太強大了, 如果僅僅是使用它來處理這些業(yè)務(wù)流我覺得還是有些大材小用了.
之前也做過一段時間的應(yīng)用性能優(yōu)化, 其中當(dāng)然就包括應(yīng)用冷啟動優(yōu)化, 中間有涉及過啟動器的概念, 當(dāng)時也查閱了一些現(xiàn)有的開源框架, 也使用過其中一些, 但是總覺得并不是很好用, 用起來不是很順手.
作為一名資深A(yù)ndroid開源框架卷王, 當(dāng)時我腦海里就萌發(fā)一種想法, 為啥我不自己寫一個任務(wù)流執(zhí)行的框架呢?想到這, 我就抽出了我的一部分業(yè)余時間(女朋友都不陪了), 擼出了這個XTask框架, 自我感覺非常nice, 在這分享給大家.
簡介
XTask是一個拓展性極強的Android任務(wù)執(zhí)行框架糖赔。
可自由定義和組合任務(wù)來實現(xiàn)你想要的功能,尤其適用于處理復(fù)雜的業(yè)務(wù)流程,可靈活添加前置任務(wù)或者調(diào)整執(zhí)行順序分井。例如:應(yīng)用的啟動初始化流程订歪。
項目地址
特征
- 支持6種線程類型方式執(zhí)行任務(wù)刊殉。
- 支持任務(wù)鏈中各任務(wù)的執(zhí)行線程調(diào)度和控制涮坐。
- 支持快捷任務(wù)創(chuàng)建吓笙,同時支持自定義任務(wù)。
- 支持串行和并行等組任務(wù)崎岂。
- 支持任務(wù)間數(shù)據(jù)共享捆毫。
- 支持自由組合任務(wù)執(zhí)行。
- 支持任務(wù)鏈執(zhí)行取消冲甘。
- 支持取消所有任務(wù)鏈和指定名稱的任務(wù)鏈绩卤。
- 支持任務(wù)鏈調(diào)用順序記錄和查詢。
- 支持自定義任務(wù)執(zhí)行的線程池江醇。
設(shè)計思想
框架主體使用責(zé)任鏈的設(shè)計模式濒憋,輔以建造者模式、工廠模式嫁审、適配器模式跋炕、組合模式、外觀模式以及代理模式來實現(xiàn)律适。
組成結(jié)構(gòu)
任務(wù)鏈
ITaskChainEngine
:任務(wù)鏈執(zhí)行引擎辐烂,負責(zé)統(tǒng)籌調(diào)度各任務(wù)步驟。任務(wù)步驟
ITaskStep
:負責(zé)具體任務(wù)邏輯處理捂贿。數(shù)據(jù)存儲倉庫
IDataStore
:存放數(shù)據(jù)的倉庫纠修,主要用于保存任務(wù)參數(shù)中的數(shù)據(jù)。任務(wù)參數(shù)
ITaskParam
:負責(zé)任務(wù)路徑記錄以及任務(wù)產(chǎn)生的參數(shù)管理厂僧。任務(wù)執(zhí)行結(jié)果
ITaskResult
:存放任務(wù)最終執(zhí)行的結(jié)果以及產(chǎn)生的數(shù)據(jù)扣草。任務(wù)組
IGroupTaskStep
:負責(zé)統(tǒng)籌調(diào)度各子任務(wù)步驟。
日志一覽
集成指南
添加Gradle依賴
1.先在項目根目錄的 build.gradle
的 repositories
添加:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
2.然后在dependencies添加:
dependencies {
...
// XTask
implementation 'com.github.xuexiangjys.XTask:xtask-core:1.0.2'
}
使用方法
XTask作為對外統(tǒng)一的API入口颜屠,所有常用的方法都能從中找到辰妙。
打開調(diào)試模式
當(dāng)需要定位問題,需要進行調(diào)試時甫窟,可打開調(diào)試模式密浑,這樣便可開啟框架的日志。
XTask.debug(true);
XTask的API介紹
方法名 | 描述 |
---|---|
debug | 設(shè)置是否打開調(diào)試 |
setLogger | 自定義日志打印 |
setIsLogTaskRunThreadName | 設(shè)置是否打印任務(wù)執(zhí)行所在的線程名粗井,默認false |
getTaskChain | 獲取任務(wù)鏈執(zhí)行引擎 |
getTask | 獲取簡化的任務(wù) |
getTaskBuilder | 獲取簡化任務(wù)的構(gòu)建者 |
getConcurrentGroupTask | 獲取并行任務(wù)組 |
getSerialGroupTask | 獲取串行任務(wù)組 |
cancelTaskChain | 取消指定任務(wù)鏈執(zhí)行 |
postToMain | 執(zhí)行任務(wù)到主線程 |
submit | 執(zhí)行普通異步任務(wù) |
emergentSubmit | 執(zhí)行緊急異步任務(wù) |
backgroundSubmit | 執(zhí)行后臺異步任務(wù) |
ioSubmit | 執(zhí)行io耗時的異步任務(wù) |
groupSubmit | 執(zhí)行分組異步任務(wù) |
如何執(zhí)行一條任務(wù)鏈
下面是一整個完整的例子:
// 1.創(chuàng)建一條任務(wù)鏈(必須)
final TaskChainEngine engine = XTask.getTaskChain();
// 2.設(shè)置任務(wù)鏈的初始化參數(shù)(可選)
engine.setTaskParam(TaskParam.get("chainName", engine.getName()));
TaskParam taskParam = TaskParam.get("param1", 100)
.put("param2", true);
// 3.創(chuàng)建多個任務(wù)尔破,并向任務(wù)鏈中添加(必須)
XTaskStep taskStep = XTask.getTask(new TaskCommand() {
@Override
public void run() {
ITaskParam param = getTaskParam();
Log.e(TAG, getName() + " start, param1:" + param.get("param1") + ", chainName:" + param.get("chainName"));
param.put("param1", 200);
param.put("param3", "this is param3!");
}
}, taskParam);
engine.addTask(taskStep)
.addTask(XTask.getTask(new TaskCommand() {
@Override
public void run() {
ITaskParam param = getTaskParam();
Log.e(TAG, getName() + " start, param1:" + param.get("param1") + ", param3:" + param.get("param3"));
param.put("param2", false);
}
}));
// 4.設(shè)置任務(wù)鏈執(zhí)行回調(diào)(可選)
ICanceller canceller = engine.setTaskChainCallback(new TaskChainCallbackAdapter() {
@Override
public void onTaskChainCompleted(@NonNull ITaskChainEngine engine, @NonNull ITaskResult result) {
Log.e(TAG, "task chain completed, thread:" + Thread.currentThread().getName());
Map<String, Object> data = result.getDataStore().getData();
for (Map.Entry<String, Object> entry : data.entrySet()) {
Log.e(TAG, "key:" + entry.getKey() + ", value:" + entry.getValue());
}
}
// 5.任務(wù)鏈執(zhí)行(必須)
}).start();
1.創(chuàng)建一條任務(wù)鏈.(必須)
TaskChainEngine engine = XTask.getTaskChain();
2.設(shè)置任務(wù)鏈的初始化參數(shù).(可選)
engine.setTaskParam(TaskParam.get("chainName", engine.getName()));
3.創(chuàng)建多個任務(wù),并向任務(wù)鏈中添加.(必須)
// 設(shè)置任務(wù)初始化參數(shù)
TaskParam taskParam = TaskParam.get("param1", 100)
.put("param2", true);
XTaskStep taskStep = XTask.getTask(new TaskCommand() {
@Override
public void run() {
// ...執(zhí)行任務(wù)
}
}, taskParam);
engine.addTask(taskStep)
.addTask(XTask.getTask(new TaskCommand() {
@Override
public void run() {
// ...執(zhí)行任務(wù)
}
}));
【注意】對于任務(wù)執(zhí)行完成浇衬,需要注意以下兩點:
- 如果任務(wù)執(zhí)行成功懒构,就調(diào)用
notifyTaskSucceed
,任務(wù)執(zhí)行失敗耘擂,就調(diào)用notifyTaskFailed
胆剧。這里任務(wù)無論成功還是失敗,只要執(zhí)行完成都需要調(diào)用notifyTaskXXX
通知任務(wù)鏈該任務(wù)完成醉冤,否則任務(wù)將無法正常執(zhí)行赞赖。 -
TaskCommand
和SimpleTaskStep
默認提供了自動通知執(zhí)行結(jié)果的功能滚朵,但是AbstractTaskStep沒有提供冤灾,需要手動通知前域。
4.設(shè)置任務(wù)鏈執(zhí)行回調(diào).(可選)
調(diào)用setTaskChainCallback設(shè)置任務(wù)鏈執(zhí)行回調(diào)。
engine.setTaskChainCallback(new TaskChainCallbackAdapter() {
@Override
public boolean isCallBackOnMainThread() {
// 回調(diào)是否返回主線程, 默認是true
return false;
}
@Override
public void onTaskChainStart(@NonNull ITaskChainEngine engine) {
Log.e(TAG, "task chain start");
}
@Override
public void onTaskChainCompleted(@NonNull ITaskChainEngine engine, @NonNull ITaskResult result) {
Log.e(TAG, "task chain completed, thread:" + Thread.currentThread().getName());
}
@Override
public void onTaskChainError(@NonNull ITaskChainEngine engine, @NonNull ITaskResult result) {
Log.e(TAG, "task chain error");
}
})
5.任務(wù)鏈執(zhí)行.(必須)
調(diào)用start執(zhí)行任務(wù)鏈韵吨。
ICanceller canceller = engine.start();
任務(wù)創(chuàng)建
創(chuàng)建任務(wù)有兩種方式:
- 通過XTask.getTask構(gòu)建
- 繼承
SimpleTaskStep
/AbstractTaskStep
實現(xiàn)任務(wù)的自定義
通過XTask創(chuàng)建
通過XTask.getTask, 傳入對應(yīng)的屬性進行構(gòu)建
屬性名 | 描述 |
---|---|
name | 任務(wù)步驟名稱 |
command | 任務(wù)執(zhí)行內(nèi)容 |
threadType | 線程執(zhí)行類型 |
taskParam | 任務(wù)參數(shù) |
taskHandler | 任務(wù)處理者 |
isAutoNotify | 是否自動通知任務(wù)執(zhí)行結(jié)果 |
XTaskStep taskStep = XTask.getTask(new TaskCommand() {
@Override
public void run() {
// todo
}
}, ThreadType.ASYNC, taskParam);
通過繼承創(chuàng)建
通過繼承
SimpleTaskStep
或者AbstractTaskStep
實現(xiàn)具體功能匿垄。
public class StepATask extends SimpleTaskStep {
@Override
public void doTask() throws Exception {
// todo
// 不需要手動通知任務(wù)鏈任務(wù)完成
}
}
public class StepBTask extends AbstractTaskStep {
@Override
public void doTask() throws Exception {
// todo
// 需手動通知任務(wù)鏈任務(wù)完成
notifyTaskSucceed(TaskResult.succeed());
}
@Override
public String getName() {
return "StepATask";
}
}
任務(wù)執(zhí)行原則
每一個任務(wù)都是依托于任務(wù)鏈進行流程控制。任何任務(wù)都需要遵循以下原則:
- 任何任務(wù)無論失敗還是成功归粉,都需要調(diào)用
notifyTaskSucceed
或者notifyTaskFailed
去通知任務(wù)鏈任務(wù)的完成情況椿疗。TaskCommand
和SimpleTaskStep
默認提供了自動通知執(zhí)行結(jié)果的功能。 - 一旦任務(wù)鏈中某個任務(wù)執(zhí)行失敗糠悼,整個鏈路都停止工作届榄。
任務(wù)類型 | 任務(wù)執(zhí)行說明 |
---|---|
TaskCommand | 自動通知執(zhí)行結(jié)果。如需手動通知倔喂,只需設(shè)置isAutoNotify 為false即可 |
SimpleTaskStep | 自動通知執(zhí)行結(jié)果铝条。如需手動通知,只需重寫isAutoNotify 方法為false即可 |
AbstractTaskStep | 需手動通知執(zhí)行結(jié)果 |
TaskCommand手動通知執(zhí)行結(jié)果
在通過XTask.getTask傳入TaskCommand構(gòu)建Task的時候席噩,設(shè)置isAutoNotify
為false即可手動通知執(zhí)行結(jié)果班缰。
final TaskChainEngine engine = XTask.getTaskChain();
for (int i = 0; i < 5; i++) {
int finalI = i;
engine.addTask(XTask.getTask(new TaskCommand() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (finalI == 2) {
notifyTaskFailed(404, "任務(wù)執(zhí)行失敗!");
} else {
notifyTaskSucceed(TaskResult.succeed());
}
}
}, false)); // 設(shè)置手動通知執(zhí)行結(jié)果
}
engine.start();
SimpleTaskStep手動通知執(zhí)行結(jié)果
重寫SimpleTaskStep
的isAutoNotify
方法為false即可手動通知執(zhí)行結(jié)果。
public class StepATask extends SimpleTaskStep {
@Override
public void doTask() throws Exception {
// todo
// 手動通知任務(wù)鏈任務(wù)完成
notifyTaskSucceed();
}
@Override
protected boolean isAutoNotify() {
return false;
}
}
參數(shù)傳遞
- 任何TaskStep我們都可以通過
getTaskParam
獲取任務(wù)參數(shù)和任務(wù)執(zhí)行結(jié)果ITaskParam
悼枢。 - 上一個TaskStep保存處理過的任務(wù)參數(shù)會自動帶入到下一個TaskStep中去埠忘,因此最后一個TaskStep擁有之前所有任務(wù)的參數(shù)數(shù)據(jù)。
XTask.getTask(new TaskCommand() {
@Override
public void run() {
ITaskParam param = getTaskParam();
Log.e(TAG, getName() + " start, param1:" + param.get("param1") + ", param3:" + param.get("param3"));
param.put("param2", false);
}
})
線程控制
設(shè)置任務(wù)的threadType類型馒索,即可完成對任務(wù)運行線程的控制莹妒。目前支持6種線程處理方式。
類型 | 描述 | 線程池構(gòu)成 |
---|---|---|
MAIN | 主線程(UI線程) | / |
ASYNC | 異步線程(開子線程绰上,普通線程池) | 核心線程數(shù)和最大線程為CPU數(shù)旨怠,0s keepTime,LinkedBlockingQueue(128)渔期,線程優(yōu)先級5 |
ASYNC_IO | 異步線程(開子線程运吓,io線程池) | 核心線程數(shù)和最大線程為(2*CPU數(shù)+1),30s keepTime疯趟,LinkedBlockingQueue(128)拘哨,線程優(yōu)先級5 |
ASYNC_EMERGENT | 異步線程(開子線程,緊急線程池) | 核心線程數(shù)為2信峻,最大線程為∞倦青,60s keepTime,SynchronousQueue(不阻塞)盹舞,線程優(yōu)先級10 |
ASYNC_BACKGROUND | 異步線程(開子線程产镐,優(yōu)先級較低線程池) | 核心線程數(shù)和最大線程為2隘庄,0s keepTime,LinkedBlockingQueue(128)癣亚,線程優(yōu)先級1 |
SYNC | 同步線程(直接執(zhí)行) | / |
// 1.構(gòu)造時傳入線程
XTaskStep taskStep = XTask.getTask(new SimpleTaskCommand(1000), ThreadType.ASYNC_EMERGENT);
// 2.設(shè)置線程的方法
taskStep.setThreadType(ThreadType.ASYNC_IO);
任務(wù)組
目前共有串行任務(wù)組(SerialGroupTaskStep)和并行任務(wù)組(ConcurrentGroupTaskStep)
串行任務(wù)組
串行任務(wù)組是按順序依次執(zhí)行丑掺,和任務(wù)鏈的處理方式類似。使用XTask.getSerialGroupTask獲取述雾。
final TaskChainEngine engine = XTask.getTaskChain();
SerialGroupTaskStep group1 = XTask.getSerialGroupTask("group1");
for (int i = 0; i < 5; i++) {
group1.addTask(XTask.getTask(new SimpleTaskCommand(500)));
}
SerialGroupTaskStep group2 = XTask.getSerialGroupTask("group2");
for (int i = 0; i < 5; i++) {
group2.addTask(XTask.getTask(new SimpleTaskCommand(1000)));
}
ICanceller canceller = engine.addTask(group1)
.addTask(group2)
.setTaskChainCallback(new TaskChainCallbackAdapter() {
@Override
public void onTaskChainCompleted(@NonNull ITaskChainEngine engine, @NonNull ITaskResult result) {
Log.e(TAG, "task chain completed, path:" + result.getPath());
}
})
.start();
addCanceller(canceller);
并行任務(wù)組
并行任務(wù)組是組內(nèi)所有任務(wù)同時執(zhí)行街州,待所有任務(wù)都完成后才視為任務(wù)組完成。使用XTask.getConcurrentGroupTask獲取玻孟。
final TaskChainEngine engine = XTask.getTaskChain();
ConcurrentGroupTaskStep group1 = XTask.getConcurrentGroupTask("group1");
for (int i = 0; i < 5; i++) {
group1.addTask(XTask.getTask(new SimpleTaskCommand(100 * (i + 1))));
}
ConcurrentGroupTaskStep group2 = XTask.getConcurrentGroupTask("group2");
for (int i = 0; i < 5; i++) {
group2.addTask(XTask.getTask(new SimpleTaskCommand(200 * (i + 1))));
}
ICanceller canceller = engine.addTask(group1)
.addTask(group2)
.setTaskChainCallback(new TaskChainCallbackAdapter() {
@Override
public void onTaskChainCompleted(@NonNull ITaskChainEngine engine, @NonNull ITaskResult result) {
Log.e(TAG, "task chain completed, path:" + result.getPath());
}
})
.start();
addCanceller(canceller);
最后
如果你覺得這個項目對你有所幫助, 你可以點擊star進行收藏或者將其分享出去, 讓更多的人知道這個項目!
我是xuexiangjys唆缴,一枚熱愛學(xué)習(xí),愛好編程黍翎,致力于Android架構(gòu)研究以及開源項目經(jīng)驗分享的技術(shù)up主面徽。獲取更多資訊,歡迎微信搜索公眾號:【我的Android開源之旅】