@@ -1111,6 +1111,19 @@ class PipelineOwner {
1111
1111
/// The [RenderBox] subclass introduces the opinion that the layout
1112
1112
/// system uses Cartesian coordinates.
1113
1113
///
1114
+ /// ## Lifecycle
1115
+ ///
1116
+ /// A [RenderObject] must [dispose] when it is no longer needed. The creator
1117
+ /// of the object is responsible for disposing of it. Typically, the creator is
1118
+ /// a [RenderObjectElement] , and that element will dispose the object it creates
1119
+ /// when it is unmounted.
1120
+ ///
1121
+ /// [RenderObject] s are responsible for cleaning up any expensive resources
1122
+ /// they hold when [dispose] is called, such as [Picture] or [Image] objects.
1123
+ /// This includes any [Layer] s that the render object has directly created. The
1124
+ /// base implementation of dispose will nullify the [layer] property. Subclasses
1125
+ /// must also nullify any other layer(s) it directly creates.
1126
+ ///
1114
1127
/// ## Writing a RenderObject subclass
1115
1128
///
1116
1129
/// In most cases, subclassing [RenderObject] itself is overkill, and
@@ -1230,6 +1243,50 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
1230
1243
});
1231
1244
}
1232
1245
1246
+ /// Whether this has been disposed.
1247
+ ///
1248
+ /// If asserts are disabled, this property is always null.
1249
+ bool ? get debugDisposed {
1250
+ bool ? disposed;
1251
+ assert (() {
1252
+ disposed = _debugDisposed;
1253
+ return true ;
1254
+ }());
1255
+ return disposed;
1256
+ }
1257
+
1258
+ bool _debugDisposed = false ;
1259
+
1260
+ /// Release any resources held by this render object.
1261
+ ///
1262
+ /// The object that creates a RenderObject is in charge of disposing it.
1263
+ /// If this render object has created any children directly, it must dispose
1264
+ /// of those children in this method as well. It must not dispose of any
1265
+ /// children that were created by some other object, such as
1266
+ /// a [RenderObjectElement] . Those children will be disposed when that
1267
+ /// element unmounts, which may be delayed if the element is moved to another
1268
+ /// part of the tree.
1269
+ ///
1270
+ /// Implementations of this method must end with a call to the inherited
1271
+ /// method, as in `super.dispose()` .
1272
+ ///
1273
+ /// The object is no longer usable after calling dispose.
1274
+ @mustCallSuper
1275
+ void dispose () {
1276
+ assert (! _debugDisposed);
1277
+ _layer = null ;
1278
+ assert (() {
1279
+ visitChildren ((RenderObject child) {
1280
+ assert (
1281
+ child.debugDisposed! ,
1282
+ '${child .runtimeType } (child of $runtimeType ) must be disposed before calling super.dispose().' ,
1283
+ );
1284
+ });
1285
+ _debugDisposed = true ;
1286
+ return true ;
1287
+ }());
1288
+ }
1289
+
1233
1290
// LAYOUT
1234
1291
1235
1292
/// Data for use by the parent render object.
@@ -1367,6 +1424,10 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
1367
1424
bool get _debugCanPerformMutations {
1368
1425
late bool result;
1369
1426
assert (() {
1427
+ if (_debugDisposed) {
1428
+ result = false ;
1429
+ return true ;
1430
+ }
1370
1431
if (owner != null && ! owner! .debugDoingLayout) {
1371
1432
result = true ;
1372
1433
return true ;
@@ -1401,6 +1462,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
1401
1462
1402
1463
@override
1403
1464
void attach (PipelineOwner owner) {
1465
+ assert (! _debugDisposed);
1404
1466
super .attach (owner);
1405
1467
// If the node was dirtied in some way while unattached, make sure to add
1406
1468
// it to the appropriate dirty list now that an owner is available
@@ -1612,6 +1674,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
1612
1674
///
1613
1675
/// See [RenderView] for an example of how this function is used.
1614
1676
void scheduleInitialLayout () {
1677
+ assert (! _debugDisposed);
1615
1678
assert (attached);
1616
1679
assert (parent is ! RenderObject );
1617
1680
assert (! owner! ._debugDoingLayout);
@@ -1681,6 +1744,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
1681
1744
/// work to update its layout information.
1682
1745
@pragma ('vm:notify-debugger-on-exception' )
1683
1746
void layout (Constraints constraints, { bool parentUsesSize = false }) {
1747
+ assert (! _debugDisposed);
1684
1748
if (! kReleaseMode && debugProfileLayoutsEnabled)
1685
1749
Timeline .startSync ('$runtimeType ' , arguments: timelineArgumentsIndicatingLandmarkEvent);
1686
1750
@@ -2040,6 +2104,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
2040
2104
/// it cannot be the case that _only_ the compositing bits changed,
2041
2105
/// something else will have scheduled a frame for us.
2042
2106
void markNeedsCompositingBitsUpdate () {
2107
+ assert (! _debugDisposed);
2043
2108
if (_needsCompositingBitsUpdate)
2044
2109
return ;
2045
2110
_needsCompositingBitsUpdate = true ;
@@ -2138,6 +2203,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
2138
2203
/// layer, thus limiting the number of nodes that [markNeedsPaint] must mark
2139
2204
/// dirty.
2140
2205
void markNeedsPaint () {
2206
+ assert (! _debugDisposed);
2141
2207
assert (owner == null || ! owner! .debugDoingPaint);
2142
2208
if (_needsPaint)
2143
2209
return ;
@@ -2222,6 +2288,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
2222
2288
///
2223
2289
/// This might be called if, e.g., the device pixel ratio changed.
2224
2290
void replaceRootLayer (OffsetLayer rootLayer) {
2291
+ assert (! _debugDisposed);
2225
2292
assert (rootLayer.attached);
2226
2293
assert (attached);
2227
2294
assert (parent is ! RenderObject );
@@ -2234,6 +2301,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
2234
2301
}
2235
2302
2236
2303
void _paintWithContext (PaintingContext context, Offset offset) {
2304
+ assert (! _debugDisposed);
2237
2305
assert (() {
2238
2306
if (_debugDoingThisPaint) {
2239
2307
throw FlutterError .fromParts (< DiagnosticsNode > [
@@ -2457,6 +2525,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
2457
2525
///
2458
2526
/// See [RendererBinding] for an example of how this function is used.
2459
2527
void scheduleInitialSemantics () {
2528
+ assert (! _debugDisposed);
2460
2529
assert (attached);
2461
2530
assert (parent is ! RenderObject );
2462
2531
assert (! owner! ._debugDoingSemantics);
@@ -2579,6 +2648,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
2579
2648
/// [RenderObject] as annotated by [describeSemanticsConfiguration] changes in
2580
2649
/// any way to update the semantics tree.
2581
2650
void markNeedsSemanticsUpdate () {
2651
+ assert (! _debugDisposed);
2582
2652
assert (! attached || ! owner! ._debugDoingSemantics);
2583
2653
if (! attached || owner! ._semanticsOwner == null ) {
2584
2654
_cachedSemanticsConfiguration = null ;
@@ -2824,6 +2894,10 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
2824
2894
@override
2825
2895
String toStringShort () {
2826
2896
String header = describeIdentity (this );
2897
+ if (_debugDisposed) {
2898
+ header += ' DISPOSED' ;
2899
+ return header;
2900
+ }
2827
2901
if (_relayoutBoundary != null && _relayoutBoundary != this ) {
2828
2902
int count = 1 ;
2829
2903
RenderObject ? target = parent as RenderObject ? ;
@@ -3209,6 +3283,7 @@ mixin ContainerRenderObjectMixin<ChildType extends RenderObject, ParentDataType
3209
3283
}
3210
3284
}
3211
3285
}
3286
+
3212
3287
/// Insert child into this render object's child list after the given child.
3213
3288
///
3214
3289
/// If `after` is null, then this inserts the child at the start of the list,
0 commit comments