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