背景
很早之前接觸了RxJava的任務流操作,覺得這種將複雜業務流通過一個個操作符拆解開來,形成一條條條理清晰的function, 讓人寫起來直呼過癮.其實這就是責任鏈模式的一種應用.
但是RxJava的功能實在是太強大了, 如果僅僅是使用它來處理這些業務流我覺得還是有些大材小用了.
之前也做過一段時間的應用效能優化, 其中當然就包括應用冷啟動優化, 中間有涉及過啟動器的概念, 當時也查閱了一些現有的開源框架, 也使用過其中一些, 但是總覺得並不是很好用, 用起來不是很順手.
作為一名資深Android開源框架卷王, 當時我腦海裡就萌發一種想法, 為啥我不自己寫一個任務流執行的框架呢?想到這, 我就抽出了我的一部分業餘時間(女朋友都不陪了), 擼出了這個XTask框架, 自我感覺非常nice, 在這分享給大家.
簡介
XTask是一個擴充性極強的Android任務執行框架。
可自由定義和組合任務來實現你想要的功能,尤其適用於處理複雜的業務流程,可靈活新增前置任務或者調整執行順序。例如:應用的啟動初始化流程。
專案地址
特徵
- 支援6種執行緒型別方式執行任務。
- 支援任務鏈中各任務的執行執行緒排程和控制。
- 支援快捷任務建立,同時支援自定義任務。
- 支援序列和並行等組任務。
- 支援任務間資料共享。
- 支援自由組合任務執行。
- 支援任務鏈執行取消。
- 支援取消所有任務鏈和指定名稱的任務鏈。
- 支援任務鏈呼叫順序記錄和查詢。
- 支援自定義任務執行的執行緒池。
設計思想
框架主體使用責任鏈的設計模式,輔以建造者模式、工廠模式、介面卡模式、組合模式、外觀模式以及代理模式來實現。
組成結構
- 任務鏈
ITaskChainEngine
:任務鏈執行引擎,負責統籌排程各任務步驟。 - 任務步驟
ITaskStep
:負責具體任務邏輯處理。 - 資料儲存倉庫
IDataStore
:存放資料的倉庫,主要用於儲存任務引數中的資料。 - 任務引數
ITaskParam
:負責任務路徑記錄以及任務產生的引數管理。 - 任務執行結果
ITaskResult
:存放任務最終執行的結果以及產生的資料。 - 任務組
IGroupTaskStep
:負責統籌排程各子任務步驟。
日誌一覽
整合指南
新增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.0'
}
使用方法
XTask作為對外統一的API入口,所有常用的方法都能從中找到。
開啟除錯模式
當需要定位問題,需要進行除錯時,可開啟除錯模式,這樣便可開啟框架的日誌。
XTask.debug(true);
XTask的API介紹
方法名 | 描述 |
---|---|
debug | 設定是否開啟除錯 |
setLogger | 自定義日誌列印 |
setIsLogTaskRunThreadName | 設定是否列印任務執行所在的執行緒名,預設false |
getTaskChain | 獲取任務鏈執行引擎 |
getTask | 獲取簡化的任務 |
getTaskBuilder | 獲取簡化任務的構建者 |
getConcurrentGroupTask | 獲取並行任務組 |
getSerialGroupTask | 獲取序列任務組 |
cancelTaskChain | 取消指定任務鏈執行 |
postToMain | 執行任務到主執行緒 |
submit | 執行普通非同步任務 |
emergentSubmit | 執行緊急非同步任務 |
backgroundSubmit | 執行後臺非同步任務 |
ioSubmit | 執行io耗時的非同步任務 |
groupSubmit | 執行分組非同步任務 |
如何執行一條任務鏈
下面是一整個完整的例子:
// 1.建立一條任務鏈(必須)
final TaskChainEngine engine = XTask.getTaskChain();
// 2.設定任務鏈的初始化引數(可選)
engine.setTaskParam(TaskParam.get("chainName", engine.getName()));
TaskParam taskParam = TaskParam.get("param1", 100)
.put("param2", true);
// 3.建立多個任務,並向任務鏈中新增(必須)
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.設定任務鏈執行回撥(可選)
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.任務鏈執行(必須)
}).start();
1.建立一條任務鏈.(必須)
TaskChainEngine engine = XTask.getTaskChain();
2.設定任務鏈的初始化引數.(可選)
engine.setTaskParam(TaskParam.get("chainName", engine.getName()));
3.建立多個任務,並向任務鏈中新增.(必須)
// 設定任務初始化引數
TaskParam taskParam = TaskParam.get("param1", 100)
.put("param2", true);
XTaskStep taskStep = XTask.getTask(new TaskCommand() {
@Override
public void run() {
// ...執行任務
}
}, taskParam);
engine.addTask(taskStep)
.addTask(XTask.getTask(new TaskCommand() {
@Override
public void run() {
// ...執行任務
}
}));
【注意】對於任務執行完成,需要注意以下兩點:
- 如果任務執行成功,就呼叫
notifyTaskSucceed
,任務執行失敗,就呼叫notifyTaskFailed
。這裡任務無論成功還是失敗,只要執行完成都需要呼叫notifyTaskXXX
通知任務鏈該任務完成,否則任務將無法正常執行。 TaskCommand
和SimpleTaskStep
預設提供了自動通知執行結果的功能,但是AbstractTaskStep沒有提供,需要手動通知。
4.設定任務鏈執行回撥.(可選)
呼叫setTaskChainCallback設定任務鏈執行回撥。
engine.setTaskChainCallback(new TaskChainCallbackAdapter() {
@Override
public boolean isCallBackOnMainThread() {
// 回撥是否返回主執行緒, 預設是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.任務鏈執行.(必須)
呼叫start執行任務鏈。
ICanceller canceller = engine.start();
任務建立
建立任務有兩種方式:
- 通過XTask.getTask構建
- 繼承
SimpleTaskStep
/AbstractTaskStep
實現任務的自定義
通過XTask建立
通過XTask.getTask, 傳入對應的屬性進行構建
屬性名 | 描述 |
---|---|
name | 任務步驟名稱 |
command | 任務執行內容 |
threadType | 執行緒執行型別 |
taskParam | 任務引數 |
taskHandler | 任務處理者 |
isAutoNotify | 是否自動通知任務執行結果 |
XTaskStep taskStep = XTask.getTask(new TaskCommand() {
@Override
public void run() {
// todo
}
}, ThreadType.ASYNC, taskParam);
通過繼承建立
通過繼承SimpleTaskStep
或者AbstractTaskStep
實現具體功能。
public class StepATask extends SimpleTaskStep {
@Override
public void doTask() throws Exception {
// todo
// 不需要手動通知任務鏈任務完成
}
}
public class StepBTask extends AbstractTaskStep {
@Override
public void doTask() throws Exception {
// todo
// 需手動通知任務鏈任務完成
notifyTaskSucceed(TaskResult.succeed());
}
@Override
public String getName() {
return "StepATask";
}
}
任務執行原則
每一個任務都是依託於任務鏈進行流程控制。任何任務都需要遵循以下原則:
- 任何任務無論失敗還是成功,都需要呼叫
notifyTaskSucceed
或者notifyTaskFailed
去通知任務鏈任務的完成情況。TaskCommand
和SimpleTaskStep
預設提供了自動通知執行結果的功能。 - 一旦任務鏈中某個任務執行失敗,整個鏈路都停止工作。
任務型別 | 任務執行說明 |
---|---|
TaskCommand | 自動通知執行結果。如需手動通知,只需設定isAutoNotify 為false即可 |
SimpleTaskStep | 自動通知執行結果。如需手動通知,只需重寫isAutoNotify 方法為false即可 |
AbstractTaskStep | 需手動通知執行結果 |
TaskCommand手動通知執行結果
在通過XTask.getTask傳入TaskCommand構建Task的時候,設定isAutoNotify
為false即可手動通知執行結果。
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, "任務執行失敗!");
} else {
notifyTaskSucceed(TaskResult.succeed());
}
}
}, false)); // 設定手動通知執行結果
}
engine.start();
SimpleTaskStep手動通知執行結果
重寫SimpleTaskStep
的isAutoNotify
方法為false即可手動通知執行結果。
public class StepATask extends SimpleTaskStep {
@Override
public void doTask() throws Exception {
// todo
// 手動通知任務鏈任務完成
notifyTaskSucceed();
}
@Override
protected boolean isAutoNotify() {
return false;
}
}
引數傳遞
- 任何TaskStep我們都可以通過
getTaskParam
獲取任務引數和任務執行結果ITaskParam
。 - 上一個TaskStep儲存處理過的任務引數會自動帶入到下一個TaskStep中去,因此最後一個TaskStep擁有之前所有任務的引數資料。
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);
}
})
執行緒控制
設定任務的threadType型別,即可完成對任務執行執行緒的控制。目前支援6種執行緒處理方式。
型別 | 描述 | 執行緒池構成 |
---|---|---|
MAIN | 主執行緒(UI執行緒) | / |
ASYNC | 非同步執行緒(開子執行緒,普通執行緒池) | 核心執行緒數和最大執行緒為CPU數,0s keepTime,LinkedBlockingQueue(128),執行緒優先順序5 |
ASYNC_IO | 非同步執行緒(開子執行緒,io執行緒池) | 核心執行緒數和最大執行緒為(2*CPU數+1),30s keepTime,LinkedBlockingQueue(128),執行緒優先順序5 |
ASYNC_EMERGENT | 非同步執行緒(開子執行緒,緊急執行緒池) | 核心執行緒數為2,最大執行緒為∞,60s keepTime,SynchronousQueue(不阻塞),執行緒優先順序10 |
ASYNC_BACKGROUND | 非同步執行緒(開子執行緒,優先順序較低執行緒池) | 核心執行緒數和最大執行緒為2,0s keepTime,LinkedBlockingQueue(128),執行緒優先順序1 |
SYNC | 同步執行緒(直接執行) | / |
// 1.構造時傳入執行緒
XTaskStep taskStep = XTask.getTask(new SimpleTaskCommand(1000), ThreadType.ASYNC_EMERGENT);
// 2.設定執行緒的方法
taskStep.setThreadType(ThreadType.ASYNC_IO);
任務組
目前共有序列任務組(SerialGroupTaskStep)和並行任務組(ConcurrentGroupTaskStep)
序列任務組
序列任務組是按順序依次執行,和任務鏈的處理方式類似。使用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);
並行任務組
並行任務組是組內所有任務同時執行,待所有任務都完成後才視為任務組完成。使用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,一枚熱愛學習,愛好程式設計,致力於Android架構研究以及開源專案經驗分享的技術up主。獲取更多資訊,歡迎微信搜尋公眾號:【我的Android開源之旅】