Commit 1ff7109b authored by Adam Barth's avatar Adam Barth

Mark State.setState as protected (#4295)

This required refactoring some cases where we weren't following the rules for
the protected annotation.
parent 88d47d57
...@@ -35,6 +35,12 @@ class ComplexLayoutAppState extends State<ComplexLayoutApp> { ...@@ -35,6 +35,12 @@ class ComplexLayoutAppState extends State<ComplexLayoutApp> {
_lightTheme = value; _lightTheme = value;
}); });
} }
void toggleAnimationSpeed() {
setState(() {
timeDilation = (timeDilation != 1.0) ? 1.0 : 5.0;
});
}
} }
class ComplexLayout extends StatefulWidget { class ComplexLayout extends StatefulWidget {
...@@ -566,12 +572,6 @@ class GalleryDrawer extends StatelessWidget { ...@@ -566,12 +572,6 @@ class GalleryDrawer extends StatelessWidget {
ComplexLayoutApp.of(context).lightTheme = value; ComplexLayoutApp.of(context).lightTheme = value;
} }
void _toggleAnimationSpeed(BuildContext context) {
ComplexLayoutApp.of(context).setState(() {
timeDilation = (timeDilation != 1.0) ? 1.0 : 5.0;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Drawer( return new Drawer(
...@@ -612,13 +612,13 @@ class GalleryDrawer extends StatelessWidget { ...@@ -612,13 +612,13 @@ class GalleryDrawer extends StatelessWidget {
new DrawerItem( new DrawerItem(
icon: Icons.hourglass_empty, icon: Icons.hourglass_empty,
selected: timeDilation != 1.0, selected: timeDilation != 1.0,
onPressed: () { _toggleAnimationSpeed(context); }, onPressed: () { ComplexLayoutApp.of(context).toggleAnimationSpeed(); },
child: new Row( child: new Row(
children: <Widget>[ children: <Widget>[
new Flexible(child: new Text('Animate Slowly')), new Flexible(child: new Text('Animate Slowly')),
new Checkbox( new Checkbox(
value: timeDilation != 1.0, value: timeDilation != 1.0,
onChanged: (bool value) { _toggleAnimationSpeed(context); } onChanged: (bool value) { ComplexLayoutApp.of(context).toggleAnimationSpeed(); }
) )
] ]
) )
......
...@@ -8,8 +8,6 @@ import 'package:stocks/stock_data.dart' as stock_data; ...@@ -8,8 +8,6 @@ import 'package:stocks/stock_data.dart' as stock_data;
const Duration kBenchmarkTime = const Duration(seconds: 15); const Duration kBenchmarkTime = const Duration(seconds: 15);
void _doNothing() { }
Future<Null> main() async { Future<Null> main() async {
assert(false); // don't run this in checked mode! Use --release. assert(false); // don't run this in checked mode! Use --release.
stock_data.StockDataFetcher.actuallyFetchData = false; stock_data.StockDataFetcher.actuallyFetchData = false;
...@@ -26,12 +24,12 @@ Future<Null> main() async { ...@@ -26,12 +24,12 @@ Future<Null> main() async {
await tester.pump(const Duration(seconds: 1)); // Complete drawer animation await tester.pump(const Duration(seconds: 1)); // Complete drawer animation
final stocks.StocksAppState appState = tester.state(find.byType(stocks.StocksApp)); final BuildableElement appState = tester.element(find.byType(stocks.StocksApp));
final BuildOwner buildOwner = WidgetsBinding.instance.buildOwner; final BuildOwner buildOwner = WidgetsBinding.instance.buildOwner;
watch.start(); watch.start();
while (watch.elapsed < kBenchmarkTime) { while (watch.elapsed < kBenchmarkTime) {
appState.setState(_doNothing); appState.markNeedsBuild();
buildOwner.buildDirtyElements(); buildOwner.buildDirtyElements();
iterations += 1; iterations += 1;
} }
......
...@@ -405,6 +405,7 @@ abstract class State<T extends StatefulWidget> { ...@@ -405,6 +405,7 @@ abstract class State<T extends StatefulWidget> {
/// If you just change the state directly without calling setState(), then the /// If you just change the state directly without calling setState(), then the
/// widget will not be scheduled for rebuilding, meaning that its rendering /// widget will not be scheduled for rebuilding, meaning that its rendering
/// will not be updated. /// will not be updated.
@protected
void setState(VoidCallback fn) { void setState(VoidCallback fn) {
assert(() { assert(() {
if (_debugLifecycleState == _StateLifecycle.defunct) { if (_debugLifecycleState == _StateLifecycle.defunct) {
......
...@@ -196,15 +196,13 @@ class LazyBlock extends StatelessWidget { ...@@ -196,15 +196,13 @@ class LazyBlock extends StatelessWidget {
double contentExtent, double contentExtent,
double containerExtent, double containerExtent,
double minScrollOffset) { double minScrollOffset) {
state.setState(() { final BoundedBehavior scrollBehavior = state.scrollBehavior;
final BoundedBehavior scrollBehavior = state.scrollBehavior; state.didUpdateScrollBehavior(scrollBehavior.updateExtents(
state.didUpdateScrollBehavior(scrollBehavior.updateExtents( contentExtent: contentExtent,
contentExtent: contentExtent, containerExtent: containerExtent,
containerExtent: containerExtent, minScrollOffset: minScrollOffset,
minScrollOffset: minScrollOffset, scrollOffset: state.scrollOffset
scrollOffset: state.scrollOffset ));
));
});
} }
Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) { Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) {
......
...@@ -63,14 +63,13 @@ class OverlayEntry { ...@@ -63,14 +63,13 @@ class OverlayEntry {
set opaque (bool value) { set opaque (bool value) {
if (_opaque == value) if (_opaque == value)
return; return;
_opaque = value;
assert(_overlay != null); assert(_overlay != null);
_overlay.setState(() { _overlay._didChangeEntryOpacity();
_opaque = value;
});
} }
OverlayState _overlay; OverlayState _overlay;
final GlobalKey _key = new GlobalKey(); final GlobalKey<_OverlayEntryState> _key = new GlobalKey<_OverlayEntryState>();
/// Remove this entry from the overlay. /// Remove this entry from the overlay.
void remove() { void remove() {
...@@ -82,7 +81,7 @@ class OverlayEntry { ...@@ -82,7 +81,7 @@ class OverlayEntry {
/// ///
/// You need to call this function if the output of [builder] has changed. /// You need to call this function if the output of [builder] has changed.
void markNeedsBuild() { void markNeedsBuild() {
_key.currentState?.setState(() { /* the state that changed is in the builder */ }); _key.currentState?._markNeedsBuild();
} }
@override @override
...@@ -101,6 +100,10 @@ class _OverlayEntry extends StatefulWidget { ...@@ -101,6 +100,10 @@ class _OverlayEntry extends StatefulWidget {
class _OverlayEntryState extends State<_OverlayEntry> { class _OverlayEntryState extends State<_OverlayEntry> {
@override @override
Widget build(BuildContext context) => config.entry.builder(context); Widget build(BuildContext context) => config.entry.builder(context);
void _markNeedsBuild() {
setState(() { /* the state that changed is in the builder */ });
}
} }
/// A [Stack] of entries that can be managed independently. /// A [Stack] of entries that can be managed independently.
...@@ -245,6 +248,13 @@ class OverlayState extends State<Overlay> { ...@@ -245,6 +248,13 @@ class OverlayState extends State<Overlay> {
return result; return result;
} }
void _didChangeEntryOpacity() {
setState(() {
// We use the opacity of the entry in our build function, which means we
// our state has changed.
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> backwardsChildren = <Widget>[]; List<Widget> backwardsChildren = <Widget>[];
......
...@@ -394,6 +394,13 @@ class _ModalScopeState extends State<_ModalScope> { ...@@ -394,6 +394,13 @@ class _ModalScopeState extends State<_ModalScope> {
}); });
} }
void _didChangeRouteOffStage() {
setState(() {
// We use the route's offstage bool in our build function, which means our
// state has changed.
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget contents = new PageStorage( Widget contents = new PageStorage(
...@@ -515,14 +522,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -515,14 +522,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
if (_offstage == value) if (_offstage == value)
return; return;
_offstage = value; _offstage = value;
_scopeKey.currentState?.setState(() { _scopeKey.currentState?._didChangeRouteOffStage();
// _offstage is the value we're setting, but since there might not be a
// state, we set it outside of this callback (which will only be called if
// there's a state currently built).
// _scopeKey is the key for the _ModalScope built in _buildModalScope().
// When we mark that state dirty, it'll rebuild itself, and use our
// offstage (via their config.route.offstage) when building.
});
} }
/// The build context for the subtree containing the primary content of this route. /// The build context for the subtree containing the primary content of this route.
......
...@@ -402,6 +402,7 @@ class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -402,6 +402,7 @@ class ScrollableState<T extends Scrollable> extends State<T> {
/// If there are no in-progress scrolling physics, this function scrolls to /// If there are no in-progress scrolling physics, this function scrolls to
/// the given offset instead. /// the given offset instead.
void didUpdateScrollBehavior(double newScrollOffset) { void didUpdateScrollBehavior(double newScrollOffset) {
setState(() { /* The scroll behavior is part of our build state. */ });
assert(_controller.isAnimating || _simulation == null); assert(_controller.isAnimating || _simulation == null);
if (_numberOfInProgressScrolls > 0) { if (_numberOfInProgressScrolls > 0) {
if (_simulation != null) { if (_simulation != null) {
......
...@@ -67,13 +67,11 @@ class ScrollableGrid extends StatelessWidget { ...@@ -67,13 +67,11 @@ class ScrollableGrid extends StatelessWidget {
final Iterable<Widget> children; final Iterable<Widget> children;
void _handleExtentsChanged(ScrollableState state, double contentExtent, double containerExtent) { void _handleExtentsChanged(ScrollableState state, double contentExtent, double containerExtent) {
state.setState(() { state.didUpdateScrollBehavior(state.scrollBehavior.updateExtents(
state.didUpdateScrollBehavior(state.scrollBehavior.updateExtents( contentExtent: contentExtent,
contentExtent: contentExtent, containerExtent: containerExtent,
containerExtent: containerExtent, scrollOffset: state.scrollOffset
scrollOffset: state.scrollOffset ));
));
});
} }
Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) { Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) {
......
...@@ -102,13 +102,11 @@ class ScrollableList extends StatelessWidget { ...@@ -102,13 +102,11 @@ class ScrollableList extends StatelessWidget {
final Iterable<Widget> children; final Iterable<Widget> children;
void _handleExtentsChanged(ScrollableState state, double contentExtent, double containerExtent) { void _handleExtentsChanged(ScrollableState state, double contentExtent, double containerExtent) {
state.setState(() { state.didUpdateScrollBehavior(state.scrollBehavior.updateExtents(
state.didUpdateScrollBehavior(state.scrollBehavior.updateExtents( contentExtent: itemsWrap ? double.INFINITY : contentExtent,
contentExtent: itemsWrap ? double.INFINITY : contentExtent, containerExtent: containerExtent,
containerExtent: containerExtent, scrollOffset: state.scrollOffset
scrollOffset: state.scrollOffset ));
));
});
} }
Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) { Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) {
...@@ -428,13 +426,11 @@ class ScrollableLazyList extends StatelessWidget { ...@@ -428,13 +426,11 @@ class ScrollableLazyList extends StatelessWidget {
final EdgeInsets padding; final EdgeInsets padding;
void _handleExtentsChanged(ScrollableState state, double contentExtent, double containerExtent) { void _handleExtentsChanged(ScrollableState state, double contentExtent, double containerExtent) {
state.setState(() { state.didUpdateScrollBehavior(state.scrollBehavior.updateExtents(
state.didUpdateScrollBehavior(state.scrollBehavior.updateExtents( contentExtent: contentExtent,
contentExtent: contentExtent, containerExtent: containerExtent,
containerExtent: containerExtent, scrollOffset: state.scrollOffset
scrollOffset: state.scrollOffset ));
));
});
} }
Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) { Widget _buildViewport(BuildContext context, ScrollableState state, double scrollOffset) {
......
...@@ -37,11 +37,11 @@ class ProbeWidgetState extends State<ProbeWidget> { ...@@ -37,11 +37,11 @@ class ProbeWidgetState extends State<ProbeWidget> {
class BadWidget extends StatelessWidget { class BadWidget extends StatelessWidget {
BadWidget(this.parentState); BadWidget(this.parentState);
final State parentState; final BadWidgetParentState parentState;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
parentState.setState(() {}); parentState._markNeedsBuild();
return new Container(); return new Container();
} }
} }
...@@ -52,6 +52,13 @@ class BadWidgetParent extends StatefulWidget { ...@@ -52,6 +52,13 @@ class BadWidgetParent extends StatefulWidget {
} }
class BadWidgetParentState extends State<BadWidgetParent> { class BadWidgetParentState extends State<BadWidgetParent> {
void _markNeedsBuild() {
setState(() {
// Our state didn't really change, but we're doing something pathological
// here to trigger an interesting scenario to test.
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new BadWidget(this); return new BadWidget(this);
......
...@@ -75,7 +75,7 @@ void main() { ...@@ -75,7 +75,7 @@ void main() {
StatefulElement outerElement = tester.element(find.byKey(outerKey)); StatefulElement outerElement = tester.element(find.byKey(outerKey));
expect(outerElement.state.config, equals(outer2)); expect(outerElement.state.config, equals(outer2));
outerElement.state.setState(() {}); outerElement.markNeedsBuild();
await tester.pump(); await tester.pump();
expect(tester.element(find.byKey(innerKey)), equals(innerElement)); expect(tester.element(find.byKey(innerKey)), equals(innerElement));
......
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