-
Notifications
You must be signed in to change notification settings - Fork 27.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Live image cache #50318
Live image cache #50318
Conversation
Argh. I meant to open this as a draft. Oh well. |
expect(imageStreamCompleter.listeners.length, 0); | ||
// Make sure the second listener can be called re-entrantly. | ||
listeners[0].onImage(null, null); | ||
listeners[0].onImage(null, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is meant to land in #50316
/// | ||
/// To obtain an [ImageCacheLocation], use [FlutterImageCache.locationForKey] or | ||
/// [ImageProvider.findCacheLocation]. | ||
class ImageCacheLocation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/cc @jamesderlin who was looking for a way to know if an image was pending in the cache.
d953dda
to
257ef91
Compare
final FlutterImageCache flutterImageCache = imageCache as FlutterImageCache; | ||
expect(flutterImageCache.locationForKey(testImage).pending, true); | ||
expect(flutterImageCache.locationForKey(testImage).weak, true); | ||
flutterImageCache.clear(); | ||
expect(flutterImageCache.locationForKey(testImage).pending, false); | ||
expect(flutterImageCache.locationForKey(testImage).weak, true); | ||
flutterImageCache.clearWeakImages(); | ||
expect(flutterImageCache.locationForKey(testImage).pending, false); | ||
expect(flutterImageCache.locationForKey(testImage).weak, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clear does remove the pending image, but this test no longer captures how to check if an image is pending or not.
This test could be independently rewritten without these changes to use the existing containsKey
API, although the new API offers more robust ways to check if an image is pending.
/// This method exists so that [FlutterImageCache] can add to its weak cache | ||
/// once an [ImageStreamCompleter] has been created by this cache. | ||
@protected | ||
void _onImageStreamCompleterCreated(Object key, ImageStreamCompleter completer) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_handleImageStreamCompleterCreated per style guide
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing this since we're just going to break the API
|
||
/// Clears any weak references to images in this cache. | ||
/// | ||
/// This should not ordinarily be called by applications. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than saying it shouldn't be called, say when it should be called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
/// This cache also exposes internal dimensions of the implementation, such as | ||
/// checking whether an image for a given key is pending, weak, or completed. | ||
/// See [ImageCacheLocation] for more details. | ||
class FlutterImageCache extends ImageCache { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the api design review meeting we discussed just merging FlutterImageCache into ImageCache, and make the test-only features be methods called debugFoo...
with their bodies in asserts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm leaning towards making these non-debug/assert methods at this point - this could be valuable information at runtime (e.g. if an application wants to know how many live images are on the screen before decoding more). I'm also documenting [precacheImage] as relying on this behavior now.
stream.removeListener(listener); | ||
// Give callers at least one frame to subscribe to the image stream | ||
// so that FlutterImageCache can weakly hold it without losing it. | ||
SchedulerBinding.instance.scheduleFrameCallback((Duration timeStamp) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should probably be schedulePostFrameCallback so that you don't actually schedule a frame
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, and updated tests relevant to this to actually schedule a frame where needed.
@@ -65,9 +65,11 @@ mixin PaintingBinding on BindingBase, ServicesBinding { | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please avoid the word "weak" throughout
I've merged in the image tracing tests. This should be fully ready for review and landing on approval. |
611b5a8
to
d60d64e
Compare
(Fixed some bugs in my last push - I had forgotten to delete some code and had a bad assert in there) |
/// Returns whether this `key` has been previously added by [putIfAbsent]. | ||
bool containsKey(Object key) { | ||
return _pendingImages[key] != null || _cache[key] != null; | ||
} | ||
|
||
/// The number of live images being held by the [ImageCache]. | ||
/// | ||
/// Compare with [ImageCache.currentSize] for completed held images. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what "completed held images" is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed a text replacement. done.
/// | ||
/// A [pending] image is one that has not completed yet. It may also be tracked | ||
/// as [live] because something is listening to it. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove one blank line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
}; | ||
|
||
|
||
// If an error is added to a synchronous completer before a listener has been |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, isn't the other occurence also in this file? Could this be just be refactored into a private method? I don't think there's any danger of anybody accessing a private method from here?
return; | ||
} | ||
_liveImages[key] = image; | ||
image.completer.addOnLastListenerRemovedCallback(() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if nobody ever listens to the stream (and hence this callback never fires)? It appears that we'd never remove the image from the live cache?
Ahh I got mixed up about the dangerzone stuff - I thought that one was on ImageCache. I'll refactor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Quick update on this: When I opened the PR, it was a breaking change. During the course of work on this PR, the tests it broke no longer were breaking (in fact, they disappeared entirely!). On landing it, it no longer breaks our compatibility guidelines (https://flutter.dev/docs/resources/compatibility). I'll still send an email to Flutter-announce explaining this. |
And if anyone would really like to see a migration guide for this, I can certainly write one :) |
This reverts commit 2f09d60.
Please I want to know version1.17.0 ImageCache add liveImage how to useful。 |
It is automatic |
Sorry, actually I mean want to ask what it does |
The design doc and linked PRs have more details, but in a nutshell this makes sure that once you resolve an image, it continues to be reachable as long as its listener count has not dropped to zero, even if it did not otherwise fit in the image cache. This is important especially for large images or cache configurations that do not allow for many images. |
WIP - this should not land until #50316; design doc for this is at https://flutter.dev/go/widget-tree-image-cache, although the approach has changed a bit since writing the doc. /cc @goderbauer @ds84182 @liyuqian @gaaclarke @ignatz @alml
Description
Related Issues
fixes #48731
fixes #49456
fixes #45406
Tests
I added the following tests:
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]
). This will ensure a smooth and quick review process.///
).flutter analyze --flutter-repo
) does not report any problems on my PR.Breaking Change
Did any tests fail when you ran them? Please read Handling breaking changes.
I don't believe this is a breaking change, but once this is cleaned up a bit I'll manually run it through google's internal test suites.