-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[url_launcher] Fixed call to onPlatformViewCreated after dispose #5431
Changes from 1 commit
8fb082e
a640546
3b09ff5
0354b1d
c49ce9b
00f0f2a
7b5e35a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -114,13 +114,24 @@ class LinkViewController extends PlatformViewController { | |||||
factory LinkViewController.fromParams( | ||||||
PlatformViewCreationParams params, | ||||||
BuildContext context, | ||||||
) { | ||||||
final int viewId = params.id; | ||||||
final LinkViewController controller = LinkViewController(viewId, context); | ||||||
controller._initialize().then((_) { | ||||||
) => | ||||||
LinkViewController(params.id, context).._asyncInit(params); | ||||||
|
||||||
Future<void> _asyncInit(PlatformViewCreationParams params) async { | ||||||
try { | ||||||
await _initialize(); | ||||||
if (context == null) { | ||||||
return; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this disposed check be performed before actually asking the framework to create a platform_view? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the whole point of this fix is to check after the await, sort of like you do when do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@kristoffer-zliide the lifecycle of Flutter Widgets and platform views is somewhat separate. In this code, you're adding elements to the DOM (code) and then checking if the Widget has been disposed to then not call onPlatformViewCreated. I don't think you need to modify the DOM at all, or call "create" on a "platform_view" if the Widget that is being initialized has been previously marked as disposed. That's why I asked you to move the In fact, if (Note: this LinkViewController was originally modeled to look like the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I appreciate the desire to skip anything that would need to be awaited, but I don't quite follow anything else you're writing. With the refactoring done in this PR, I don't think I need to read more than 15 lines of code in the Link.dart file to see that the check wouldn't do anything before the await, since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm just trying to understand what's flutter doing here, because I don't think we should be getting an "init" on something that has been already "disposed". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The framework seems to be disposing of the link while the Something like:
|
||||||
} | ||||||
params.onPlatformViewCreated(viewId); | ||||||
}); | ||||||
return controller; | ||||||
} catch (exception, stack) { | ||||||
FlutterError.reportError(FlutterErrorDetails( | ||||||
exception: exception, | ||||||
stack: stack, | ||||||
library: 'url_launcher', | ||||||
context: ErrorDescription('while initializing view $viewId'), | ||||||
)); | ||||||
} | ||||||
} | ||||||
|
||||||
static final Map<int, LinkViewController> _instances = | ||||||
|
@@ -160,7 +171,7 @@ class LinkViewController extends PlatformViewController { | |||||
final int viewId; | ||||||
|
||||||
/// The context of the [Link] widget that created this controller. | ||||||
final BuildContext context; | ||||||
BuildContext? context; | ||||||
|
||||||
late html.Element _element; | ||||||
|
||||||
|
@@ -263,14 +274,29 @@ class LinkViewController extends PlatformViewController { | |||||
} | ||||||
|
||||||
@override | ||||||
Future<void> dispose() async { | ||||||
Future<void> dispose() { | ||||||
context = null; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kind of like the context being nullable (despite the $billion mistake), since it makes people aware that it may not be safe to access it. I went over it again and realized the context wasn't actually used anywhere, so I removed it. I also realized that the element need not be late initialized, so there'd be no need for _isInitialized and the asserts, and so with nothing nullable, I added an _isDisposed as you suggest 😄 |
||||||
if (_isInitialized) { | ||||||
assert(_instances[viewId] == this); | ||||||
_instances.remove(viewId); | ||||||
return _asyncDispose(); | ||||||
} | ||||||
return Future<void>.value(); | ||||||
} | ||||||
|
||||||
Future<void> _asyncDispose() async { | ||||||
try { | ||||||
if (_instances.isEmpty) { | ||||||
await _clickSubscription.cancel(); | ||||||
} | ||||||
await SystemChannels.platform_views.invokeMethod<void>('dispose', viewId); | ||||||
} catch (exception, stack) { | ||||||
FlutterError.reportError(FlutterErrorDetails( | ||||||
exception: exception, | ||||||
stack: stack, | ||||||
library: 'url_launcher', | ||||||
context: ErrorDescription('while disposing view $viewId'), | ||||||
)); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest keeping
context
final and adding a new field_isDisposed
: