Home > Mobile >  How to create an isolate using the compute function for Recursive function
How to create an isolate using the compute function for Recursive function

Time:08-16

I am using the recursive function for a huge data which causes the app to freeze for a few seconds, so I want to create an isolate using the compute function for that recursive function

So I make a simple example with the same data structure as my live project, please help me to include the isolate fuction as I noted in the code below.

import 'package:flutter/foundation.dart';

class Item {
  Item({this.id, this.childIds, this.parentIds});

  final String id;
  final List<String> childIds;
  List<String> parentIds;

  @override
  String toString() {
    return 'Item{id: $id, childIds: $childIds, parentIds: $parentIds}';
  }
}

List<Item> data = [
  Item(id: 'aaa', childIds: ['ccc']),
  Item(id: 'bbb', childIds: ['ccc', 'ddd']),
  Item(id: 'ccc', childIds: ['ggg']),
  Item(id: 'ddd', childIds: ['fff', 'hhh']),
  Item(id: 'eee', childIds: ['hhh']),
  Item(id: 'fff', childIds: ['ggg']),
  Item(id: 'ggg', childIds: null),
  Item(id: 'hhh', childIds: null),
];

void main() async {
  await data.map((e) async {
    e.parentIds = await idFindParent(e.id);
    // Option 1: create Isolate here
    // e.parentIds = await compute(idFindParent,e.id);
  }).toList();
  data.forEach((e) => print(e));
}

List<String> idFindParent(String id) {
  List<Item> itemsHasChild = data.where((e) => e.childIds != null).toList();
  List<Item> parents = itemsHasChild.where((parent) => parent.childIds.contains(id)).toList();
  if (parents.isEmpty) return [];
  List<String> parentIds = parents.map((e) => e.id).toSet().toList();
  return findParentRecursive(parentIds);
  // Option 2: create Isolate here
  // return compute(findParentRecursive, parentIds);
}

List<String> findParentRecursive(List<String> ids) {
  bool everyParentIsEmpty = ids.every((id) => data
      .where((e) => e.childIds != null)
      .toList()
      .where((e) => e.childIds.any((childIds) => childIds.contains(id)))
      .toList()
      .isEmpty);

  if (everyParentIsEmpty) return ids;

  List<String> _ids = [];
  ids.map((id) {
    List<Item> itemsHasChild = data.where((e) => e.childIds != null).toList();
    List<Item> parents =
        itemsHasChild.where((e) => e.childIds.any((childIds) => childIds.contains(id))).toList();
    if (parents.isEmpty) {
      _ids.add(id);
    } else if (parents.isNotEmpty) {
      parents.map((e) {
        return _ids.add(e.id);
      }).toList();
    }
  }).toList();

  return findParentRecursive(_ids.toSet().toList());
}

CodePudding user response:

Note: idFindParent do not use "UI" code. Ex: import some ui dependencies and use it in idFindParent function.

import 'dart:async';
import 'dart:isolate';

class Item {
  Item({this.id, this.childIds, this.parentIds});

  final String id;
  final List<String> childIds;
  List<String> parentIds;

  @override
  String toString() {
    return 'Item{id: $id, childIds: $childIds, parentIds: $parentIds}';
  }
}

List<Item> data = [
  Item(id: 'aaa', childIds: ['ccc']),
  Item(id: 'bbb', childIds: ['ccc', 'ddd']),
  Item(id: 'ccc', childIds: ['ggg']),
  Item(id: 'ddd', childIds: ['fff', 'hhh']),
  Item(id: 'eee', childIds: ['hhh']),
  Item(id: 'fff', childIds: ['ggg']),
  Item(id: 'ggg', childIds: null),
  Item(id: 'hhh', childIds: null),
];

void main() async {
  var dataMap = await data.map((e) async {
    Completer<List<String>> completer = Completer();
    isolateData(e.id, completer);
    e.parentIds = await completer.future;
    return e;
  }).toList();
  var results = await Future.wait(dataMap);
  print(results);
}

void isolateData(String id, Completer<List<String>> completer) async {
  var port = ReceivePort();
  var isolate = await Isolate.spawn(
    idFindParent,
    [id, port.sendPort],
  );
  port.listen((result) {
    completer.complete(result);
    isolate.kill();
    port.close();
  });
}

void idFindParent(List<Object> args) {
  String id = args[0] as String;
  SendPort port = args[1] as SendPort;

  List<Item> itemsHasChild = data.where((e) => e.childIds != null).toList();
  List<Item> parents = itemsHasChild.where((parent) => parent.childIds.contains(id)).toList();
  if (parents.isEmpty) {
    List<String> ids = [];
    port.send(ids);
    return;
  } else {
    List<String> parentIds = parents.map((e) => e.id).toSet().toList();
    var ids = findParentRecursive(parentIds);
    port.send(ids);
    return;
  }
}

List<String> findParentRecursive(List<String> ids) {
  bool everyParentIsEmpty =
      ids.every((id) => data.where((e) => e.childIds != null).toList().where((e) => e.childIds.any((childIds) => childIds.contains(id))).toList().isEmpty);
  if (everyParentIsEmpty) return ids;
  List<String> _ids = [];
  ids.map((id) {
    List<Item> itemsHasChild = data.where((e) => e.childIds != null).toList();
    List<Item> parents = itemsHasChild.where((e) => e.childIds.any((childIds) => childIds.contains(id))).toList();
    if (parents.isEmpty) {
      _ids.add(id);
    } else if (parents.isNotEmpty) {
      parents.map((e) {
        return _ids.add(e.id);
      }).toList();
    }
  }).toList();

  return findParentRecursive(_ids.toSet().toList());
}
  • Related