When i run this method, in flutter, for example when I onTap
in gesture detector flutter freezes 2 times, when get
method invoke (I'm think there because of Dio json converter, maybe, idk), and when base64Decode
method invoke
On the flutter web when get
method invoke, flutter frizzed at all (onSendProgress
not work to at this time too) and after this application in chrome crash with code 5, after minute, or two maybe -_-
context
is not BuildContext
httpClient
is Dio HTTP client
transformOf
check is request result is error, and if yes, transform request result to my flutter custom exceptions, and after throw it, else return request result.
Request result size is 20-50mb
Future<Uint8List> readBookFile(Identificator groupId, Identificator bookId) async {
final result = await context.httpClient.get(
'/book/file',
queryParameters: {
'groupId': groupId.toString(),
'bookId': bookId.toString(),
},
).transformOf(context);
return base64Decode(result['bookBytes']);
}
How optimise this code for dispose freezes?
CodePudding user response:
By default, Flutter apps do all of their work on a single UI thread. If you try to perform expensive computation inside that UI thread your app's UI gets freeze.
Problem
In your case base64Decode(result['bookBytes']);
is a very expensive computation. (because it decode large data set (20-50mb))
Solution
You can solve this by using a separate Isolate for running the above expensive task. (see below code)
create a method called
parseBookBytes()
put the expensivebaseDecode64()
task into it.Using compute() function execute
parseBookBytes()
in a separate isolate.
// A function that converts a result into a Uint8List.
Uint8List parseBookBytes(var bookBytes) {
return base64Decode(bookBytes);
}
Future<Uint8List> readBookFile(Identificator groupId, Identificator bookId) async {
final result = await context.httpClient.get(
'/book/file',
queryParameters: {
'groupId': groupId.toString(),
'bookId': bookId.toString(),
},
).transformOf(context);
return compute(parseBookBytes, result['bookBytes']); //run on a separate isolate using compute() function
}
Resources
CodePudding user response:
For fix this I create 2 parse and 2 compute functions
Uint8List parseBase64(String base64) {
return base64Decode(base64);
}
Future<Uint8List> parseBase64Compute(String base64) {
return compute<String, Uint8List>(parseBase64, base64.trim());
}
Map<String, dynamic> parseJson(String json) {
return jsonDecode(json);
}
Future<Map<String, dynamic>> parseJsonCompute(String base64) {
return compute<String, Map<String, dynamic>>(parseJson, base64);
}
After I'm create simple dio transformer for json
class JsonTransformer extends DefaultTransformer {
JsonTransformer() : super(jsonDecodeCallback: parseJsonCompute);
}
And apply this
httpClient.transformer = JsonTransformer();
And refactored function is
Future<Uint8List> readBookFile(Identificator groupId, Identificator bookId) async {
final result = await context.httpClient.get(
'/book/file',
queryParameters: {
'groupId': groupId.toString(),
'bookId': bookId.toString(),
},
).transformOf(context);
return parseBase64Compute(result['bookBytes']);;
}