Home > database >  How Optimize this HTTP Request Method for Dispose Freezes in UI Thread?
How Optimize this HTTP Request Method for Dispose Freezes in UI Thread?

Time:12-11

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)

  1. create a method called parseBookBytes() put the expensive baseDecode64() task into it.

  2. 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

  1. Link 1
  2. Link 2
  3. Link 3

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']);;
}
  • Related