A lot of what gets filed as "flaky mobile test" is a locator that was never stable in the first place. The test passed for three weeks, a developer wrapped a view in a FrameLayout, and an absolute XPath that encoded the entire hierarchy fell over. Nobody touched the test. It still broke.

This is the order I pick locators in, why, and what each one looks like when it fails. Android and iOS first, then a short Flutter section, then the part that actually fixes the problem long-term: getting IDs added where the feature is written.

The rule underneath all of it

Pick the attribute a developer set on purpose. Avoid the one the render tree happened to produce.

An accessibilityIdentifier, an android:id, a testID, a Flutter Key: someone typed those. They change when a human decides to change them. Position in a hierarchy, sibling index, the class name of a wrapper: those change whenever the layout is refactored, a design system component is swapped, or an OS update renders a control differently. Every tier below is a version of that rule.