Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class FlutterView extends FrameLayout {
// Internal view hierarchy references.
@Nullable
private FlutterRenderer.RenderSurface renderSurface;
private boolean didRenderFirstFrame;

// Connections to a Flutter execution context.
@Nullable
Expand Down Expand Up @@ -97,6 +98,13 @@ public void onAccessibilityChanged(boolean isAccessibilityEnabled, boolean isTou
}
};

private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
@Override
public void onFirstFrameRendered() {
didRenderFirstFrame = true;
}
};

/**
* Constructs a {@code FlutterView} programmatically, without any XML attributes.
* <p>
Expand Down Expand Up @@ -171,11 +179,34 @@ private void init() {
break;
}

// Register a listener for the first frame render event to set didRenderFirstFrame.
renderSurface.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);

// FlutterView needs to be focusable so that the InputMethodManager can interact with it.
setFocusable(true);
setFocusableInTouchMode(true);
}

/**
* Returns true if an attached {@link FlutterEngine} has rendered at least 1 frame to this
* {@code FlutterView}.
* <p>
* Returns false if no {@link FlutterEngine} is attached.
* <p>
* This flag is specific to a given {@link FlutterEngine}. The following hypothetical timeline
* demonstrates how this flag changes over time.
* <ol>
* <li>{@code flutterEngineA} is attached to this {@code FlutterView}: returns false</li>
* <li>{@code flutterEngineA} renders its first frame to this {@code FlutterView}: returns true</li>
* <li>{@code flutterEngineA} is detached from this {@code FlutterView}: returns false</li>
* <li>{@code flutterEngineB} is attached to this {@code FlutterView}: returns false</li>
* <li>{@code flutterEngineB} renders its first frame to this {@code FlutterView}: returns true</li>
* </ol>
*/
public boolean hasRenderedFirstFrame() {
return didRenderFirstFrame;
}

/**
* Adds the given {@code listener} to this {@code FlutterView}, to be notified upon Flutter's
* first rendered frame.
Expand Down Expand Up @@ -471,6 +502,7 @@ public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
this.flutterEngine = flutterEngine;

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

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

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

Expand Down