mirror of
https://github.com/flutter/flutter
synced 2024-09-20 00:32:02 +00:00
Guard against usage after async callbacks in RenderAndroidView, unregister listener (#108496)
This commit is contained in:
parent
b1881487be
commit
0cc7db54ce
|
@ -109,6 +109,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
|
|||
/// Sets a new Android view controller.
|
||||
@override
|
||||
set controller(AndroidViewController controller) {
|
||||
assert(!_isDisposed);
|
||||
assert(_viewController != null);
|
||||
assert(controller != null);
|
||||
if (_viewController == controller) {
|
||||
|
@ -140,6 +141,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
|
|||
}
|
||||
|
||||
void _onPlatformViewCreated(int id) {
|
||||
assert(!_isDisposed);
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
|
@ -179,8 +181,14 @@ class RenderAndroidView extends PlatformViewRenderBox {
|
|||
targetSize = size;
|
||||
if (_viewController.isCreated) {
|
||||
_currentTextureSize = await _viewController.setSize(targetSize);
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
await _viewController.create(size: targetSize);
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
_currentTextureSize = targetSize;
|
||||
}
|
||||
// We've resized the platform view to targetSize, but it is possible that
|
||||
|
@ -248,6 +256,7 @@ class RenderAndroidView extends PlatformViewRenderBox {
|
|||
void dispose() {
|
||||
_isDisposed = true;
|
||||
_clipRectLayer.layer = null;
|
||||
_viewController.removeOnPlatformViewCreatedListener(_onPlatformViewCreated);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
|
@ -221,6 +221,45 @@ void main() {
|
|||
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(
|
||||
|
|
|
@ -101,9 +101,7 @@ class FakeAndroidViewController implements AndroidViewController {
|
|||
}
|
||||
|
||||
@override
|
||||
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
void removeOnPlatformViewCreatedListener(PlatformViewCreatedCallback listener) {}
|
||||
|
||||
@override
|
||||
Future<void> sendMotionEvent(AndroidMotionEvent event) {
|
||||
|
|
Loading…
Reference in a new issue