什麼是EasyExecutor
EasyExecutor是開源基礎元件整合庫EasyAndroid中的基礎元件之一。
其作用是:對執行緒池進行二次封裝,為上層提供最簡單、最方便的執行緒操作體驗
EasyAndroid作為一款整合元件庫,此庫中所整合的元件,均包含以下特點,你可以放心使用~~
1. 設計獨立
元件間獨立存在,不相互依賴,且若只需要整合庫中的部分元件。也可以很方便的
只copy對應的元件檔案
進行使用
2. 設計輕巧
因為是元件整合庫,所以要求每個元件的設計儘量精練、輕巧。避免因為一個小功能而引入大量無用程式碼.
每個元件的方法數均
不超過100
. 大部分元件甚至不超過50
。
得益於編碼時的高內聚性
,若你只需要使用EasyExecutor. 那麼可以直接去拷貝EasyExecutor原始碼檔案到你的專案中,直接進行使用,也是沒問題的。
EasyAndroid開源庫地址:
https://github.com/yjfnypeu/EasyAndroid
EasyExecutor元件地址:
https://github.com/yjfnypeu/EasyAndroid/blob/master/utils/src/main/java/com/haoge/easyandroid/easy/EasyExecutor.kt
特性
- 安全: 直接catch住任務執行期間出現的異常。並通知給使用者,避免出現crash
- 回撥通知: 執行任務期間,有分別的生命週期作為通知。
- 配置靈活: 可方便、靈活的對每次所啟動的任務,配置執行緒名、回撥等。
- 任務延遲: 支援在每次啟動任務前。指定延遲時間
- 非同步任務: 支援直接啟動非同步任務並回撥傳遞資料
- 執行緒切換: 支援指定回撥方法所在的執行緒。預設為執行於UI執行緒中
- 進度通知: 支援方便地進行任務處理進度通知
用法
建立配置EasyExecutor例項
EasyExecutor是對執行緒池進行的封裝,所以在建立時,我們需要指定需要建立的執行緒池的大小
val builder = EasyExecutor.newBuilder(size)
... // 其他配置
val executor = builder.build()// 配置完成後再建立EasyExecutor提供使用
複製程式碼
引數size為Int
型別,即為指定的執行緒池大小
,size與建立的執行緒池的關係為:
val executor = when {
// size小於1, 建立可快取大小的執行緒池提供使用
size <= 0 -> Executors.newCachedThreadPool(createFactory())
// size大於0, 建立指定大小的執行緒池。
else -> Executors.newFixedThreadPool(size, createFactory())
}
複製程式碼
執行緒優先順序配置
可以通過以下方式,指定執行緒池建立出來的執行緒優先順序
:
builder.setPriority(priority)
複製程式碼
執行緒任務名配置
所謂任務名
即是建立出來的執行緒的執行緒名
, 而指定任務名的方式有以下兩種:
1.指定預設任務名:在建立時進行指定
builder.setName("default name")
複製程式碼
2.指定臨時任務名:在使用前進行指定
executor.setName("temp name")
複製程式碼
臨時
與預設
任務名的關係是:在啟動一次後臺任務時:
- 當
有配置臨時任務名
時:使用臨時任務名
作為此次的執行緒任務名,並將此臨時任務名進行重置
- 當
沒配置臨時任務名
時:使用預設任務名
作為此次的執行緒任務名。
啟動非同步任務
普通非同步任務,直接建立任務進行啟動即可:
executor.execute { // TODO }
複製程式碼
很多時候,在java原生中的使用習慣是:普通任務都是通過Runnable
介面進行定義,所以EasyExecutor
也提供了直接使用Runnable
任務的過載方法:
val runnable:Runnable = createTask()
executor.execute(runnable)
複製程式碼
啟動非同步回撥任務
非同步回撥任務:用於在需要接收非同步任務返回值時使用:
executor.async(
task:(Notifier) -> T, // Notifier將在後面的進度通知小節進行介紹
result:(T)->Unit)// 接收task的返回值並通知到此
複製程式碼
比如說。在子執行緒進行Bitmap建立:
executor.async(
{ // 非同步任務
// 子執行緒中,進行Bitmap建立,
return@Callable bitmap
},
{ bitmap -> // 非同步回撥,預設執行於UI執行緒
// TODO 使用建立好的bitmap進行操作
// 關於回撥執行緒的派發,後面 派發器 小節會進行詳細說明
}
)
複製程式碼
啟動延遲任務
如果需要指定此次任務
需要被延遲執行
時。使用setDelay
直接指定延遲時間
即可:
executor.setDelay(delayTime)
複製程式碼
請注意: delayTime
型別為Long
, 單位為毫秒
。且此延遲時間
的有效作用域是此次被啟動的任務
。一旦有任務被啟動之後。延遲時間
將被重置。也就是:
executor.setDelay(3000)
executor.execute(task1)// task1任務將被延遲3秒執行
executor.execute(task2)// task2任務將被直接執行
複製程式碼
安全的進行回撥派發
EasyExecutor
提供三個回撥方法:
型別 | lambda | 說明 |
---|---|---|
onStart | (String) -> Unit | 當執行緒任務被執行時被觸發,引數為任務名 |
onError | (String, Throwable) -> Unit | 當執行緒任務執行出現異常時被觸發, 引數為任務名 和出現的異常 |
onSuccess | (String) -> Unit | 當執行緒任務執行完成時被觸發,引數為任務名 |
此三種回撥,也有預設回撥配置
和臨時回撥配置
的區別
指定預設回撥:作用域為所有的執行緒任務
builder.onStart {threadName -> } // 所有任務啟動時的回撥
.onSuccess {threadName -> }// 所有任務執行完畢後的回撥
.onError {threadName, throwable -> }// 所有任務執行出現異常時的回撥
複製程式碼
指定臨時回撥:作用域為此次啟動的執行緒任務
executor.onStart {threadName -> } // 此次任務啟動時的回撥
.onSuccess {threadName -> }// 此次任務執行完畢後的回撥
.onError {threadName, throwable -> }// 此次任務執行出現異常時的回撥
複製程式碼
所以,與任務名配置
不同。臨時回撥不會覆蓋掉預設回撥,而他們被觸發的先後順序是:先觸發預設回撥。再觸發臨時回撥
而所謂安全
,即是在整個任務的執行過程中。會將執行過程中出現的異常
進行捕獲。防止任務執行出錯導致crash
。被捕獲的異常將會通過onError
回撥。通知到指定執行緒進行處理:
Thread.currentThread().setUncaughtExceptionHandler {
name, e ->
// deliver:派發器。將訊息通知到指定執行緒。
deliver.execute {
builder.error?.invoke(name, e)// 預設回撥異常通知
error?.invoke(name, e)// 臨時回撥異常通知
}
}
複製程式碼
配置派發器
就以上面的三個回撥方法
為例:我們在說的時候。只說了它們被觸發的時機,但是沒說它們具體執行在哪個執行緒中。而這,就是派發器乾的事:
派發器的作用: 就是將訊息派發到指定執行緒中去之後再進行使用者通知!
派發器的本質,是一個Executor
介面的實現類:
internal var deliver:Executor = UIDeliver
複製程式碼
而預設使用的UIDeliver
,就是專門針對Android執行時環境
建立的:將訊息派發到UI執行緒進行通知
internal val UIDeliver:Executor = Executor { runnable ->
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run()
} else {
mainHandler.post { runnable.run() }
}
}
複製程式碼
而對於派發器來說。也存在預設配置
與臨時配置
預設配置:當不存在臨時派發器配置時,使用此預設派發器
builder.setDeliver(Executor {})
複製程式碼
臨時配置:只對此次啟動任務生效
executor.setDeliver(Executor {})
複製程式碼
需要注意的是:派發器也對非同步回撥任務生效
。所以在預設配置下,非同步回撥也是執行於UI執行緒中的:
executor.async(
Callable<T> {return T},
{ T ->
// 此回撥所處執行緒也受派發器控制。
}
)
複製程式碼
進行非同步任務進度通知
有些時候,我們會需要在任務的處理過程中,對外進行進度狀態通知,以便進行上傳的進度UI更新。使用EasyExecutor
。也可以很方便的做到進度通知的效果:
需要進行狀態通知,首先需要定製進度回撥通知:
executor.onProgressChanged { current:Long, total:Long ->
// 傳參current為當前的進度, total為資料總量。
// 此回撥所處執行緒也受派發器控制
}
複製程式碼
而EasyExecutor
本身提供的任務模型
就提供了有進行外部狀態通知的例項:
// 普通任務:
executor.execute { notifier -> }
// 非同步任務
executor.async( { notifier -> }, { result -> })
複製程式碼
任務例項中的傳參notifier即是用於進行外部通知的類。對於需要監聽狀態通知的任務。可以通過此例項方便的指定進度資訊。
所以一個完整的進度回撥任務
模型應該是如以下程式碼一樣:
executor.onProgressChanged {
current, total ->
TODO("進行進度變化通知展示")
}
.execute { notifier ->
// 在合適的處理進度中。使用以下api進行進度狀態派發即可
notifier.progressChanged(current, total)
}
複製程式碼
歡迎掃描下方二維碼關注我的公眾號?