agentleFS
wrinfotelwrinfotel/verified-android-skills/skills/compose-migration/SKILL.md

compose-migration

Skill0 starsChanged 32 days agoMITView on GitHub

Interop and incremental migration between Android Views and Jetpack Compose: ComposeView lifecycle strategy in Fragments, AndroidView factory/update split, XML layout interop, and migration ordering. Use when embedding composables in View hierarchies, wrapping legacy views, or planning a View-to-Compose migration. Core rules have machine checks in checks/.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    After ANY interop or migration edit, run the Verification step (bottom of this file).

    line 16
  2. Very specific:

    MUST keep the factory lambda pure: create the view and nothing else — it runs once at instantiation, so state read there goes stale.

    line 55
  3. Very specific:

    When a layout hosts more than one ComposeView, each MUST have a unique android:id, or savedInstanceState restoration breaks.

    line 85
  4. Very specific:

    No deterministic check covers ordering.

    line 117
  5. Distinctive:

    Run after every interop or migration edit (from the project root):

    line 122
  6. Very specific:

    All three must pass (exit 0) before declaring the task done.

    line 130

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Compose Migration

Operational rules for a coding agent. RIGHT/WRONG pairs are canonical. After ANY interop or migration edit, run the Verification step (bottom of this file).

1. ComposeView in Fragments — set the composition strategy

MUST set setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) on every ComposeView used inside a Fragment, so the composition disposes with the Fragment's view lifecycle. The default strategy (DisposeOnDetachedFromWindowOrReleasedFromPool) disposes on window detach and may cause state loss during incremental migration.

WRONG:

class ProfileFragment : Fragment() {
    override fun onCreateView(...): View =
        ComposeView(requireContext())
            .apply { setContent { ProfileScreen() } }
}

RIGHT:

class ProfileFragment : Fragment() {
    override fun onCreateView(...): View =
        ComposeView(requireContext()).apply {
            setViewCompositionStrategy(
                ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
            )
            setContent { ProfileScreen() }
        }
}

Fragments are a transitionary step: Compose-only screens belong in a single-Activity architecture without Fragments.

2. AndroidView — factory creates once, update reads state

MUST keep the factory lambda pure: create the view and nothing else — it runs once at instantiation, so state read there goes stale. MUST read Compose state in update, which reruns whenever the state it reads changes. MUST NOT hold view references outside AndroidView via remember.

WRONG:

AndroidView(
    factory = { context ->
        TextView(context).apply { text = count.value.toString() }  // stale
    },
)

RIGHT:

AndroidView(
    factory = { context -> TextView(context) },
    update = { view -> view.text = count.value.toString() },
)

Reach for AndroidView only for SDK components without a Compose counterpart (ads, maps, WebView); custom views are better rewritten as composables. In lazy lists and pagers use the AndroidView overload with onReset (1.4.0+) so the underlying view instance is reused.

3. XML interop — unique IDs for multiple ComposeViews

When a layout hosts more than one ComposeView, each MUST have a unique android:id, or savedInstanceState restoration breaks.

WRONG:

<androidx.compose.ui.platform.ComposeView android:layout_width="match_parent" />
<androidx.compose.ui.platform.ComposeView android:layout_width="match_parent" />

RIGHT:

<androidx.compose.ui.platform.ComposeView android:id="@+id/header_compose" ... />
<androidx.compose.ui.platform.ComposeView android:id="@+id/body_compose" ... />

Embed legacy XML during migration via AndroidViewBinding (androidx.compose.ui:ui-viewbinding) — for small legacy layouts only, never for full screens.

4. Migration order (review-verified)

  • New features and screens: Compose first — ComposeView in the Fragment's onCreateView with the strategy above while navigation is still Fragment-based.
  • Existing screens: migrate bottom-up — reusable leaf elements first, building a shared component library as the source of truth, one screen at a time; start with simple screens.
  • Navigation: move to Navigation Compose only after all Fragments are replaced by screen-level composables; keep Fragment navigation until then.
  • Rely on UI tests across migration steps to catch regressions.

No deterministic check covers ordering; verify against references/migration.md.

Verification

Run after every interop or migration edit (from the project root):

bash <skill-dir>/checks/check_composeview_fragment_strategy.sh <src-dir>
bash <skill-dir>/checks/check_androidview_factory_state.sh     <src-dir>
bash <skill-dir>/checks/check_composeview_ids_in_xml.sh        <res-or-src-dir>

All three must pass (exit 0) before declaring the task done. Checks are deterministic file-level heuristics — they catch the documented anti-patterns above, not every migration bug. Ordering (§4) is verified by review against references/migration.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.