Move UTF-8 decoding off the main thread. (#14206)
This reduces the jank of bringing up the license screen further. The remaining lost frame or two are caused by Dart itself, see: https://github.com/dart-lang/sdk/issues/31954 https://github.com/dart-lang/sdk/issues/31959 https://github.com/dart-lang/sdk/issues/31960 Fixes https://github.com/flutter/flutter/issues/5187
This commit is contained in:
parent
10f721c8a5
commit
b6c6e36589
@ -160,6 +160,15 @@ abstract class CachingAssetBundle extends AssetBundle {
|
||||
final ByteData data = await load(key);
|
||||
if (data == null)
|
||||
throw new FlutterError('Unable to load asset: $key');
|
||||
if (data.lengthInBytes < 10 * 1024) {
|
||||
// 10KB takes about 3ms to parse on a Pixel 2 XL.
|
||||
// See: https://github.com/dart-lang/sdk/issues/31954
|
||||
return UTF8.decode(data.buffer.asUint8List());
|
||||
}
|
||||
return compute(_utf8decode, data, debugLabel: 'UTF8 decode for "$key"');
|
||||
}
|
||||
|
||||
static String _utf8decode(ByteData data) {
|
||||
return UTF8.decode(data.buffer.asUint8List());
|
||||
}
|
||||
|
||||
|
@ -40,9 +40,32 @@ abstract class ServicesBinding extends BindingBase {
|
||||
}
|
||||
|
||||
Stream<LicenseEntry> _addLicenses() async* {
|
||||
final String rawLicenses = await rootBundle.loadString('LICENSE', cache: false);
|
||||
final List<LicenseEntry> licenses = await compute(_parseLicenses, rawLicenses, debugLabel: 'parseLicenses');
|
||||
yield* new Stream<LicenseEntry>.fromIterable(licenses);
|
||||
// We use timers here (rather than scheduleTask from the scheduler binding)
|
||||
// because the services layer can't use the scheduler binding (the scheduler
|
||||
// binding uses the services layer to manage its lifecycle events). Timers
|
||||
// are what scheduleTask uses under the hood anyway. The only difference is
|
||||
// that these will just run next, instead of being prioritized relative to
|
||||
// the other tasks that might be running. Using _something_ here to break
|
||||
// this into two parts is important because isolates take a while to copy
|
||||
// data at the moment, and if we receive the data in the same event loop
|
||||
// iteration as we send the data to the next isolate, we are definitely
|
||||
// going to miss frames. Another solution would be to have the work all
|
||||
// happen in one isolate, and we may go there eventually, but first we are
|
||||
// going to see if isolate communication can be made cheaper.
|
||||
// See: https://github.com/dart-lang/sdk/issues/31959
|
||||
// https://github.com/dart-lang/sdk/issues/31960
|
||||
// TODO(ianh): Remove this complexity once these bugs are fixed.
|
||||
final Completer<String> rawLicenses = new Completer<String>();
|
||||
Timer.run(() async {
|
||||
rawLicenses.complete(rootBundle.loadString('LICENSE', cache: false));
|
||||
});
|
||||
await rawLicenses.future;
|
||||
final Completer<List<LicenseEntry>> parsedLicenses = new Completer<List<LicenseEntry>>();
|
||||
Timer.run(() async {
|
||||
parsedLicenses.complete(compute(_parseLicenses, await rawLicenses.future, debugLabel: 'parseLicenses'));
|
||||
});
|
||||
await parsedLicenses.future;
|
||||
yield* new Stream<LicenseEntry>.fromIterable(await parsedLicenses.future);
|
||||
}
|
||||
|
||||
// This is run in another isolate created by _addLicenses above.
|
||||
|
Loading…
x
Reference in New Issue
Block a user