Skip to content

Commit 2d2cfc0

Browse files
Expose a hasRenderedFirstFrame() method in FlutterView (#34275). (#9285)
1 parent 8040117 commit 2d2cfc0

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

shell/platform/android/io/flutter/embedding/android/FlutterView.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public class FlutterView extends FrameLayout {
6868
// Internal view hierarchy references.
6969
@Nullable
7070
private FlutterRenderer.RenderSurface renderSurface;
71+
private boolean didRenderFirstFrame;
7172

7273
// Connections to a Flutter execution context.
7374
@Nullable
@@ -97,6 +98,13 @@ public void onAccessibilityChanged(boolean isAccessibilityEnabled, boolean isTou
9798
}
9899
};
99100

101+
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
102+
@Override
103+
public void onFirstFrameRendered() {
104+
didRenderFirstFrame = true;
105+
}
106+
};
107+
100108
/**
101109
* Constructs a {@code FlutterView} programmatically, without any XML attributes.
102110
* <p>
@@ -171,11 +179,34 @@ private void init() {
171179
break;
172180
}
173181

182+
// Register a listener for the first frame render event to set didRenderFirstFrame.
183+
renderSurface.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
184+
174185
// FlutterView needs to be focusable so that the InputMethodManager can interact with it.
175186
setFocusable(true);
176187
setFocusableInTouchMode(true);
177188
}
178189

190+
/**
191+
* Returns true if an attached {@link FlutterEngine} has rendered at least 1 frame to this
192+
* {@code FlutterView}.
193+
* <p>
194+
* Returns false if no {@link FlutterEngine} is attached.
195+
* <p>
196+
* This flag is specific to a given {@link FlutterEngine}. The following hypothetical timeline
197+
* demonstrates how this flag changes over time.
198+
* <ol>
199+
* <li>{@code flutterEngineA} is attached to this {@code FlutterView}: returns false</li>
200+
* <li>{@code flutterEngineA} renders its first frame to this {@code FlutterView}: returns true</li>
201+
* <li>{@code flutterEngineA} is detached from this {@code FlutterView}: returns false</li>
202+
* <li>{@code flutterEngineB} is attached to this {@code FlutterView}: returns false</li>
203+
* <li>{@code flutterEngineB} renders its first frame to this {@code FlutterView}: returns true</li>
204+
* </ol>
205+
*/
206+
public boolean hasRenderedFirstFrame() {
207+
return didRenderFirstFrame;
208+
}
209+
179210
/**
180211
* Adds the given {@code listener} to this {@code FlutterView}, to be notified upon Flutter's
181212
* first rendered frame.
@@ -471,6 +502,7 @@ public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
471502
this.flutterEngine = flutterEngine;
472503

473504
// Instruct our FlutterRenderer that we are now its designated RenderSurface.
505+
didRenderFirstFrame = false;
474506
this.flutterEngine.getRenderer().attachToRenderSurface(renderSurface);
475507

476508
// Initialize various components that know how to process Android View I/O
@@ -536,6 +568,7 @@ public void detachFromFlutterEngine() {
536568
textInputPlugin.getInputMethodManager().restartInput(this);
537569

538570
// Instruct our FlutterRenderer that we are no longer interested in being its RenderSurface.
571+
didRenderFirstFrame = false;
539572
flutterEngine.getRenderer().detachFromRenderSurface();
540573
flutterEngine = null;
541574

0 commit comments

Comments
 (0)