Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
86dd664f
Unverified
Commit
86dd664f
authored
Dec 05, 2019
by
gaaclarke
Committed by
GitHub
Dec 05, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Made the behavior for caching large images modular. (#46010)
Introduced LargeImageHandler to ImageCache class.
parent
ec0842e0
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
62 additions
and
5 deletions
+62
-5
image_cache.dart
packages/flutter/lib/src/painting/image_cache.dart
+42
-5
image_cache_test.dart
packages/flutter/test/painting/image_cache_test.dart
+20
-0
No files found.
packages/flutter/lib/src/painting/image_cache.dart
View file @
86dd664f
...
@@ -7,6 +7,9 @@ import 'image_stream.dart';
...
@@ -7,6 +7,9 @@ import 'image_stream.dart';
const
int
_kDefaultSize
=
1000
;
const
int
_kDefaultSize
=
1000
;
const
int
_kDefaultSizeBytes
=
100
<<
20
;
// 100 MiB
const
int
_kDefaultSizeBytes
=
100
<<
20
;
// 100 MiB
/// Function used by [ImageCache.largeImageHandler].
typedef
LargeImageHandler
=
void
Function
(
ImageCache
,
int
);
/// Class for caching images.
/// Class for caching images.
///
///
/// Implements a least-recently-used cache of up to 1000 images, and up to 100
/// Implements a least-recently-used cache of up to 1000 images, and up to 100
...
@@ -90,6 +93,28 @@ class ImageCache {
...
@@ -90,6 +93,28 @@ class ImageCache {
int
get
currentSizeBytes
=>
_currentSizeBytes
;
int
get
currentSizeBytes
=>
_currentSizeBytes
;
int
_currentSizeBytes
=
0
;
int
_currentSizeBytes
=
0
;
/// Callback that is executed when inserting an image whose byte size is
/// larger than the [maximumByteSize]. Editing the [maximumByteSize] in the
/// callback can accomodate for the image. Set to `null` for the default
/// behavior, which is to increase the [maximumByteSize] to accomodate the
/// large image.
///
/// {@tool sample}
///
/// Here is an example implementation that increases the cache size in
/// response to a large image:
/// ```dart
/// void handler(ImageCache imageCache, int imageSize) {
/// final int newSize = imageSize + 1000;
/// imageCache.maximumSizeBytes = newSize;
/// print("Increase image cache size: $newSize");
/// }
/// ```
set
largeImageHandler
(
LargeImageHandler
handler
)
{
_largeImageHandler
=
handler
;
}
LargeImageHandler
_largeImageHandler
;
/// Evicts all entries from the cache.
/// Evicts all entries from the cache.
///
///
/// This is useful if, for instance, the root asset bundle has been updated
/// This is useful if, for instance, the root asset bundle has been updated
...
@@ -170,12 +195,16 @@ class ImageCache {
...
@@ -170,12 +195,16 @@ class ImageCache {
// Images that fail to load don't contribute to cache size.
// 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
int
imageSize
=
info
?.
image
==
null
?
0
:
info
.
image
.
height
*
info
.
image
.
width
*
4
;
final
_CachedImage
image
=
_CachedImage
(
result
,
imageSize
);
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
if
(
_isImageTooLarge
(
imageSize
))
{
// some change.
final
LargeImageHandler
handler
=
_largeImageHandler
??
_bumpUpMaximumSizeLargeImageHandler
;
if
(
maximumSizeBytes
>
0
&&
imageSize
>
maximumSizeBytes
)
{
handler
(
this
,
imageSize
);
_maximumSizeBytes
=
imageSize
+
1000
;
if
(
_isImageTooLarge
(
imageSize
))
{
// Abort insertion of image, it doesn't fit.
return
;
}
}
}
_currentSizeBytes
+=
imageSize
;
_currentSizeBytes
+=
imageSize
;
final
_PendingImage
pendingImage
=
_pendingImages
.
remove
(
key
);
final
_PendingImage
pendingImage
=
_pendingImages
.
remove
(
key
);
if
(
pendingImage
!=
null
)
{
if
(
pendingImage
!=
null
)
{
...
@@ -194,6 +223,14 @@ class ImageCache {
...
@@ -194,6 +223,14 @@ class ImageCache {
return
result
;
return
result
;
}
}
bool
_isImageTooLarge
(
int
imageSize
)
{
return
maximumSizeBytes
>
0
&&
imageSize
>
maximumSizeBytes
;
}
static
void
_bumpUpMaximumSizeLargeImageHandler
(
ImageCache
imageCache
,
int
imageSize
)
{
imageCache
.
maximumSizeBytes
=
imageSize
+
1000
;
}
// Remove images from the cache until both the length and bytes are below
// Remove images from the cache until both the length and bytes are below
// maximum, or the cache is empty.
// maximum, or the cache is empty.
void
_checkCacheSize
()
{
void
_checkCacheSize
()
{
...
...
packages/flutter/test/painting/image_cache_test.dart
View file @
86dd664f
...
@@ -15,6 +15,7 @@ void main() {
...
@@ -15,6 +15,7 @@ void main() {
});
});
tearDown
(()
{
tearDown
(()
{
imageCache
.
largeImageHandler
=
null
;
imageCache
.
clear
();
imageCache
.
clear
();
imageCache
.
maximumSize
=
1000
;
imageCache
.
maximumSize
=
1000
;
imageCache
.
maximumSizeBytes
=
10485760
;
imageCache
.
maximumSizeBytes
=
10485760
;
...
@@ -131,6 +132,25 @@ void main() {
...
@@ -131,6 +132,25 @@ void main() {
expect
(
imageCache
.
maximumSizeBytes
,
256
+
1000
);
expect
(
imageCache
.
maximumSizeBytes
,
256
+
1000
);
});
});
test
(
'Large image handler that rejects an image.'
,
()
async
{
bool
wasCalled
=
false
;
imageCache
.
largeImageHandler
=
(
ImageCache
imageCache
,
int
imageSize
)
{
wasCalled
=
true
;
};
const
TestImage
testImage1
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage2
=
TestImage
(
width:
16
,
height:
16
);
imageCache
.
maximumSizeBytes
=
256
;
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage1
).
resolve
(
ImageConfiguration
.
empty
));
expect
(
imageCache
.
currentSize
,
1
);
expect
(
imageCache
.
currentSizeBytes
,
256
);
expect
(
imageCache
.
maximumSizeBytes
,
256
);
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
,
image:
testImage2
).
resolve
(
ImageConfiguration
.
empty
));
expect
(
imageCache
.
currentSize
,
1
);
expect
(
imageCache
.
currentSizeBytes
,
256
);
expect
(
imageCache
.
maximumSizeBytes
,
256
);
expect
(
wasCalled
,
isTrue
);
});
test
(
'Returns null if an error is caught resolving an image'
,
()
{
test
(
'Returns null if an error is caught resolving an image'
,
()
{
final
ErrorImageProvider
errorImage
=
ErrorImageProvider
();
final
ErrorImageProvider
errorImage
=
ErrorImageProvider
();
expect
(()
=>
imageCache
.
putIfAbsent
(
errorImage
,
()
=>
errorImage
.
load
(
errorImage
,
null
)),
throwsA
(
isInstanceOf
<
Error
>()));
expect
(()
=>
imageCache
.
putIfAbsent
(
errorImage
,
()
=>
errorImage
.
load
(
errorImage
,
null
)),
throwsA
(
isInstanceOf
<
Error
>()));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment