_updateInvertColors();
_resolveImage();//解析图片从这里开始
//设置和移除监听图片变化的回调
if (TickerMode.of(context))
_listenToStream();
else
_stopListeningToStream();
super.didChangeDependencies();
}
void _resolveImage() {
//根据 ImageConfiguration 调用 ImageProvider 的 resolve 函数获得 ImageStream 对象
final ImageStream newStream = widget.image.resolve(createLocalImageConfiguration(
context,
size: widget.width != null && widget.height != null ? Size(widget.width, widget.height) : null,
));
_updateSourceStream(newStream);
}
…
}
它的生命周期方法方法包括initState()
、didChangeDependencies()
、build()
、deactivate()
、dispose()
、didUpdateWidget()
等等。当它插入到渲染树时,先调用initState()
函数,再调用 didChangeDependencies()
。代码中可以看到调用了方法 _resolveImage(),这个方法中创建了 ImageStream 的新对象 newStream 。widget.image 就是 ImageProvider,调用resolve方法,代码如下:
ImageStream resolve(ImageConfiguration configuration) {
final ImageStream stream = ImageStream();
T obtainedKey;
bool didError = false;
Future handleError(dynamic exception, StackTrace stack) async {
if (didError) {
return;
}
didError = true;
await null; // 等待事件轮询,以防侦听器被添加到图像流中。
final _ErrorImageCompleter imageCompleter = _ErrorImageCompleter();
stream.setCompleter(imageCompleter);
…
}
…
Future key;
try {
key = obtainKey(configuration);
} catch (error, stackTrace) {
return;
}
key.then((T key) {
obtainedKey = key;
final ImageStreamCompleter completer =
PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key), onError: handleError);
if (completer != null) {
stream.setCompleter(completer);
}
}).catchError(handleError);
return stream;
ImageStreamCompleter 用于管理 dart:ui 加载的类的基类。ImageStreams 的对象很少直接构造,而是由 ImageStreamCompleter 自动配置它。ImageStream 中的图片管理者 ImageStreamCompleter 通过方法创建,imageCache 是 Flutter 框架中实现的用于图片缓存的单例,它这 Dart 虚拟机加载时就已经创建。imageCache 最多可缓存 1000 张图像和 100MB 内存空间。可以使用 [maximumSize] 和 [maximumSizeBytes]调整最大大小。
PaintingBinding.instance.imageCache.putIfAbsent(key, () => load(key), onError: handleError);
根据源码可以看到两个关键方法 :putIfAbsent 和 load。
putIfAbsent
ImageStreamCompleter putIfAbsent(Object key, ImageStreamCompleter loader(), {ImageErrorListener onError }) {
ImageStreamCompleter result = _pendingImages[key]?.completer;
// 因为图像还没有加载,不需要做任何事情。
if (result != null)
return result;
// 从缓存列表中根据Key删除对应的 imageprovider,便于将它移动到下面最近使用位置。
final _CachedImage image = _cache.remove(key);
if (image != null) {
_cache[key] = image;
return image.completer;
}
try {
result = loader();
} catch (error, stackTrace) {
…
}
void listener(ImageInfo info, bool syncCall) {
// 无法加载的图像不会占用缓存大小。
final int imageSize = info?.image == null ? 0 : info.image.height * info.image.width * 4;
final _CachedImage image = _CachedImage(result, imageSize);
// 如果图像大于最大缓存大小,且缓存大小不为零,则将缓存大小增加到图像大小加上 1000。
// 思考点:一直这么加什么时候引起崩溃?
if (maximumSizeBytes > 0 && imageSize > maximumSizeBytes) {
_maximumSizeBytes = imageSize + 1000;
}
_currentSizeBytes += imageSize;
final _PendingImage pendingImage = _pendingImages.remove(key);
if (pendingImage != null) {
pendingImage.removeListener();
}
_cache[key] = image;
_checkCacheSize();
}
if (maximumSize > 0 && maximumSizeBytes > 0) {
final ImageStreamListener streamListener = ImageStreamListener(listener);
_pendingImages[key] = _PendingImage(result, streamListener);
// 移除 [_PendingImage.removeListener] 上的监听
result.addListener(streamListener);
}
return result;
}
load
/// 拉取网络图片的 image_provider.NetworkImage 具体实现.
class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkImage> implements image_provider.NetworkImage {
…
@override
ImageStreamCompleter load(image_provider.NetworkImage key) {
final StreamController chunkEvents = StreamController();
return MultiFrameImageStreamCompleter(
codec: _loadAsync(key, chunkEvents),
chunkEvents: chunkEvents.stream,
scale: key.scale,
informationCollector: () {
return [
DiagnosticsProperty<image_provider.ImageProvider>(‘Image provider’, this),
DiagnosticsProperty<image_provider.NetworkImage>(‘Image key’, key),
];
},
);
}
loadAsync
Future<ui.Codec> _loadAsync(
NetworkImage key,
StreamController chunkEvents,
) async {
try {
final Uri resolved = Uri.base.resolve(key.url);
final HttpClientRequest request = await _httpClient.getUrl(resolved);
headers?.forEach((String name, String value) {
request.headers.add(name, value);
});
final HttpClientResponse response = await request.close();
if (response.statusCode != HttpStatus.ok)
throw image_provider.NetworkImageLoadException(statusCode: response.statusCode, uri: resolved);
//将网络返回的 response 信息,转换成内存中的 Uint8List bytes。这里面有解压 gzip 的逻辑。
final Uint8List bytes = await consolidateHttpClientResponseBytes(
response,
onBytesReceived: (int cumulative, int total) {
chunkEvents.add(ImageChunkEvent(
cumulativeBytesLoaded: cumulative,
expectedTotalBytes: total,
));
},
);
if (bytes.lengthInBytes == 0)
throw Exception(‘NetworkImage is an empty file: $resolved’);
return PaintingBinding.instance.instantiateImageCodec(bytes);
} finally {
chunkEvents.close();
}
}
将网络返回的response信息,转换成内存中的 Uint8List bytes,最终返回一个实例化图像编解码器对象Codec,此处 Codec 可以移步到 painting.dart 文件的 _instantiateImageCodec 看出来它是调用了native方法去处理了。
MultiFrameImageStreamCompleter
这个对象就是 ImageStreamCompleter 的具体实现,见名知意,多帧图片流管理,作用管理图像帧的解码和调度。
这个类处理两种类型的帧:
-
图像帧 :动画图像的图像帧。
-
app 帧 :Flutter 引擎绘制到屏幕的帧,显示到应用程序 GUI。
这就不贴所有代码了,在 image_stream.dart 文件中 可见 class MultiFrameImageStreamCompleter。
MultiFrameImageStreamCompleter({
@required Future<ui.Codec> codec,
@required double scale,
Stream chunkEvents,
InformationCollector informationCollector,
}) : assert(codec != null),
_informationCollector = informationCollector,
_scale = scale {
codec.then(_handleCodecReady, onError: (dynamic error, StackTrace stack) {
…
});
_handleCodecReady
这里 codec 异步回调次方法
void _handleCodecReady(ui.Codec codec) {
_codec = codec;
if (hasListeners) {
_decodeNextFrameAndSchedule();
}
}
_decodeNextFrameAndSchedule
codec 解码获取到图片的帧数,判断图片是只有一帧的话,就是png、jpg这样静态图片。
Future _decodeNextFrameAndSchedule() async {
try {
_nextFrame = await _codec.getNextFrame();
} catch (exception, stack) {
…
return;
}
if (_codec.frameCount == 1) { // 此处判断图片是只有一帧的逻辑.
_emitFrame(ImageInfo(image: _nextFrame.image, scale: _scale));
return;
}
_scheduleAppFrame();
}
void _scheduleAppFrame() {
if (_frameCallbackScheduled) {
return;
}
_frameCallbackScheduled = true;
SchedulerBinding.instance.scheduleFrameCallback(_handleAppFrame);
}
_emitFrame(ImageInfo(image: _nextFrame.image, scale: _scale));
void _emitFrame(ImageInfo imageInfo) {
setImage(imageInfo);
_framesEmitted += 1;
}
@protected
void setImage(ImageInfo image) {
_currentImage = image;
if (_listeners.isEmpty)
return;
// 复制一份以允许并发修改。
final List localListeners = List.from(_listeners);
for (ImageStreamListener listener in localListeners) {
try {
listener.onImage(image, false);
} catch (exception, stack) {
…
}
}
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
要如何成为Android架构师?
搭建自己的知识框架,全面提升自己的技术体系,并且往底层源码方向深入钻研。
大多数技术人喜欢用思维脑图来构建自己的知识体系,一目了然。这里给大家分享一份大厂主流的Android架构师技术体系,可以用来搭建自己的知识框架,或者查漏补缺;
对应这份技术大纲,我也整理了一套Android高级架构师完整系列的视频教程,主要针对3-5年Android开发经验以上,需要往高级架构师层次学习提升的同学,在这里点击GitHub免费分享,希望能帮你突破瓶颈,跳槽进大厂;
最后我必须强调几点:
1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。
2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识
3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。
你只需要按照在这个大的框架去填充自己,年薪40W一定不是终点,技术无止境
bs.csdn.net/topics/618156601)**,希望能帮你突破瓶颈,跳槽进大厂;
最后我必须强调几点:
1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。
2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识
3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。
你只需要按照在这个大的框架去填充自己,年薪40W一定不是终点,技术无止境