Unverified Commit 0cc7db54 authored by Dan Field's avatar Dan Field Committed by GitHub

Guard against usage after async callbacks in RenderAndroidView, unregister listener (#108496)

parent b1881487
...@@ -109,6 +109,7 @@ class RenderAndroidView extends PlatformViewRenderBox { ...@@ -109,6 +109,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
/// Sets a new Android view controller. /// Sets a new Android view controller.
@override @override
set controller(AndroidViewController controller) { set controller(AndroidViewController controller) {
assert(!_isDisposed);
assert(_viewController != null); assert(_viewController != null);
assert(controller != null); assert(controller != null);
if (_viewController == controller) { if (_viewController == controller) {
...@@ -140,6 +141,7 @@ class RenderAndroidView extends PlatformViewRenderBox { ...@@ -140,6 +141,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
} }
void _onPlatformViewCreated(int id) { void _onPlatformViewCreated(int id) {
assert(!_isDisposed);
markNeedsSemanticsUpdate(); markNeedsSemanticsUpdate();
} }
...@@ -179,8 +181,14 @@ class RenderAndroidView extends PlatformViewRenderBox { ...@@ -179,8 +181,14 @@ class RenderAndroidView extends PlatformViewRenderBox {
targetSize = size; targetSize = size;
if (_viewController.isCreated) { if (_viewController.isCreated) {
_currentTextureSize = await _viewController.setSize(targetSize); _currentTextureSize = await _viewController.setSize(targetSize);
if (_isDisposed) {
return;
}
} else { } else {
await _viewController.create(size: targetSize); await _viewController.create(size: targetSize);
if (_isDisposed) {
return;
}
_currentTextureSize = targetSize; _currentTextureSize = targetSize;
} }
// We've resized the platform view to targetSize, but it is possible that // We've resized the platform view to targetSize, but it is possible that
...@@ -248,6 +256,7 @@ class RenderAndroidView extends PlatformViewRenderBox { ...@@ -248,6 +256,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
void dispose() { void dispose() {
_isDisposed = true; _isDisposed = true;
_clipRectLayer.layer = null; _clipRectLayer.layer = null;
_viewController.removeOnPlatformViewCreatedListener(_onPlatformViewCreated);
super.dispose(); super.dispose();
} }
......
...@@ -221,6 +221,45 @@ void main() { ...@@ -221,6 +221,45 @@ void main() {
expect(renderBox.debugLayer!.firstChild, isA<TextureLayer>()); expect(renderBox.debugLayer!.firstChild, isA<TextureLayer>());
}); });
}); });
test('markNeedsPaint does not get called on a disposed RO', () async {
FakeAsync().run((FakeAsync async) {
final AndroidViewController viewController =
PlatformViewsService.initAndroidView(id: 0, viewType: 'webview', layoutDirection: TextDirection.rtl);
final RenderAndroidView renderBox = RenderAndroidView(
viewController: viewController,
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
);
final Completer<void> viewCreation = Completer<void>();
const MethodChannel channel = MethodChannel('flutter/platform_views');
binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
assert(methodCall.method == 'create', 'Unexpected method call');
await viewCreation.future;
return /*textureId=*/ 0;
});
layout(renderBox);
pumpFrame(phase: EnginePhase.paint);
expect(renderBox.debugLayer, isNotNull);
expect(renderBox.debugLayer!.hasChildren, isFalse);
expect(viewController.isCreated, isFalse);
expect(renderBox.debugNeedsPaint, isFalse);
renderBox.dispose();
viewCreation.complete();
async.flushMicrotasks();
expect(viewController.isCreated, isTrue);
expect(renderBox.debugNeedsPaint, isFalse);
expect(renderBox.debugLayer, isNull);
pumpFrame(phase: EnginePhase.paint);
expect(renderBox.debugLayer, isNull);
});
});
} }
ui.PointerData _pointerData( ui.PointerData _pointerData(
......
...@@ -101,9 +101,7 @@ class FakeAndroidViewController implements AndroidViewController { ...@@ -101,9 +101,7 @@ class FakeAndroidViewController implements AndroidViewController {
} }
@override @override
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) { void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {}
throw UnimplementedError();
}
@override @override
Future<void> sendMotionEvent(AndroidMotionEvent event) { Future<void> sendMotionEvent(AndroidMotionEvent event) {
......
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