溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Flutter隊列任務如何實現

發布時間:2022-06-14 13:50:02 來源:億速云 閱讀:281 作者:iii 欄目:開發技術

本篇內容介紹了“Flutter隊列任務如何實現”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    隊列

    任務隊列,那當然要有個隊列。這個隊列的任務內容應該是返回FutureFunction,因為我需要得到他處理完成的結果,比如等待彈窗關閉時return,才表示這個任務被完成。

    typedef TaskEventFunction = Future Function();
    
    class TaskQueue {
        List<TaskEventFunction> _actionQueue = [];
    }

    添加任務進隊列

    然后是加入隊列的方法add

    void add(TaskEventFunction task) {
      _actionQueue.add(task);
    }

    然后想到,隊列是不是最好去重?或者可選去重。

    那一個Function如何去重呢,我們可以使用它的hashCode,同一個FunctionhashCode相同。

    taskQueue.add(testFunction);
    
    Future testFunction() async {
      await Future.delayed(const Duration(milliseconds: 1000));
      return Future.value(true);
    }

    即我們可以按上面這樣定義,同一個類同一個實例下同一個Function,就是相同的hashCode。若是以下這種寫法則hashCode不一樣,每次add都相當于一個新的Function。

    taskQueue.add(() async {
      await Future.delayed(const Duration(milliseconds: 1000));
      return Future.value(true);
    });

    假如不需要去重,可以用第二種。也可以主動指定taskId來選擇哪些需要去重(即使內容不一樣),哪些不需要。

    修改一下add,增加taskId。同時hashCode應該作為主要的key,修改一下隊列類型。 最終如下:

    /// 任務編號隊列
    List<String> _actionQueue = [];
    
    /// 任務隊列
    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返回。

    移除隊列指定任務

    有添加任務的方法,那也需有移除任務的方法

    /// 這里需注意,add的時taskId為-1,那就直接把task傳入,add時有返回,可以對應
    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為準。

    判斷是否包含對應任務

    使用者可以自己判斷是否已包含對應的任務

    /// 是否隊列中包含該任務
    /// [task] 與 [taskId] 應該只傳一個
    bool containers({TaskEventFunction? task, String? taskId}) {
      assert(task != null || taskId != null);
      String? id = taskId;
      id ??= task.hashCode.toString();
      return _actionQueue.contains(taskId);
    }

    執行隊列任務

    任務隊列的進出基本成型,開始處理任務。很簡單,取出任務,然后執行任務,最后移除任務

    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,表示任務正在處理中的狀態,正在處理的話,不允許執行下一個任務。

    在執行完成(或失?。┖?,自動觸發下一個任務。add中也可以加入startLoop,使添加任務后自動啟動任務循環。

    任務條件

    基本的任務隊列已經完成。不過每個任務其實一般都會有個條件,確認符合當前場景才執行。比如說的確是新人且在首頁,才顯示新人優惠彈窗。

    條件可以是整個任務隊列統一的條件,也可以是某個任務特定的條件。

    typedef TaskConditionFunction = FutureOr<bool> Function();

    這里類型用FutureOr<bool>,有可能需要等待一下才能確認條件。任務對應的條件,也根據taskId來存儲。

    /// 任務條件
    Map<String, TaskConditionFunction> _actionCondition = {};
    
    /// 總條件
    TaskConditionFunction? _condition;

    添加任務時加入條件

    TaskEventFunction add(TaskEventFunction task, {
      String? taskId,
      TaskConditionFunction? condition,
    }) {
        ...
        
        if (condition != null && !_actionCondition.containsKey(id)) {
          _actionCondition[id] = condition;
        }
    
    }

    設置總條件,或補充條件

    /// 設置允許執行條件
    void setAcceptConditions(TaskConditionFunction condition,
        {String? taskId}) {
      if (taskId == null) {
        _condition = condition;
      } else {
        _actionCondition[taskId] = condition;
      }
    }

    執行任務前判斷條件是否滿足

        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 {
          // 不滿足條件一般后續的也不會執行
          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);
    }

    原則上應該既滿足總條件也滿足任務條件。

    使用和總結

    實例化TaskQueue

    TaskQueue taskQueue = TaskQueue();

    添加任務并開始任務

    taskQueue.add(testFunction, condition: () async {
      await Future.delayed(const Duration(milliseconds: 200));
      return Future.value(true);
    });
    taskQueue.startLoop();
    
    Future testFunction() async {
      return showDialog(...);
    }

    注意設置條件要返回bool。

    還可以加入類似延時等操作,跟條件一樣配置即可。太久的操作不要像上面一樣寫在condition中,可能執行完之后又不滿足了,根據具體情況考慮。

    一般來說類似彈窗的returnawait showDialog就可以等待彈窗頁面結束,再進行下一個。

    跨頁面還是當前頁面的控制,只需要考慮是全局實例TaskQueue還是頁面內實例TaskQueue。

    “Flutter隊列任務如何實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女