skip to content

In Flutter add-to-app on Android, when do you embed a FlutterFragment instead of a FlutterActivity, and what must the host activity do for it?

level: middleimportance: should knowfreq 22%

answer

  1. part of a screen vs whole screen
  2. forward OS callbacks to the fragment
  3. shouldAutomaticallyHandleOnBackPressed on API 33+
  4. SurfaceView default, TextureView for interleaving
  5. shouldAttachEngineToActivity(false) for partial UI

basics

~20 s

Use FlutterFragment when Flutter is only part of a native screen, such as a card or a tab. The host activity must forward OS calls like onPostResume, onNewIntent, back presses, permission results, onUserLeaveHint and onTrimMemory to the fragment.

solid answer

~40 s

`FlutterActivity` is the quickest way to show a full Flutter screen. `FlutterFragment` fits when Flutter renders only part of a native screen — a loyalty-points card on a native booking page, a tab, a drawer. Because a fragment does not receive every OS event itself, the docs require the host `Activity` to forward `onPostResume`, `onNewIntent`, `onBackPressed`, `onRequestPermissionsResult`, `onUserLeaveHint` and `onTrimMemory` to it; on Android 13+ (API 33) `shouldAutomaticallyHandleOnBackPressed(true)` replaces manual back forwarding and supports predictive back. For partial UI, build it with `shouldAttachEngineToActivity(false)` so Flutter and its plugins do not take over the activity's system chrome. Rendering defaults to `SurfaceView`, which is faster but must be the top- or bottom-most view; choose `RenderMode.texture` when Flutter must sit between native views or be animated.

go deeper

for a junior

Remember that FlutterFragment embeds Flutter in part of a native screen while FlutterActivity shows a full screen.

for a middle

List the calls the host activity forwards and explain shouldAutomaticallyHandleOnBackPressed on API 33 and above.

for a senior

Choose render and transparency modes and use shouldAttachEngineToActivity(false) so partial Flutter UI does not interfere with native system chrome.

for a principal

Define integration conventions for teams embedding Flutter fragments across many native screens, including engine sharing and ownership of system UI.

## Two containers on Android | | `FlutterActivity` | `FlutterFragment` | |---|---|---| | Shows | A whole screen | Part of a screen, or a screen inside a single-activity app | | Setup | Manifest entry plus an intent builder | Added by the host's `FragmentManager` | | OS events | Receives them itself | Needs the host activity to forward them | | Typical use | A standalone Flutter feature | A card, tab, drawer or panel inside native UI | In an airline app, a full loyalty dashboard fits `FlutterActivity`; a small Flutter points summary embedded on the native booking screen fits `FlutterFragment`. ## Creating one ```kotlin class BookingActivity : FragmentActivity() { private var flutterFragment: FlutterFragment? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.booking) val fm = supportFragmentManager flutterFragment = fm.findFragmentByTag(TAG) as FlutterFragment? if (flutterFragment == null) { val fragment = FlutterFragment.withCachedEngine("loyalty_engine") .shouldAttachEngineToActivity(false) .build<FlutterFragment>() flutterFragment = fragment fm.beginTransaction().add(R.id.loyalty_card, fragment, TAG).commit() } } companion object { private const val TAG = "loyalty_fragment" } } ``` The builder also offers `withNewEngine()`, a Dart entrypoint, an initial route (for new engines), render and transparency modes. ## The calls the host must forward The fragment cannot see every event its activity receives, so the host overrides and forwards: 1. `onPostResume()` 2. `onNewIntent(intent)` 3. `onBackPressed()` — or, on Android 13+ (API 33), build with `shouldAutomaticallyHandleOnBackPressed(true)` to handle back and predictive back without forwarding 4. `onRequestPermissionsResult(...)` 5. `onUserLeaveHint()` 6. `onTrimMemory(level)` Missing one shows up as subtle bugs: a plugin never gets its permission result, deep links through `onNewIntent` are ignored, or the Flutter back stack is skipped. ## Partial UI and the activity's system chrome A full-screen fragment may reasonably control the status bar, navigation bar and orientation. A fragment that is one card among native views should not. `shouldAttachEngineToActivity(false)`: - stops the fragment from exposing its `Activity` to Flutter plugins; - stops Flutter from controlling the activity's system UI. ## Render mode - **`SurfaceView`** (default): significantly better performance, but it cannot be interleaved in the middle of a view hierarchy — it must be the bottom-most or top-most view. - **`TextureView`** (`renderMode(FlutterView.RenderMode.texture)`): can sit between native views and be animated with them, at a performance cost. - `transparencyMode(FlutterView.TransparencyMode.transparent)` gives a see-through background when native content should show behind Flutter. ## Common pitfalls - Adding a new fragment on every `onCreate` after rotation instead of finding the existing one by tag. - Forgetting the forwarding overrides because `FlutterActivity` never needed them. - Leaving `shouldAttachEngineToActivity` at its default for a small card, then finding Flutter changing the status bar colour. - Using `SurfaceView` for a card that native content scrolls over. (The activity and fragment lifecycles themselves belong to the Android topics; here what matters is what Flutter needs from them.)

  • What breaks if the host activity does not forward onRequestPermissionsResult to the FlutterFragment?
    Plugins inside the Flutter fragment that request runtime permissions never receive the result, so their Dart futures hang or report failure even after the user granted the permission.
  • Why switch a FlutterFragment to RenderMode.texture?
    The default `SurfaceView` must be the top- or bottom-most view and cannot be interleaved in the view hierarchy. When Flutter content sits between native views, or must animate with them, `TextureView` works at a performance cost.

A FlutterFragment is like a subtenant in a shared flat: the main tenant (the host activity) receives all the post and must pass the subtenant's letters on — and a polite subtenant (shouldAttachEngineToActivity false) does not repaint the hallway.

saying these in an interview costs you the question

  • FlutterFragment receives every OS callback without host forwarding.
  • TextureView is the faster default render mode for FlutterFragment.
  • A small FlutterFragment card should control the activity's status bar.
  • FlutterFragment cannot use a pre-warmed cached engine.
  • Back handling always requires overriding onBackPressed on every API level.