putIfAbsent method

ImageStreamCompleter putIfAbsent (Object key, ImageStreamCompleter loader(), { ImageErrorListener onError })

Returns the previously cached ImageStream for the given key, if available; if not, calls the given callback to obtain it first. In either case, the key is moved to the "most recently used" position.

The arguments must not be null. The loader cannot return null.

In the event that the loader throws an exception, it will be caught only if onError is also provided. When an exception is caught resolving an image, no completers are cached and null is returned instead of a new completer.

Implementation

ImageStreamCompleter putIfAbsent(Object key, ImageStreamCompleter loader(), { ImageErrorListener onError }) {
  assert(key != null);
  assert(loader != null);
  ImageStreamCompleter result = _pendingImages[key]?.completer;
  // Nothing needs to be done because the image hasn't loaded yet.
  if (result != null)
    return result;
  // Remove the provider from the list so that we can move it to the
  // recently used position below.
  final _CachedImage image = _cache.remove(key);
  if (image != null) {
    _cache[key] = image;
    return image.completer;
  }
  try {
    result = loader();
  } catch (error, stackTrace) {
    if (onError != null) {
      onError(error, stackTrace);
      return null;
    } else {
      rethrow;
    }
  }
  void listener(ImageInfo info, bool syncCall) {
    // Images that fail to load don't contribute to cache size.
    final int imageSize = info?.image == null ? 0 : info.image.height * info.image.width * 4;
    final _CachedImage image = _CachedImage(result, imageSize);
    // If the image is bigger than the maximum cache size, and the cache size
    // is not zero, then increase the cache size to the size of the image plus
    // some change.
    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);
    // Listener is removed in [_PendingImage.removeListener].
    result.addListener(streamListener);
  }
  return result;
}