Flutter?隊(duì)列任務(wù)的實(shí)現(xiàn)
前言
在電商的應(yīng)用中,最常見的就是在首頁或完成某事件之后,彈出一堆的活動/廣告。假如重疊彈出,很丑,給用戶的體驗(yàn)也不好,所以一般都會依次依條件的彈出。
下面講講我是怎么實(shí)現(xiàn)一個方便的隊(duì)列任務(wù)管理。
隊(duì)列
任務(wù)隊(duì)列,那當(dāng)然要有個隊(duì)列。這個隊(duì)列的任務(wù)內(nèi)容應(yīng)該是返回Future
的Function
,因?yàn)槲倚枰玫剿?strong>處理完成的結(jié)果,比如等待彈窗關(guān)閉時return
,才表示這個任務(wù)被完成。
typedef TaskEventFunction = Future Function(); class TaskQueue { List<TaskEventFunction> _actionQueue = []; }
添加任務(wù)進(jìn)隊(duì)列
然后是加入隊(duì)列的方法add
void add(TaskEventFunction task) { _actionQueue.add(task); }
然后想到,隊(duì)列是不是最好去重?或者可選去重。
那一個Function
如何去重呢,我們可以使用它的hashCode,同一個Function
的hashCode相同。
taskQueue.add(testFunction); Future testFunction() async { await Future.delayed(const Duration(milliseconds: 1000)); return Future.value(true); }
即我們可以按上面這樣定義,同一個類同一個實(shí)例下同一個Function
,就是相同的hashCode。若是以下這種寫法則hashCode不一樣,每次add
都相當(dāng)于一個新的Function
。
taskQueue.add(() async { await Future.delayed(const Duration(milliseconds: 1000)); return Future.value(true); });
假如不需要去重,可以用第二種。也可以主動指定taskId來選擇哪些需要去重(即使內(nèi)容不一樣),哪些不需要。
修改一下add
,增加taskId
。同時hashCode應(yīng)該作為主要的key,修改一下隊(duì)列類型。 最終如下:
/// 任務(wù)編號隊(duì)列 List<String> _actionQueue = []; /// 任務(wù)隊(duì)列 Map<String, TaskEventFunction> _actionMap = {}; /// 指定taskId 為 -1 則不用去重 String add(TaskEventFunction task, { String? taskId, }) { String? id = taskId; id ??= task.hashCode.toString(); bool isContains = false; if (taskId != '-1') { isContains = _actionQueue.contains(id); } else { id = task.hashCode.toString(); } if (!isContains) { _actionQueue.add(id); _actionMap[id] = task; } return id; }
-1時則不去重,也把最終的taskId
返回。
移除隊(duì)列指定任務(wù)
有添加任務(wù)的方法,那也需有移除任務(wù)的方法
/// 這里需注意,add的時taskId為-1,那就直接把task傳入,add時有返回,可以對應(yīng) bool remove(TaskEventFunction task, {String? taskId}) { String? id = taskId; id ??= task.hashCode.toString(); if (_actionQueue.contains(id)) { _actionMap.remove(id); return _actionQueue.remove(id); } return false; }
以taskId/hashCode為準(zhǔn)。
判斷是否包含對應(yīng)任務(wù)
使用者可以自己判斷是否已包含對應(yīng)的任務(wù)
/// 是否隊(duì)列中包含該任務(wù) /// [task] 與 [taskId] 應(yīng)該只傳一個 bool containers({TaskEventFunction? task, String? taskId}) { assert(task != null || taskId != null); String? id = taskId; id ??= task.hashCode.toString(); return _actionQueue.contains(taskId); }
執(zhí)行隊(duì)列任務(wù)
任務(wù)隊(duì)列的進(jìn)出基本成型,開始處理任務(wù)。很簡單,取出任務(wù),然后執(zhí)行任務(wù),最后移除任務(wù)
void startLoop() async { if (dealing || _actionQueue.isEmpty) { return; } dealing = true; String taskId = _actionQueue.first; TaskEventFunction? callback = _actionMap[taskId]; if (callback == null) { _actionQueue.remove(taskId); return; } try { await callback(); } catch (e) { log('_actionQueue 出錯 $e'); } finally { _actionQueue.remove(taskId); _actionMap.remove(taskId); dealing = false; if (_actionQueue.isNotEmpty) { startLoop(); } } }
這里加了個dealing
,表示任務(wù)正在處理中的狀態(tài),正在處理的話,不允許執(zhí)行下一個任務(wù)。
在執(zhí)行完成(或失?。┖?,自動觸發(fā)下一個任務(wù)。add
中也可以加入startLoop
,使添加任務(wù)后自動啟動任務(wù)循環(huán)。
任務(wù)條件
基本的任務(wù)隊(duì)列已經(jīng)完成。不過每個任務(wù)其實(shí)一般都會有個條件,確認(rèn)符合當(dāng)前場景才執(zhí)行。比如說的確是新人且在首頁,才顯示新人優(yōu)惠彈窗。
條件可以是整個任務(wù)隊(duì)列統(tǒng)一的條件,也可以是某個任務(wù)特定的條件。
typedef TaskConditionFunction = FutureOr<bool> Function();
這里類型用FutureOr<bool>
,有可能需要等待一下才能確認(rèn)條件。任務(wù)對應(yīng)的條件,也根據(jù)taskId來存儲。
/// 任務(wù)條件 Map<String, TaskConditionFunction> _actionCondition = {}; /// 總條件 TaskConditionFunction? _condition;
添加任務(wù)時加入條件
TaskEventFunction add(TaskEventFunction task, { String? taskId, TaskConditionFunction? condition, }) { ... if (condition != null && !_actionCondition.containsKey(id)) { _actionCondition[id] = condition; } }
設(shè)置總條件,或補(bǔ)充條件
/// 設(shè)置允許執(zhí)行條件 void setAcceptConditions(TaskConditionFunction condition, {String? taskId}) { if (taskId == null) { _condition = condition; } else { _actionCondition[taskId] = condition; } }
執(zhí)行任務(wù)前判斷條件是否滿足
bool canNext = await _nextConditions(taskId); if (canNext) { try { await callback(); } catch (e) { log('_actionQueue 出錯 $e'); } finally { _actionQueue.remove(taskId); _actionMap.remove(taskId); dealing = false; if (_actionQueue.isNotEmpty) { startLoop(); } } } else { // 不滿足條件一般后續(xù)的也不會執(zhí)行 dealing = false; }
Future<bool> _nextConditions([String? id]) async { String taskId = id ?? _actionQueue.first; bool canNext = true; var taskCondition = _actionCondition[taskId]; if (_condition != null) { canNext = await _condition!.call(); } if (canNext && taskCondition != null) { canNext = await taskCondition(); } return Future.value(canNext); }
原則上應(yīng)該既滿足總條件也滿足任務(wù)條件。
使用和總結(jié)
實(shí)例化TaskQueue
TaskQueue taskQueue = TaskQueue();
添加任務(wù)并開始任務(wù)
taskQueue.add(testFunction, condition: () async { await Future.delayed(const Duration(milliseconds: 200)); return Future.value(true); }); taskQueue.startLoop(); Future testFunction() async { return showDialog(...); }
注意設(shè)置條件要返回bool
。
還可以加入類似延時等操作,跟條件一樣配置即可。太久的操作不要像上面一樣寫在condition
中,可能執(zhí)行完之后又不滿足了,根據(jù)具體情況考慮。
一般來說類似彈窗的return
或await showDialog
就可以等待彈窗頁面結(jié)束,再進(jìn)行下一個。
跨頁面還是當(dāng)前頁面的控制,只需要考慮是全局實(shí)例TaskQueue
還是頁面內(nèi)實(shí)例TaskQueue
。
這樣一個使用簡單好用的任務(wù)隊(duì)列就實(shí)現(xiàn)好了,更多相關(guān)Flutter 隊(duì)列任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解Flutter自定義應(yīng)用程序內(nèi)鍵盤的實(shí)現(xiàn)方法
- Flutter實(shí)現(xiàn)切換應(yīng)用時隱藏應(yīng)用預(yù)覽
- Flutter獲取ListView當(dāng)前正在顯示的Widget信息(應(yīng)用場景)
- Android利用Flutter?path繪制粽子的示例代碼
- 基于Flutter實(shí)現(xiàn)多邊形和多角星組件
- Flutter?WebView?預(yù)加載實(shí)現(xiàn)方法(Http?Server)
- 基于flutter?sound插件實(shí)現(xiàn)錄音與播放功能
- Flutter添加頁面過渡動畫實(shí)現(xiàn)步驟
- flutter項(xiàng)目引入iconfont阿里巴巴圖標(biāo)
相關(guān)文章
Android第三方開源下拉框NiceSpinner使用詳解
這篇文章主要為大家詳細(xì)介紹了Android第三方開源下拉框NiceSpinner的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07Android開發(fā)之RadioGroup的簡單使用與監(jiān)聽示例
這篇文章主要介紹了Android開發(fā)之RadioGroup的簡單使用與監(jiān)聽,結(jié)合實(shí)例形式分析了Android針對RadioGroup單選按鈕簡單實(shí)用技巧,需要的朋友可以參考下2017-07-07Android百度地圖應(yīng)用之MapFragment的使用
這篇文章主要為大家詳細(xì)介紹了Android百度地圖應(yīng)用之MapFragment的使用的相關(guān)資料,需要的朋友可以參考下2016-06-06Android圖片的Base64編碼與解碼及解碼Base64圖片方法
Base64是網(wǎng)絡(luò)上最常見的用于傳輸8Bit字節(jié)碼的編碼方式之一,Base64就是一種基于64個可打印字符來表示二進(jìn)制數(shù)據(jù)的方法。接下來通過本文給大家分享Android圖片的Base64編碼與解碼及解碼Base64圖片,需要的朋友參考下吧2017-12-12