Flutter cached_network_image使用Dio请求图片
背景
在Flutter中通常使用cached_network_image控件显示图片,该控件使用http库请求图片,http库无法像dio一样方便的添加拦截器等。
实现
CachedNetworkImage使用flutter_cache_manager进行图片缓存,可以使用自定义cache_manager来替换http为dio。 如下:
class DioCacheManager extends CacheManager { static const key = 'dioCache'; static DioCacheManager _instance; factory DioCacheManager(Dio dio) { if (_instance == null) { _instance = DioCacheManager._(dio); } return _instance; } DioCacheManager._(Dio dio) : super(Config(key, fileService: DioHttpFileService(dio))); }
class DioHttpFileService extends FileService { Dio _dio; DioHttpFileService(this._dio); @override Future<FileServiceResponse> get(String url, {Map<String, String> headers}) async { Options options = Options(headers: headers ?? {}, responseType: ResponseType.stream); Response<ResponseBody> httpResponse = await _dio.get<ResponseBody>(url, options: options); return DioGetResponse(httpResponse); } } class DioGetResponse implements FileServiceResponse { final DateTime _receivedTime = DateTime.now(); Response<ResponseBody> _response; DioGetResponse(this._response); @override Stream<List<int>> get content => _response.data.stream; @override int get contentLength => _getContentLength(); @override String get eTag => _response.headers['etag']?.first ?? '-1'; @override String get fileExtension { var fileExtension = ''; final contentTypeHeader = _response.headers[Headers.contentTypeHeader]?.first; if (contentTypeHeader != null) { final contentType = ContentType.parse(contentTypeHeader); fileExtension = mimeTypes[contentType.mimeType]; } return fileExtension; } @override int get statusCode => _response.statusCode; @override DateTime get validTill { // Without a cache-control header we keep the file for a week var ageDuration = const Duration(days: 7); final controlHeader = _response.headers['cache-control']?.first; if (controlHeader != null) { final controlSettings = controlHeader.split(','); for (final setting in controlSettings) { final sanitizedSetting = setting.trim().toLowerCase(); if (sanitizedSetting == 'no-cache') { ageDuration = const Duration(); } if (sanitizedSetting.startsWith('max-age=')) { var validSeconds = int.tryParse(sanitizedSetting.split('=')[1]) ?? 0; if (validSeconds > 0) { ageDuration = Duration(seconds: validSeconds); } } } } return _receivedTime.add(ageDuration); } int _getContentLength() { try { return int.parse( _response.headers[Headers.contentLengthHeader]?.first ?? '-1'); } catch (e) { return -1; } } }
使用方法
dependencies: flutter_cache_manager_dio: ^2.0.0
CachedNetworkImage( cacheManager: DioCacheManager(dio), imageUrl: url, placeholder: (context, url) => CircularProgressIndicator(), errorWidget: (context, url, error) => Container( child: Text( 'error', ), ), );
然后就可以使用dio的拦截等功能了,比如使用拦截器添加并刷新token,添加log等功能。