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
934189d0
Commit
934189d0
authored
Aug 26, 2016
by
Ian Hickson
Committed by
GitHub
Aug 26, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
don't clear the dirty bit of an inactive node (#5614)
Fixes
https://github.com/flutter/flutter/issues/5588
parent
886f588d
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
178 additions
and
10 deletions
+178
-10
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+7
-10
reparent_state_harder_test.dart
packages/flutter/test/widget/reparent_state_harder_test.dart
+171
-0
No files found.
packages/flutter/lib/src/widgets/framework.dart
View file @
934189d0
...
...
@@ -1283,11 +1283,6 @@ class BuildOwner {
int
dirtyCount
=
_dirtyElements
.
length
;
int
index
=
0
;
while
(
index
<
dirtyCount
)
{
assert
(()
{
if
(
debugPrintRebuildDirtyWidgets
)
debugPrint
(
'Rebuilding
${_dirtyElements[index].widget}
'
);
return
true
;
});
_dirtyElements
[
index
].
rebuild
();
index
+=
1
;
if
(
dirtyCount
<
_dirtyElements
.
length
)
{
...
...
@@ -1295,7 +1290,7 @@ class BuildOwner {
dirtyCount
=
_dirtyElements
.
length
;
}
}
assert
(!
_dirtyElements
.
any
((
BuildableElement
element
)
=>
element
.
dirty
));
assert
(!
_dirtyElements
.
any
((
BuildableElement
element
)
=>
element
.
_active
&&
element
.
dirty
));
},
building:
true
);
}
finally
{
_dirtyElements
.
clear
();
...
...
@@ -1913,10 +1908,13 @@ abstract class BuildableElement extends Element {
/// changed.
void
rebuild
()
{
assert
(
_debugLifecycleState
!=
_ElementLifecycle
.
initial
);
if
(!
_active
||
!
_dirty
)
{
_dirty
=
false
;
if
(!
_active
||
!
_dirty
)
return
;
}
assert
(()
{
if
(
debugPrintRebuildDirtyWidgets
)
debugPrint
(
'Rebuilding
$this
'
);
return
true
;
});
assert
(
_debugLifecycleState
==
_ElementLifecycle
.
active
);
assert
(
owner
.
_debugStateLocked
);
BuildableElement
debugPreviousBuildTarget
;
...
...
@@ -2179,7 +2177,6 @@ class StatefulElement extends ComponentElement {
'that all the resources used by the widget are fully released.'
);
});
assert
(!
dirty
);
// See BuildableElement.unmount for why this is important.
_state
.
_element
=
null
;
_state
=
null
;
}
...
...
packages/flutter/test/widget/reparent_state_harder_test.dart
0 → 100644
View file @
934189d0
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/src/widgets/basic.dart'
;
import
'package:flutter/src/widgets/framework.dart'
;
import
'package:flutter/src/widgets/layout_builder.dart'
;
import
'package:flutter_test/flutter_test.dart'
hide
TypeMatcher
;
// This is a regression test for https://github.com/flutter/flutter/issues/5588.
class
OrderSwitcher
extends
StatefulWidget
{
OrderSwitcher
({
Key
key
,
this
.
a
,
this
.
b
})
:
super
(
key:
key
);
final
Widget
a
;
final
Widget
b
;
@override
OrderSwitcherState
createState
()
=>
new
OrderSwitcherState
();
}
class
OrderSwitcherState
extends
State
<
OrderSwitcher
>
{
bool
_aFirst
=
true
;
void
switchChildren
()
{
setState
(()
{
_aFirst
=
false
;
});
}
@override
Widget
build
(
BuildContext
context
)
{
List
<
Widget
>
children
=
<
Widget
>[];
if
(
_aFirst
)
{
children
.
add
(
new
KeyedSubtree
(
child:
config
.
a
));
children
.
add
(
config
.
b
);
}
else
{
children
.
add
(
new
KeyedSubtree
(
child:
config
.
b
));
children
.
add
(
config
.
a
);
}
return
new
Stack
(
children:
children
);
}
}
class
DummyStatefulWidget
extends
StatefulWidget
{
DummyStatefulWidget
(
Key
key
)
:
super
(
key:
key
);
@override
DummyStatefulWidgetState
createState
()
=>
new
DummyStatefulWidgetState
();
}
class
DummyStatefulWidgetState
extends
State
<
DummyStatefulWidget
>
{
@override
Widget
build
(
BuildContext
context
)
=>
new
Text
(
'LEAF'
);
}
class
RekeyableDummyStatefulWidgetWrapper
extends
StatefulWidget
{
RekeyableDummyStatefulWidgetWrapper
({
this
.
child
,
this
.
initialKey
});
final
Widget
child
;
final
GlobalKey
initialKey
;
@override
RekeyableDummyStatefulWidgetWrapperState
createState
()
=>
new
RekeyableDummyStatefulWidgetWrapperState
();
}
class
RekeyableDummyStatefulWidgetWrapperState
extends
State
<
RekeyableDummyStatefulWidgetWrapper
>
{
GlobalKey
_key
;
@override
void
initState
()
{
super
.
initState
();
_key
=
config
.
initialKey
;
}
void
_setChild
(
GlobalKey
value
)
{
setState
(()
{
_key
=
value
;
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
new
DummyStatefulWidget
(
_key
);
}
}
void
main
(
)
{
testWidgets
(
'Handle GlobalKey reparenting in weird orders'
,
(
WidgetTester
tester
)
async
{
// This is a bit of a weird test so let's try to explain it a bit.
//
// Basically what's happening here is that we have a complicated tree, and
// in one frame, we change it to a slightly different tree with a specific
// set of mutations:
//
// * The keyA subtree is regrafted to be one level higher, but later than
// the keyB subtree.
// * The keyB subtree is, similarly, moved one level deeper, but earlier, than
// the keyA subtree.
// * The keyD subtree is replaced by the previously earlier and shallower
// keyC subtree. This happens during a LayoutBuilder layout callback, so it
// happens long after A and B have finished their dance.
//
// The net result is that when keyC is moved, it has already been marked
// dirty from being removed then reinserted into the tree (redundantly, as
// it turns out, though this isn't known at the time), and has already been
// visited once by the code that tries to clean nodes (though at that point
// nothing happens since it isn't in the tree).
//
// This test verifies that none of the asserts go off during this dance.
final
GlobalKey
<
OrderSwitcherState
>
keyRoot
=
new
GlobalKey
(
debugLabel:
'Root'
);
final
GlobalKey
keyA
=
new
GlobalKey
(
debugLabel:
'A'
);
final
GlobalKey
keyB
=
new
GlobalKey
(
debugLabel:
'B'
);
final
GlobalKey
keyC
=
new
GlobalKey
(
debugLabel:
'C'
);
final
GlobalKey
keyD
=
new
GlobalKey
(
debugLabel:
'D'
);
await
tester
.
pumpWidget
(
new
OrderSwitcher
(
key:
keyRoot
,
a:
new
KeyedSubtree
(
key:
keyA
,
child:
new
RekeyableDummyStatefulWidgetWrapper
(
initialKey:
keyC
),
),
b:
new
KeyedSubtree
(
key:
keyB
,
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
new
RekeyableDummyStatefulWidgetWrapper
(
initialKey:
keyD
);
}
);
}
);
}
);
}
)
),
));
expect
(
find
.
byKey
(
keyA
),
findsOneWidget
);
expect
(
find
.
byKey
(
keyB
),
findsOneWidget
);
expect
(
find
.
byKey
(
keyC
),
findsOneWidget
);
expect
(
find
.
byKey
(
keyD
),
findsOneWidget
);
expect
(
find
.
byType
(
RekeyableDummyStatefulWidgetWrapper
),
findsNWidgets
(
2
));
expect
(
find
.
byType
(
DummyStatefulWidget
),
findsNWidgets
(
2
));
keyRoot
.
currentState
.
switchChildren
();
List
<
State
>
states
=
tester
.
stateList
(
find
.
byType
(
RekeyableDummyStatefulWidgetWrapper
)).
toList
();
RekeyableDummyStatefulWidgetWrapperState
a
=
states
[
0
];
a
.
_setChild
(
null
);
RekeyableDummyStatefulWidgetWrapperState
b
=
states
[
1
];
b
.
_setChild
(
keyC
);
await
tester
.
pump
();
expect
(
find
.
byKey
(
keyA
),
findsOneWidget
);
expect
(
find
.
byKey
(
keyB
),
findsOneWidget
);
expect
(
find
.
byKey
(
keyC
),
findsOneWidget
);
expect
(
find
.
byKey
(
keyD
),
findsNothing
);
expect
(
find
.
byType
(
RekeyableDummyStatefulWidgetWrapper
),
findsNWidgets
(
2
));
expect
(
find
.
byType
(
DummyStatefulWidget
),
findsNWidgets
(
2
));
});
}
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