Provide an observatory extension to evict resources (#5241)
...so that you can use hot reload mode to update assets.
diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart
index 0cdfff5..31bd199 100644
--- a/packages/flutter/lib/src/services/asset_bundle.dart
+++ b/packages/flutter/lib/src/services/asset_bundle.dart
@@ -62,6 +62,11 @@
/// used with one parser for the lifetime of the asset bundle.
Future<dynamic> loadStructuredData(String key, dynamic parser(String value));
+ /// If this is a caching asset bundle, and the given key describes a cached
+ /// asset, then evict the asset from the cache so that the next time it is
+ /// loaded, the cache will be reread from the asset bundle.
+ void evict(String key) { }
+
@override
String toString() => '$runtimeType@$hashCode()';
}
@@ -101,6 +106,9 @@
return parser(await loadString(key));
}
+ // TODO(ianh): Once the underlying network logic learns about caching, we
+ // should implement evict().
+
@override
String toString() => '$runtimeType@$hashCode($_baseUrl)';
}
@@ -155,6 +163,12 @@
});
return completer.future;
}
+
+ @override
+ void evict(String key) {
+ _stringCache.remove(key);
+ _structuredDataCache.remove(key);
+ }
}
/// An [AssetBundle] that loads resources from a Mojo service.
diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart
index c223ffc..415f413 100644
--- a/packages/flutter/lib/src/services/binding.dart
+++ b/packages/flutter/lib/src/services/binding.dart
@@ -7,6 +7,7 @@
import 'package:flutter/foundation.dart';
import 'asset_bundle.dart';
+import 'image_cache.dart';
import 'shell.dart';
/// Ensures that the [MojoShell] singleton is created synchronously
@@ -47,4 +48,21 @@
}
}
}
+
+ @override
+ void initServiceExtensions() {
+ super.initServiceExtensions();
+ registerStringServiceExtension(
+ // ext.flutter.evict value=foo.png will cause foo.png to be evicted from the rootBundle cache
+ // and cause the entire image cache to be cleared. This is used by hot reload mode to clear
+ // out the cache of resources that have changed.
+ // TODO(ianh): find a way to only evict affected images, not all images
+ name: 'evict',
+ getter: () => '',
+ setter: (String value) {
+ rootBundle.evict(value);
+ imageCache.clear();
+ }
+ );
+ }
}
diff --git a/packages/flutter/lib/src/services/image_cache.dart b/packages/flutter/lib/src/services/image_cache.dart
index ec517ef..c4b5ff6 100644
--- a/packages/flutter/lib/src/services/image_cache.dart
+++ b/packages/flutter/lib/src/services/image_cache.dart
@@ -55,6 +55,16 @@
}
}
+ /// Evicts all entries from the cache.
+ ///
+ /// This is useful if, for instance, the root asset bundle has been updated
+ /// and therefore new images must be obtained.
+ // TODO(ianh): Provide a way to target individual images. This is currently non-trivial
+ // because by the time we get to the imageCache, the keys we're using are opaque.
+ void clear() {
+ _cache.clear();
+ }
+
/// 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.
diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart
index a0cb221..9045fc7 100644
--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -731,6 +731,28 @@
@protected
void didUpdateConfig(T oldConfig) { }
+ /// Called whenever the application is reassembled during debugging.
+ ///
+ /// This method should rerun any initialization logic that depends on global
+ /// state, for example, image loading from asset bundles (since the asset
+ /// bundle may have changed).
+ ///
+ /// In addition to this method being invoked, it is guaranteed that the
+ /// [build] method will be invoked when a reassemble is signalled. Most
+ /// widgets therefore do not need to do anything in the [reassemble] method.
+ ///
+ /// This function will only be called during development. In release builds,
+ /// the `ext.flutter.reassemble` hook is not available, and so this code will
+ /// never execute.
+ ///
+ /// See also:
+ ///
+ /// * [BindingBase.reassembleApplication]
+ /// * [Image], which uses this to reload images
+ @protected
+ @mustCallSuper
+ void reassemble() { }
+
/// Notify the framework that the internal state of this object has changed.
///
/// Whenever you change the internal state of a [State] object, make the
@@ -2061,6 +2083,7 @@
@override
void _reassemble() {
_builder = state.build;
+ state.reassemble();
super._reassemble();
}
diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart
index d83c150..7ee99fb 100644
--- a/packages/flutter/lib/src/widgets/image.dart
+++ b/packages/flutter/lib/src/widgets/image.dart
@@ -206,6 +206,12 @@
}
@override
+ void reassemble() {
+ _resolveImage();
+ super.reassemble();
+ }
+
+ @override
void dispose() {
_imageStream.removeListener(_handleImageChanged);
super.dispose();