rootBundle.loadString hanging for large-ish (50k+) files due to isolate?

535 Views Asked by At

I'm trying to load a large-ish (1000 lines, 68k) text file using

final String enString = await rootBundle.loadString('res/string/string_en.json');

The Dart class function AssetBundle.loadString that loads the string is

Future<String> loadString(String key, { bool cache = true }) async {
  final ByteData data = await load(key);
  if (data == null)
    throw FlutterError('Unable to load asset: $key');
  // 50 KB of data should take 2-3 ms to parse on a Moto G4, and about 400 μs
  // on a Pixel 4.
  if (data.lengthInBytes < 50 * 1024) {
    return utf8.decode(data.buffer.asUint8List());
  }
  // For strings larger than 50 KB, run the computation in an isolate to
  // avoid causing main thread jank.
 return compute(_utf8decode, data, debugLabel: 'UTF8 decode for "$key"');
}

Looking at the code above, if the file is bigger than 50k, as mine is, an isolate is used.

As a test, I cut my file in half (so 32k) and it loaded in a second (not using the isolate). But, unedited, the function hangs when the isolate is used.

My files is just a simple json file of key-value pairs. Here are the first few lines

{
  "ctaButtonConfirm": "Confirm",
  "ctaButtonContinue": "Continue",
  "ctaButtonReview": "Review",
  "balance": "Balance",
  "totalBalance": "Total Balance",
  "transactions": "Transactions",
     :

Seem like it hangs when the isolate is used?

EDIT

Based on the loadString code above I wrote an extension function that doesn't use an isolate and it works fine, so it's looking like the isolate doesn't like my file?

extension AssetBundleX on AssetBundle {
  Future<String> loadStringWithoutIsolate(String key) async {
    final ByteData data = await load(key);

    return utf8.decode(data.buffer.asUint8List());
  }
}
1

There are 1 best solutions below

0
On

You can't access rootBundle from spawned isolate. So use main isolate instead.

Or in [docs](This is useful for operations that take longer than a few milliseconds, and which would therefore risk skipping frames. For tasks that will only take a few milliseconds, consider SchedulerBinding.scheduleTask instead.)

you can try SchedulerBinding.scheduleTask instead.