面试题答案
一键面试优化策略确保下载稳定性和高效性
- 设置合理的超时时间:
在使用Dio发起下载请求时,设置适当的连接超时(
connectTimeout
)和接收超时(receiveTimeout
)。例如:
Dio dio = Dio();
dio.options.connectTimeout = 10000; // 10秒连接超时
dio.options.receiveTimeout = 30000; // 30秒接收超时
这样可以避免因长时间等待无响应而占用资源。
2. 重试机制:
当网络请求失败(如丢包导致的失败)时,实现重试逻辑。可以使用RetryInterceptor
来实现,示例如下:
class RetryInterceptor extends Interceptor {
final int maxRetries;
RetryInterceptor({this.maxRetries = 3});
@override
void onError(DioError err, ErrorInterceptorHandler handler) async {
if (err.type == DioErrorType.connectTimeout ||
err.type == DioErrorType.sendTimeout ||
err.type == DioErrorType.receiveTimeout) {
int retryCount = 0;
while (retryCount < maxRetries) {
try {
final response = await err.requestOptions.retry();
return handler.resolve(response);
} catch (e) {
retryCount++;
}
}
return handler.reject(err);
}
return handler.reject(err);
}
}
然后将该拦截器添加到Dio中:
Dio dio = Dio();
dio.interceptors.add(RetryInterceptor());
- 优化网络请求:
- 压缩:如果服务器支持,启用gzip压缩,在Dio的
options
中设置headers
:
- 压缩:如果服务器支持,启用gzip压缩,在Dio的
dio.options.headers = {'accept-encoding': 'gzip'};
- **缓存**:对于部分不经常更新的文件,可以利用Dio的缓存功能,设置`CacheOptions`:
dio.interceptors.add(CacheInterceptor(
options: CacheOptions(
store: MemCacheStore(),
maxStale: const Duration(days: 7),
),
));
- 优化下载速度:
- 多线程下载:虽然Flutter是单线程的,但可以利用
Isolate
实现多线程下载。将文件分成多个部分,每个Isolate
负责下载一部分,最后合并。例如,可以根据文件大小计算每个线程下载的字节范围,通过dio.download
指定onReceiveProgress
和range
参数实现。 - 优化I/O操作:在文件写入时,使用异步I/O操作,避免阻塞主线程。可以使用
dart:io
中的File.writeAsBytes
等异步方法。
- 多线程下载:虽然Flutter是单线程的,但可以利用
断点续传功能实现
- 获取已下载长度:
在开始下载前,检查本地已下载文件的大小,以此作为断点续传的起点。可以使用
File
类的lengthSync
方法获取文件长度,例如:
import 'dart:io';
File file = File('path/to/downloaded/file');
if (file.existsSync()) {
int downloadedLength = file.lengthSync();
// 后续使用downloadedLength作为断点续传的起点
}
- 设置请求头:
在发起下载请求时,通过
Range
请求头指定从哪个字节开始下载。例如:
dio.download(url, savePath,
onReceiveProgress: (received, total) {
// 下载进度处理
},
options: Options(
headers: {'Range': 'bytes=$downloadedLength-'}));
- 合并文件:
如果采用多线程下载,下载完成后需要将各个部分的文件合并成完整的文件。可以使用
File
类的writeAsBytes
方法将各部分字节数据依次写入目标文件。例如,假设有多个临时文件part1
、part2
等,合并代码如下:
List<File> partFiles = [File('part1'), File('part2')];
File finalFile = File('final_file');
List<int> allBytes = [];
for (var partFile in partFiles) {
allBytes.addAll(await partFile.readAsBytes());
}
await finalFile.writeAsBytes(allBytes);