Use Isolate to sort list

Issue

I have a non-primitive list which I would like to sort.

When I sort it, the UI thread is blocked and the app freezes for a few seconds.

I tried to avoid this by using dart’s Isloate compute function but since the parameter sent to the compute function must be a primitive or a list/map of primitives (send method) it didn’t work.

To conclude, is there any way to perform a list sort(non-primitive) without blocking the UI thread?

Edit: Clarification – I was trying to call a function through compute and I was passing a list of objects (which I got from a third party plugin) as an argument, those objects had a property of type Iterable and that caused everything to fail – make sure all the types are primitive or List/Map of primitives. With the answers I received and changing the type from Iterable to List it worked.

Solution

I’m not sure if I understood your question, but you can sort a list of non primitive elements like this:

final List<Element> elements = [
  Element(id: 1),
  Element(id: 7),
  Element(id: 2),
  Element(id: 0)
];

elements.sort((a, b) => a.compareTo(b));
// or
elements.sort((a, b) => a.id > b.id ? 1 : -1);

This would be a print(elements); output:

I/flutter ( 7351): [id: 0, id: 1, id: 2, id: 7]

And this would be the class Element

class Element {
  final int id;

  Element({this.id});

  @override
  String toString() => "id: $id";

  int compareTo(Element other) => this.id > other.id ? 1 : -1;
}

Edit: To make this asynchronously, you could do this:

Future<List<Element>> asyncSort() async {
  print("before sort: $elements");
  elements = await compute(_sort, elements);
  print("after sort: $elements");
  return elements;
}

static List<Element> _sort(List<Element> list) {
  list.sort((a, b) => a.compareTo(b));
  return list;
}

print("before calling asyncSort(): $elements");
asyncSort();
print("after calling asyncSort(): $elements");

And this would be the output:

I/flutter ( 7351): before calling asyncSort(): [id: 1, id: 7, id: 2, id: 0]
I/flutter ( 7351): before sort: [id: 1, id: 7, id: 2, id: 0]
I/flutter ( 7351): after calling asyncSort(): [id: 1, id: 7, id: 2, id: 0]
I/flutter ( 7351): after sort: [id: 0, id: 1, id: 2, id: 7]

Edit2: If you want to send a compare function to compute, you could use a Map or a List of arguments with the list and the compare function and pass that instead of the list, because compute just takes one argument. Here is an example:

Future<List<Element>> asyncSort() async {
  print("before sort: $elements");
  Map args = {"list": elements, "compare": compare};
  elements = await compute(_sortWith, args);
  print("after sort: $elements");
  return elements;
}

static List<Element> _sortWith(Map args) {
  List<Element> list = args["list"];
  Function(Element a, Element b) compare = args["compare"];

  list.sort((a, b) => compare(a, b));
  return list;
}

static int compare(Element a, Element b) {
  return a.id > b.id ? 1 : -1;
}

Answered By – Pablo Barrera

Answer Checked By – Marilyn (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *