home / skills / hoangnguyen0403 / agent-skills-standard / legacy-state

legacy-state skill

/skills/android/legacy-state

This skill enforces Android legacy state practices by mandating repeatOnLifecycle with StateFlow and viewLifecycleOwner usage to prevent leaks.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill legacy-state

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
1007 B
---
name: Android Legacy State
description: Standards for State integration with Views using Coroutines and Lifecycle
metadata:
  labels: [android, state, views, lifecycle]
  triggers:
    files: ['**/*Fragment.kt', '**/*Activity.kt']
    keywords: ['repeatOnLifecycle', 'launchWhenStarted']
---

# Android Legacy State Standards

## **Priority: P1**

## Implementation Guidelines

### Flow Consumption

- **Rule**: ALWAYS use `repeatOnLifecycle(Lifecycle.State.STARTED)` to collect flows in Views.
- **Why**: Prevents crashes (collecting while view is destroyed) and saves resources (stops collecting in background).

### LiveData vs Flow

- **New Code**: Use `StateFlow` exclusively.
- **Legacy**: If using LiveData, observe with `viewLifecycleOwner` (Fragment), NOT `this`.

## Anti-Patterns

- **launchWhenX**: `**Deprecated**: Use repeatOnLifecycle.`
- **observe(this)**: `**Leak Risk**: Use viewLifecycleOwner in Fragments.`

## References

- [Flow Consumption Template](references/implementation.md)

Overview

This skill defines concise standards for integrating state with Android Views using Kotlin coroutines and the Android lifecycle. It focuses on safe Flow collection, migration guidance from LiveData, and avoiding common anti-patterns that cause leaks or crashes. The goal is predictable, lifecycle-aware UI state handling across Activities and Fragments.

How this skill works

The guidance enforces collecting StateFlow and other Flows inside repeatOnLifecycle(Lifecycle.State.STARTED) so collection automatically starts and stops with the view lifecycle. For legacy LiveData usage, it requires observing with viewLifecycleOwner in Fragments to avoid leaks. It also calls out deprecated and risky patterns like launchWhenX and observe(this) and recommends explicit, lifecycle-aware collection instead.

When to use it

  • Collecting StateFlow/Flow in Activities and Fragments to update UI reactively.
  • Migrating legacy LiveData-based state to StateFlow in new code.
  • Implementing lifecycle-aware coroutines to avoid background resource use when UI is not visible.
  • Reviewing code for leaks or crashes related to incorrect lifecycle owners.
  • Enforcing team-wide coding standards for Android state handling.

Best practices

  • Always use repeatOnLifecycle(Lifecycle.State.STARTED) when collecting flows in Views.
  • Prefer StateFlow for new state implementations; treat LiveData as legacy only.
  • In Fragments observe LiveData with viewLifecycleOwner, never with the Fragment instance.
  • Avoid launchWhenStarted / launchWhenResumed; use repeatOnLifecycle for deterministic behavior.
  • Keep collection scopes tied to view lifecycle to prevent collecting after destroy.

Example use cases

  • A Fragment collecting a ViewModel StateFlow to render a list while respecting pause/resume.
  • Replacing LiveData observers with StateFlow and repeatOnLifecycle during a migration sprint.
  • Code review checklist item: flag observe(this) and launchWhenX occurrences for remediation.
  • Implementing a splash-to-main flow where background collection must stop when UI is not visible.

FAQ

Why repeatOnLifecycle instead of launchWhenStarted?

repeatOnLifecycle creates a new coroutine in the lifecycleScope and cancels it automatically on stop, avoiding subtle race conditions and ensuring collection restarts reliably.

Can I keep using LiveData?

Legacy LiveData is allowed but observe with viewLifecycleOwner in Fragments. Prefer StateFlow for new code for clearer semantics with coroutines.