I have an app in Flutter that needs to perform several heavy server calls. To try and avoid lagging the UI, we've passed the HTTP requests and the JSON parsing to isolates. Two things happened:
- The app became slower
- The UI blocks/lags just as much as before
So we're probably doing something wrong. This is the isolate code:
static Future<Map<String, dynamic>> get(String url) async
{
Map<String, dynamic> config = {};
config["url"] = url;
config["headers"] = Globals.getHeaders();
Stopwatch stopwatch = new Stopwatch()..start();
Map<String, dynamic> res = await Isolate.run(() {
return getIsolate(config);
});
if (res["success"] == false && res["reason"] == "timeout")
Globals.syncTimeout = true;
print("\Isolate run time: ${stopwatch.elapsedMilliseconds} ms - URL: " + url);
stopwatch.stop();
return res;
}
static Future<Map<String, dynamic>> getIsolate(Map<String, dynamic> config) async
{
Stopwatch stopwatch = new Stopwatch()..start();
String url = config["url"];
Map<String, String> headers = config["headers"];
var data = await http.get(Uri.parse(url), headers: headers).timeout(const Duration(seconds: 30), onTimeout: () { return http.Response("timeout", 408); });
print("\tNetwork time: ${stopwatch.elapsedMilliseconds} ms - URL: " + url);
stopwatch.reset();
if (data.body == "timeout")
return {"success": false, "reason": "timeout"};
Map<String, dynamic> response = jsonDecode(data.body);
print("\tJSON time: ${stopwatch.elapsedMilliseconds} ms - URL: " + url);
stopwatch.stop();
return response;
}
For testing, you can see above that we've added several prints with stopwatches. These logs cover the work within the isolate and the whole isolation block (Isolate.run) invocation. I thought they would be about the same. They aren't. By a long margin:
I/flutter (25468): Network time: 380 ms - URL: url1
I/flutter (25468): JSON time: 43 ms - URL: url1
I/flutter (25468): Isolate run time: 2788 ms - URL: url1
I/flutter (25468): Network time: 1344 ms - URL: url2
I/flutter (25468): JSON time: 67 ms - URL: url2
I/flutter (25468): Isolate run time: 4175 ms - URL: url2
I understand that there may be an invocation overhead for creating isolates, but not of this magnitude. Also, the UI still blocks a lot although no heavy work is being done outside isolates. The flow is something very basic akin to:
initState()
{
getData();
}
getData() async
{
await NetworkManager.get(url1);
setState(() {});
}
build()
{
...
}
Am I doing something wrong?
Added note: These metrics were obtained while running in Profile mode.