欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flutter?隊(duì)列任務(wù)的實(shí)現(xiàn)

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

前言

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

下面講講我是怎么實(shí)現(xiàn)一個方便的隊(duì)列任務(wù)管理

隊(duì)列

任務(wù)隊(duì)列,那當(dāng)然要有個隊(duì)列。這個隊(duì)列的任務(wù)內(nèi)容應(yīng)該是返回FutureFunction,因?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,同一個FunctionhashCode相同。

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ù)具體情況考慮。

一般來說類似彈窗的returnawait 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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論