Skip to content

Commit 0cc7db5

Browse files
authored
Guard against usage after async callbacks in RenderAndroidView, unregister listener (#108496)
1 parent b188148 commit 0cc7db5

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

packages/flutter/lib/src/rendering/platform_view.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
109109
/// Sets a new Android view controller.
110110
@override
111111
set controller(AndroidViewController controller) {
112+
assert(!_isDisposed);
112113
assert(_viewController != null);
113114
assert(controller != null);
114115
if (_viewController == controller) {
@@ -140,6 +141,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
140141
}
141142

142143
void _onPlatformViewCreated(int id) {
144+
assert(!_isDisposed);
143145
markNeedsSemanticsUpdate();
144146
}
145147

@@ -179,8 +181,14 @@ class RenderAndroidView extends PlatformViewRenderBox {
179181
targetSize = size;
180182
if (_viewController.isCreated) {
181183
_currentTextureSize = await _viewController.setSize(targetSize);
184+
if (_isDisposed) {
185+
return;
186+
}
182187
} else {
183188
await _viewController.create(size: targetSize);
189+
if (_isDisposed) {
190+
return;
191+
}
184192
_currentTextureSize = targetSize;
185193
}
186194
// We've resized the platform view to targetSize, but it is possible that
@@ -248,6 +256,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
248256
void dispose() {
249257
_isDisposed = true;
250258
_clipRectLayer.layer = null;
259+
_viewController.removeOnPlatformViewCreatedListener(_onPlatformViewCreated);
251260
super.dispose();
252261
}
253262

packages/flutter/test/rendering/platform_view_test.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,45 @@ void main() {
221221
expect(renderBox.debugLayer!.firstChild, isA<TextureLayer>());
222222
});
223223
});
224+
225+
test('markNeedsPaint does not get called on a disposed RO', () async {
226+
FakeAsync().run((FakeAsync async) {
227+
final AndroidViewController viewController =
228+
PlatformViewsService.initAndroidView(id: 0, viewType: 'webview', layoutDirection: TextDirection.rtl);
229+
final RenderAndroidView renderBox = RenderAndroidView(
230+
viewController: viewController,
231+
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
232+
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
233+
);
234+
235+
final Completer<void> viewCreation = Completer<void>();
236+
const MethodChannel channel = MethodChannel('flutter/platform_views');
237+
binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
238+
assert(methodCall.method == 'create', 'Unexpected method call');
239+
await viewCreation.future;
240+
return /*textureId=*/ 0;
241+
});
242+
243+
layout(renderBox);
244+
pumpFrame(phase: EnginePhase.paint);
245+
246+
expect(renderBox.debugLayer, isNotNull);
247+
expect(renderBox.debugLayer!.hasChildren, isFalse);
248+
expect(viewController.isCreated, isFalse);
249+
expect(renderBox.debugNeedsPaint, isFalse);
250+
251+
renderBox.dispose();
252+
viewCreation.complete();
253+
async.flushMicrotasks();
254+
255+
expect(viewController.isCreated, isTrue);
256+
expect(renderBox.debugNeedsPaint, isFalse);
257+
expect(renderBox.debugLayer, isNull);
258+
259+
pumpFrame(phase: EnginePhase.paint);
260+
expect(renderBox.debugLayer, isNull);
261+
});
262+
});
224263
}
225264

226265
ui.PointerData _pointerData(

packages/flutter/test/services/fake_platform_views.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,7 @@ class FakeAndroidViewController implements AndroidViewController {
101101
}
102102

103103
@override
104-
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {
105-
throw UnimplementedError();
106-
}
104+
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {}
107105

108106
@override
109107
Future<void> sendMotionEvent(AndroidMotionEvent event) {

0 commit comments

Comments
 (0)