如何优化此 HTTP 请求方法以在 UI 线程中处理冻结?
How Optimize this HTTP Request Method for Dispose Freezes in UI Thread?
当我 运行 这个方法时,在 flutter 中,例如当我 onTap
在手势检测器中 flutter 冻结 2 次,当 get
方法调用时(我认为那里是因为Dio json 转换器,也许,idk),当 base64Decode
方法调用时
在 flutter web 上,当 get
方法调用时,flutter 完全崩溃(onSendProgress
此时也无法正常工作)并且在 chrome 中的此应用程序崩溃后代码 5 ,一两分钟后 -_-
context
不是 BuildContext
httpClient
是 Dio HTTP 客户端
transformOf
检查请求结果是否错误,如果是,则将请求结果转换为我的flutter自定义异常,抛出后,否则return请求结果。
请求结果大小为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))
解决方案
您可以通过为 运行 上述昂贵的任务使用 单独的 Isolate 来解决这个问题。 (见下面的代码)
创建一个名为 parseBookBytes()
的方法,将昂贵的 baseDecode64()
任务放入其中。
使用 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
}
资源
为了解决这个问题,我创建了 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']);;
}
当我 运行 这个方法时,在 flutter 中,例如当我 onTap
在手势检测器中 flutter 冻结 2 次,当 get
方法调用时(我认为那里是因为Dio json 转换器,也许,idk),当 base64Decode
方法调用时
在 flutter web 上,当 get
方法调用时,flutter 完全崩溃(onSendProgress
此时也无法正常工作)并且在 chrome 中的此应用程序崩溃后代码 5 ,一两分钟后 -_-
context
不是 BuildContext
httpClient
是 Dio HTTP 客户端
transformOf
检查请求结果是否错误,如果是,则将请求结果转换为我的flutter自定义异常,抛出后,否则return请求结果。
请求结果大小为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))
解决方案
您可以通过为 运行 上述昂贵的任务使用 单独的 Isolate 来解决这个问题。 (见下面的代码)
创建一个名为
parseBookBytes()
的方法,将昂贵的baseDecode64()
任务放入其中。使用 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
}
资源
为了解决这个问题,我创建了 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']);;
}