Unverified Commit a9ea825a authored by Dan Field's avatar Dan Field Committed by GitHub

Do not cache itemBuilder calls in a GridView (#61033)

parent a6ce2d4b
......@@ -1052,20 +1052,11 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
performRebuild();
}
// We inflate widgets at two different times:
// 1. When we ourselves are told to rebuild (see performRebuild).
// 2. When our render object needs a new child (see createChild).
// In both cases, we cache the results of calling into our delegate to get the widget,
// so that if we do case 2 later, we don't call the builder again.
// Any time we do case 1, though, we reset the cache.
final Map<int, Widget> _childWidgets = HashMap<int, Widget>();
final SplayTreeMap<int, Element> _childElements = SplayTreeMap<int, Element>();
RenderBox _currentBeforeChild;
@override
void performRebuild() {
_childWidgets.clear(); // Reset the cache, as described above.
super.performRebuild();
_currentBeforeChild = null;
assert(_currentlyUpdatingChildIndex == null);
......@@ -1133,7 +1124,7 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render
}
Widget _build(int index) {
return _childWidgets.putIfAbsent(index, () => widget.delegate.build(this, index));
return widget.delegate.build(this, index);
}
@override
......
......@@ -566,4 +566,40 @@ void main() {
expect(tester.getTopLeft(find.byKey(target)), const Offset(606.0, 0.0));
expect(tester.getBottomRight(find.byKey(target)), const Offset(800.0, 194.0));
});
testWidgets('GridView does not cache itemBuilder calls', (WidgetTester tester) async {
final Map<int, int> counters = <int, int>{};
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: GridView.builder(
itemCount: 1000,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
counters[index] ??= 0;
counters[index] += 1;
return SizedBox(
key: ValueKey<int>(index),
width: 200,
height: 200,
);
},
),
));
expect(find.byKey(const ValueKey<int>(4)), findsOneWidget);
expect(counters[4], 1);
await tester.fling(find.byType(GridView), const Offset(0, -300), 5000);
await tester.pumpAndSettle();
expect(find.byKey(const ValueKey<int>(4)), findsNothing);
expect(counters[4], 1);
await tester.fling(find.byType(GridView), const Offset(0, 300), 5000);
await tester.pumpAndSettle();
expect(find.byKey(const ValueKey<int>(4)), findsOneWidget);
expect(counters[4], 2);
});
}
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