Skip to content

Commit 48bf7ac

Browse files
Eagerly remove the PlatformView from the view hierarchy on Android (flutter#43423)
Eagerly remove the PlatformView from the view hierarchy on Android. Fixes [#107297](flutter/flutter#107297) ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing.
1 parent 42df55a commit 48bf7ac

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,22 @@ public void dispose(int viewId) {
232232
Log.e(TAG, "Disposing unknown platform view with id: " + viewId);
233233
return;
234234
}
235+
if (platformView.getView() != null) {
236+
final View embeddedView = platformView.getView();
237+
final ViewGroup pvParent = (ViewGroup) embeddedView.getParent();
238+
if (pvParent != null) {
239+
// Eagerly remove the embedded view from the PlatformViewWrapper.
240+
// Without this call, we see some crashes because removing the view
241+
// is used as a signal to stop processing.
242+
pvParent.removeView(embeddedView);
243+
}
244+
}
235245
platformViews.remove(viewId);
236-
237246
try {
238247
platformView.dispose();
239248
} catch (RuntimeException exception) {
240249
Log.e(TAG, "Disposing platform view threw an exception", exception);
241250
}
242-
243251
if (usesVirtualDisplay(viewId)) {
244252
final VirtualDisplayController vdController = vdControllers.get(viewId);
245253
final View embeddedView = vdController.getView();
@@ -581,7 +589,8 @@ private long configureForVirtualDisplay(
581589
// Configures the view for Texture Layer Hybrid Composition mode, returning the associated
582590
// texture ID.
583591
@TargetApi(23)
584-
private long configureForTextureLayerComposition(
592+
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
593+
public long configureForTextureLayerComposition(
585594
@NonNull PlatformView platformView,
586595
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
587596
// This mode attaches the view to the Android view hierarchy and record its drawing

shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
4040
import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
4141
import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel;
42+
import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel.PlatformViewTouch;
4243
import io.flutter.embedding.engine.systemchannels.SettingsChannel;
4344
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
4445
import io.flutter.plugin.common.MethodCall;
@@ -79,6 +80,8 @@ public CountingPlatformView(Context context) {
7980

8081
@Override
8182
public void dispose() {
83+
// We have been removed from the view hierarhy before the call to dispose.
84+
assertNull(view.getParent());
8285
disposeCalls++;
8386
}
8487

@@ -98,6 +101,46 @@ public void onFlutterViewDetached() {
98101
}
99102
}
100103

104+
@Test
105+
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
106+
public void itRemovesPlatformViewBeforeDiposeIsCalled() {
107+
PlatformViewsController platformViewsController = new PlatformViewsController();
108+
FlutterJNI jni = new FlutterJNI();
109+
attach(jni, platformViewsController);
110+
// Get the platform view registry.
111+
PlatformViewRegistry registry = platformViewsController.getRegistry();
112+
113+
// Register a factory for our platform view.
114+
registry.registerViewFactory(
115+
CountingPlatformView.VIEW_TYPE_ID,
116+
new PlatformViewFactory(StandardMessageCodec.INSTANCE) {
117+
@Override
118+
public PlatformView create(Context context, int viewId, Object args) {
119+
return new CountingPlatformView(context);
120+
}
121+
});
122+
123+
// Create the platform view.
124+
int viewId = 0;
125+
final PlatformViewsChannel.PlatformViewCreationRequest request =
126+
new PlatformViewsChannel.PlatformViewCreationRequest(
127+
viewId,
128+
CountingPlatformView.VIEW_TYPE_ID,
129+
0,
130+
0,
131+
128,
132+
128,
133+
View.LAYOUT_DIRECTION_LTR,
134+
null);
135+
PlatformView pView = platformViewsController.createPlatformView(request, true);
136+
assertTrue(pView instanceof CountingPlatformView);
137+
CountingPlatformView cpv = (CountingPlatformView) pView;
138+
platformViewsController.configureForTextureLayerComposition(pView, request);
139+
assertEquals(0, cpv.disposeCalls);
140+
platformViewsController.disposePlatformView(viewId);
141+
assertEquals(1, cpv.disposeCalls);
142+
}
143+
101144
@Test
102145
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
103146
public void itNotifiesPlatformViewsOfEngineAttachmentAndDetachment() {
@@ -121,7 +164,7 @@ public PlatformView create(Context context, int viewId, Object args) {
121164
int viewId = 0;
122165
final PlatformViewsChannel.PlatformViewCreationRequest request =
123166
new PlatformViewsChannel.PlatformViewCreationRequest(
124-
viewId++,
167+
viewId,
125168
CountingPlatformView.VIEW_TYPE_ID,
126169
0,
127170
0,

0 commit comments

Comments
 (0)