Open
Description
Imported from dnfield/flutter_svg#1099
Original report by @8symbols on Sep 2, 2024
If you provide a bundle
argument to SvgPicture.asset
and use Image.asset(...)
, then in profile and release modes the following exception will be thrown and svg won't be displayed:
Exception
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Illegal argument in isolate message: object is unsendable - Library:'dart:async' Class: _Future@4048458 (see restrictions listed at `SendPort.send()` documentation for more information)
<- _List len:8 (from dart:core)
<- _Map len:1 (from dart:collection)
<- Instance of 'PlatformAssetBundle' (from package:flutter/src/services/asset_bundle.dart)
<- Instance of 'SvgAssetLoader' (from package:flutter_svg/src/loaders.dart)
<- Context num_variables: 2 <- SvgLoader._load.<anonymous closure>.<anonymous closure> (from package:flutter_svg/src/loaders.dart)
<- Context num_variables: 2 <- compute.<anonymous closure> (from package:flutter/src/foundation/_isolates_io.dart)
<- resultPort in Instance of '_RemoteRunner<ByteData>' (from dart:isolate)
#0 Isolate._spawnFunction (dart:isolate-patch/isolate_patch.dart:398)
#1 Isolate.spawn (dart:isolate-patch/isolate_patch.dart:378)
#2 Isolate.run (dart:isolate:285)
#3 compute (package:flutter/src/foundation/_isolates_io.dart:18)
#4 compute (package:flutter/src/foundation/isolates.dart:82)
#5 SvgLoader._load.<anonymous closure> (package:flutter_svg/src/loaders.dart:154)
<asynchronous suspension>
#6 _VectorGraphicWidgetState._loadPicture.<anonymous closure> (package:vector_graphics/src/vector_graphics.dart:355)
<asynchronous suspension>
#7 _VectorGraphicWidgetState._loadPicture.<anonymous closure> (package:vector_graphics/src/vector_graphics.dart:369)
<asynchronous suspension>
#8 _VectorGraphicWidgetState._loadAssetBytes.<anonymous closure> (package:vector_graphics/src/vector_graphics.dart:402)
<asynchronous suspension>
That's because CachingAssetBundle stores futures in its fields, SvgAssetLoader stores bundle (if you provided one) and SvgLoader somehow sends it to other isolate in compute.
Debug build doesn't have this problem because it doesn't use other isolate.
Reproducible with Flutter 3.24.1 and flutter_svg: 2.0.10+1
.
Sample app
assets/any_svg.svg
and assets/any_png.png
are literally any svg and png files respectively.
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(
const MaterialApp(
home: Screen(),
),
);
}
class Screen extends StatelessWidget {
const Screen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
SvgPicture.asset(
'assets/any_svg.svg',
bundle: DefaultAssetBundle.of(context),
),
Image.asset(
'assets/any_png.png',
width: 100.0,
height: 100.0,
),
],
),
);
}
}
Problem can be fixed with the following change, but I don't sure how adequate it is.
Change that fixes problem
Future<ByteData> _load(BuildContext? context) {
final SvgTheme theme = getTheme(context);
return prepareMessage(context).then((T? message) {
return _compute<T>(
message: message,
xml: provideSvg(message),
theme: theme,
colorMapper: colorMapper,
);
});
}
static Future<ByteData> _compute<T>({
required T? message,
required String xml,
required SvgTheme theme,
required ColorMapper? colorMapper,
}) {
return compute((T? message) {
return vg
.encodeSvg(
xml: xml,
theme: theme.toVgTheme(),
colorMapper: colorMapper == null
? null
: _DelegateVgColorMapper(colorMapper),
debugName: 'Svg loader',
enableClippingOptimizer: false,
enableMaskingOptimizer: false,
enableOverdrawOptimizer: false,
)
.buffer
.asByteData();
}, message, debugLabel: 'Load Bytes');
}