最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Flutter?隊列任務的實現(xiàn)

 更新時間:2022年06月14日 11:14:29   作者:BlackDream  
本文主要介紹了Flutter?隊列任務的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

在電商的應用中,最常見的就是在首頁或完成某事件之后,彈出一堆的活動/廣告。假如重疊彈出,很丑,給用戶的體驗也不好,所以一般都會依次依條件的彈出。

下面講講我是怎么實現(xiàn)一個方便的隊列任務管理。

隊列

任務隊列,那當然要有個隊列。這個隊列的任務內容應該是返回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);
}

執(zhí)行隊列任務

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

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

在執(zhí)行完成(或失?。┖螅?strong>自動觸發(fā)下一個任務。add中也可以加入startLoop,使添加任務后自動啟動任務循環(huán)。

任務條件

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

條件可以是整個任務隊列統(tǒng)一的條件,也可以是某個任務特定的條件

typedef TaskConditionFunction = FutureOr<bool> Function();

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

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

/// 總條件
TaskConditionFunction? _condition;

添加任務時加入條件

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

}

設置總條件,或補充條件

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

執(zhí)行任務前判斷條件是否滿足

    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);
}

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

使用和總結

實例化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中,可能執(zhí)行完之后又不滿足了,根據(jù)具體情況考慮。

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

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

這樣一個使用簡單好用的任務隊列就實現(xiàn)好了,更多相關Flutter 隊列任務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

贵阳市| 静海县| 宝清县| 竹山县| 北流市| 甘肃省| 铜山县| 镇宁| 郯城县| 额尔古纳市| 张家港市| 陇西县| 富蕴县| 彰化县| 江城| 黎平县| 兴仁县| 来宾市| 凤山县| 长海县| 苍溪县| 中牟县| 闸北区| 威远县| 岱山县| 喜德县| 涡阳县| 永靖县| 二连浩特市| 霍山县| 耿马| 长兴县| 安乡县| 偏关县| 永胜县| 平定县| 北安市| 壤塘县| 恩施市| 阿克| 许昌县|