如何优化此HTTP请求方法以处理UI线程中的冻结



当我在flutter中运行此方法时,例如当我在手势检测器中的onTapflutter冻结2次时,当get方法调用时(我认为这是因为Dio-json转换器,可能是idk(,以及当base64Decode方法调用时

在flutter web上,当get方法调用时,flutter完全卷曲(onSendProgress此时也不起作用(,并且在chrome应用程序崩溃后,代码为5,可能在一两分钟后-_-

context不是BuildContext

httpClient是Dio HTTP客户端

transformOf检查请求结果是否为错误,如果是,将请求结果转换为我的flutter自定义异常,抛出后返回请求结果。

请求结果大小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']);
}

如何优化此代码以进行处置冻结?

默认情况下,Flutter应用程序在一个UI线程上完成所有工作。如果你试图在UI线程内执行昂贵的计算,你的应用程序的UI就会冻结。

问题

在您的情况下,base64Decode(result['bookBytes']);是一个非常昂贵的计算。(因为它解码大数据集(20-50mb((

解决方案

您可以通过使用单独的隔离来运行上述昂贵的任务来解决此问题。(参见以下代码(

  1. 创建一个名为parseBookBytes()的方法,将昂贵的baseDecode64()任务放入其中

  2. 使用compute((函数在单独的隔离中执行parseBookBytes()

// 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
}

资源

  1. 链接1
  2. 链接2
  3. 链接3

为了解决这个问题,我创建了2个解析和2个计算函数

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);
}

在我为json 创建了简单的dio转换器之后

class JsonTransformer extends DefaultTransformer {
JsonTransformer() : super(jsonDecodeCallback: parseJsonCompute);
}

并应用此

httpClient.transformer = JsonTransformer();

重构后的函数是

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

最新更新