Unverified Commit 14f3a36a authored by Dan Field's avatar Dan Field Committed by GitHub

Clear ImageCache on MemoryPressure (#53959)

parent 4b92c167
......@@ -99,6 +99,12 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
imageCache.clearLiveImages();
}
@override
void handleMemoryPressure() {
super.handleMemoryPressure();
imageCache.clear();
}
/// Listenable that notifies when the available fonts on the system have
/// changed.
///
......
......@@ -48,13 +48,32 @@ mixin ServicesBinding on BindingBase {
return const _DefaultBinaryMessenger._();
}
/// Called when the operating system notifies the application of a memory
/// pressure situation.
///
/// This method exposes the `memoryPressure` notification from
/// [SystemChannels.system].
@protected
@mustCallSuper
void handleMemoryPressure() { }
/// Handler called for messages received on the [SystemChannels.system]
/// message channel.
///
/// Other bindings may override this to respond to incoming system messages.
@protected
@mustCallSuper
Future<void> handleSystemMessage(Object systemMessage) async { }
Future<void> handleSystemMessage(Object systemMessage) async {
final Map<String, dynamic> message = systemMessage as Map<String, dynamic>;
final String type = message['type'] as String;
switch (type) {
case 'memoryPressure':
handleMemoryPressure();
break;
}
return;
}
/// Adds relevant licenses to the [LicenseRegistry].
///
......
......@@ -655,32 +655,13 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
observer.didChangeAppLifecycleState(state);
}
/// Called when the operating system notifies the application of a memory
/// pressure situation.
///
/// Notifies all the observers using
/// [WidgetsBindingObserver.didHaveMemoryPressure].
///
/// This method exposes the `memoryPressure` notification from
/// [SystemChannels.system].
@override
void handleMemoryPressure() {
super.handleMemoryPressure();
for (final WidgetsBindingObserver observer in _observers)
observer.didHaveMemoryPressure();
}
@override
Future<void> handleSystemMessage(Object systemMessage) async {
await super.handleSystemMessage(systemMessage);
final Map<String, dynamic> message = systemMessage as Map<String, dynamic>;
final String type = message['type'] as String;
switch (type) {
case 'memoryPressure':
handleMemoryPressure();
break;
}
return;
}
bool _needToReportFirstFrame = true;
final Completer<void> _firstFrameCompleter = Completer<void>();
......
......@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data' show Uint8List;
import 'dart:ui';
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
......@@ -11,21 +10,22 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/painting.dart';
import 'image_data.dart';
import 'painting_utils.dart';
void main() {
final PaintingBindingSpy binding = PaintingBindingSpy();
test('instantiateImageCodec used for loading images', () async {
expect(binding.instantiateImageCodecCalledCount, 0);
final Uint8List bytes = Uint8List.fromList(kTransparentImage);
final MemoryImage memoryImage = MemoryImage(bytes);
memoryImage.load(memoryImage, (Uint8List bytes, {int cacheWidth, int cacheHeight}) {
return PaintingBinding.instance.instantiateImageCodec(bytes, cacheWidth: cacheWidth, cacheHeight: cacheHeight);
});
expect(binding.instantiateImageCodecCalledCount, 1);
testWidgets('didHaveMemoryPressure clears imageCache', (WidgetTester tester) async {
imageCache.putIfAbsent(1, () => OneFrameImageStreamCompleter(
Future<ImageInfo>.value(ImageInfo(
image: FakeImage(),
scale: 1.0,
),
)));
await tester.idle();
expect(imageCache.currentSize, 1);
final ByteData message = const JSONMessageCodec().encodeMessage(
<String, dynamic>{'type': 'memoryPressure'});
await ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage('flutter/system', message, (_) { });
expect(imageCache.currentSize, 0);
});
test('evict clears live references', () async {
......@@ -84,7 +84,7 @@ class TestBindingBase implements BindingBase {
void unlocked() {}
@override
Window get window => throw UnimplementedError();
ui.Window get window => throw UnimplementedError();
}
class TestPaintingBinding extends TestBindingBase with ServicesBinding, PaintingBinding {
......@@ -111,4 +111,20 @@ class FakeImageCache extends ImageCache {
liveClearCount += 1;
super.clearLiveImages();
}
}
\ No newline at end of file
}
class FakeImage implements ui.Image {
@override
void dispose() {}
@override
int get height => 10;
@override
Future<ByteData> toByteData({ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba}) {
throw UnimplementedError();
}
@override
int get width => 10;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment