Direct answer
Android Geocoder is an interface to a device geocoding implementation, not a documented offline database. isPresent() reports that an implementation exists on the device and may return results; it does not guarantee that a particular request will succeed or run without network access. The API warns that geocoding services may have no availability or accuracy guarantee and says results are best guesses. Its synchronous methods may hit the network and may block for excessive time. Treat those as platform boundaries, not as a promise about every provider or phone. API 33 added three listener forms: reverse lookup by latitude/longitude, forward lookup by name with no bounds, and forward lookup by name with a bounding box. The corresponding synchronous overloads date to API 1 and were deprecated in API 33 to avoid blocking a thread; older supported devices still need a deliberate background-thread policy if those overloads are used. A listener avoids synchronous waiting, but Android gives no callback-time guarantee; only one callback method is invoked, and error text may be absent or vary in format. Neither path guarantees local execution, offline behavior, cancellation, speed, or availability. A successful listener callback can contain an empty list; legacy methods can return null or an empty list when no match or backend exists. Preserve the exact overload, callback category, API level, locale, request type, and time rather than rewriting every empty result as “address not found.” First decide whether the product truly needs geocoding. Translating an address or preserving its original text is different from resolving it into coordinates or converting coordinates back into a localized postal address. Do not call Geocoder just to make an offline claim sound richer. If the feature requires a guaranteed offline lookup, evaluate a separately licensed, bundled geographic dataset or keep the address unresolved for user review. A data package brings its own coverage, update, storage, language, and licensing contract; it is not a hidden capability of Geocoder. If an app offers geocoding, treat addresses and coordinates as potentially sensitive. Android warns that Geocoder may hit the network but does not specify one backend, destination, or payload for every device. In the AOSP implementation the framework delegates through LocationManager/Binder to a geocode provider; depending on the device, provider work and its egress may be outside the app process and UID. A counter limited to the app UID therefore cannot establish that no provider traffic occurred, and Android restricts ordinary apps from reading other UIDs’ traffic counters. Do not infer zero egress from local inference, an app-UID-only counter, or one cached result. Make network-backed behavior distinct and disclosed, require user choice before a sensitive query, and use device-level capture or a controlled provider test before making a data-flow claim. Handle concurrency through one state owner. Attach a request ID, input revision, locale, and operation to each call. When a callback arrives, the owner must compare that identity with the active request and apply the candidate in the same serialized/atomic state transition; checking in the callback and later enqueueing a write leaves a race where an older address can overwrite newer state. Stale results are discarded. The listener has no documented cancellation or ordering guarantee. Keep the original address beside candidates, bound result count, and ask the user to choose among plausible nearby places. Test capability and outcome independently. Record isPresent(), the exact API path, network policy, input fixture class, locale, returned candidate count, null versus empty result, IOException or callback failure, and whether any network activity occurred. Repeat with fresh synthetic addresses while offline; do not count a result from an earlier session as evidence. An implementation may use cache or local service, so a single pass does not prove all queries are offline. Conversely, a failed offline query does not prove every implementation always requires a server. Do not use a best-guess geocoder result for emergency routing, legal boundaries, or another safety-critical or regulatory decision. Keep user review and an authoritative source outside a model suggestion. The method here is a verification plan: the selected address can remain unresolved, be manually confirmed, or be processed by an explicitly selected route with documented limitations. It does not assert Cove has a Geocoder integration, location permission flow, offline map data, or a measured network behavior.
An address resolves online but not in airplane mode
A local assistant extracts a hotel address from a user note and the app converts it to coordinates using Android Geocoder. A warm test returned one candidate, so the team assumed the next result would work offline. On a fresh disconnected device, isPresent() is true but the callback returns an empty result.
Decision
Treat Geocoder presence, each request result, network behavior, and address meaning as separate evidence; preserve the original text and offer a user-reviewed fallback instead of guessing.
Expected outcome
The application can report that this request was unresolved under the tested conditions, without declaring the address invalid or promising universal offline geocoding.
Evidence to collect
The claim becomes reviewable only when the following evidence is attached to the same artifact and test run:
- Device/API/provider and request identity
- isPresent, callback/exception, and empty-result cases
- Network observation limits and address review
Task quality needs a versioned corpus and acceptance rules. Fluent sample output is not an accuracy result.
Implementation workflow
- Separate text translation from geocoding. Write down whether the task needs address text, a coordinate, or a reverse-geocoded label. Preserve the original address and do not call Geocoder when the application only needs to translate or display it.
- Pin API and implementation availability. Record device/API level, locale, Geocoder.isPresent(), request overload and provider environment. Treat presence as an implementation hint only; it is not a successful-request or offline-capability check.
- Select the overload and atomically apply current results. API 33 listener overloads cover reverse lookup, forward lookup without bounds, and forward lookup with a bounding box; legacy synchronous variants were deprecated in API 33 and may block, so any fallback belongs off the main thread. Have one state owner compare request ID/input revision and apply the result in one serialized transaction; never split the check from the write. Ignore stale callbacks and do not assume cancellation, callback timing, or ordering.
- Classify outcomes without guessing. Handle candidate results, empty or null results, no backend, IOException, and later failure separately. Preserve the original input and show candidate ambiguity; never reinterpret a best guess as ground truth.
- Verify provider network attribution. Run fresh synthetic fixtures with connectivity denied and allowed. Record the exact overload, app UID and device-level network observations. Framework Binder delegation may place provider egress outside the app UID; a negative app-only TrafficStats counter is not proof of no network. Do not infer zero egress from a cached result or local inference.
- Offer a deliberate fallback. If a guaranteed offline result is required, use a separately reviewed local dataset with an explicit coverage and update policy, or keep the location unresolved for user confirmation. Do not silently fall back to an undisclosed network route.
Keep each transition observable. A failure should identify the stage, artifact, runtime, and recovery action without logging private user content.
Acceptance criteria
- The feature distinguishes address translation/display, forward geocoding, and reverse geocoding as separate tasks.
- Geocoder.isPresent() is not treated as proof that a request succeeds or is offline; API 33 async behavior is not described as a network or cancellation guarantee.
- All three API 33 listener overloads and any legacy synchronous fallback are distinguished; callback ordering/timing/error text are not assumed, and stale result check-plus-apply is atomic in one owner.
- Empty listener results, legacy null/empty results, error callbacks, absent backend, locale variation, and fresh offline requests have distinct outcomes.
- No safety-critical location decision, Cove integration, provider destination, or zero-upload claim is inferred without its own evidence.
Decision table
| Dimension | Choice or evidence | How to interpret it |
|---|---|---|
| Preserve or translate address text | Keep original text and use an explicitly tested translation task if needed. | Does not resolve a point or prove a geocoder can operate offline. |
| Android Geocoder | Choose the exact overload, inspect each result, and validate the provider path. | isPresent reports a possible implementation; listener overloads avoid synchronous waiting but do not guarantee offline use, timing, cancellation, availability, or accuracy. |
| App-UID traffic counter | Use only as evidence about the app UID it measures. | A framework/provider may perform separate work; app-only counters cannot establish that no provider egress occurred. |
| Bundled offline geographic data | Ship or install a separately licensed local dataset with a version and coverage manifest. | Can support a bounded offline claim only for tested coverage; updates, storage, and licensing remain separate obligations. |
| Unresolved location | Retain the address and ask the user to confirm or choose another route. | Honest when no reliable candidate exists; safer than treating a guessed point as authoritative. |
Failure patterns to prevent
- Equating isPresent with offline availability
- Inferring provider network behavior from connectivity state
- Treating an address result as proven location truth
Also prevent silent fallback, unpinned artifacts, missing cancellation, and conclusions that combine unlike configurations. Store unsuccessful runs alongside successful ones.
Minimum reproducibility record
| Layer | Record |
|---|---|
| Device | Manufacturer, model, chipset, RAM class, operating-system build |
| Software | Application version and git commit |
| Model | Family, variant, revision, format, file length, hash, quantization |
| Runtime | Name, revision, requested backend, observed backend evidence |
| Workload | Fixture revision, input hash, prompt hash, output policy |
| Outcome | Completed, failed, cancelled, fallback, and privacy-safe diagnostics |
Release checklist
- ☐ The primary query is answered without an unsupported number.
- ☐ Every artifact and runtime is pinned.
- ☐ The representative task and failure policy are explicit.
- ☐ Lifecycle, cancellation, cleanup, and fallback are tested.
- ☐ User-content and network boundaries are documented.
- ☐ Result wording applies only to the recorded configuration.
- ☐ The page links to raw method or evidence when results are added.
Sources and related evidence
- On-device and hybrid routing boundary
- Android privacy and security
- Android API — Geocoder presence, network warning, and result behavior
- Android API — GeocodeListener asynchronous callback
- Android API — NetworkCapabilities for connection state
- Android API — TrafficStats UID attribution limits
- AOSP — Geocoder framework delegation through LocationManager
- AOSP — GeocoderProxy Binder forwarding to a provider
Chinese deployment and troubleshooting content is organized in the .奇连 AI 端侧专题.
Frequently asked questions
Does Geocoder.isPresent() prove that address lookup works offline?
No. It reports that a geocoder implementation is present and may return results. A specific query can still fail, return nothing, or rely on an implementation that may use network services.
Which Geocoder overloads became asynchronous in API 33?
There are listener overloads for reverse lookup, forward lookup without a bounding box, and forward lookup with a bounding box. Their legacy synchronous counterparts were deprecated in API 33; they can block and should not run on the UI thread.
Does a zero app-UID traffic counter prove Geocoder did not use a network?
No. The framework delegates to a provider, whose process/UID can differ from the app. TrafficStats app-UID counters say nothing conclusive about separate provider egress; use device-level observation and scope claims to the tested build/provider.
How should the owner handle a callback racing with a newer address?
Compare request ID and input revision and apply the candidate inside one serialized owner transition. A check followed by a queued write is racy: a newer request can become active between those operations.
Is an empty Geocoder response proof that the typed address is invalid?
No. The API can return an empty or null result when there is no match or no backend service. Preserve that outcome separately from malformed input, I/O failure, and an actual candidate.
Can a local model safely use the first returned coordinate?
Not by default. Results are best guesses with no availability or accuracy guarantee. Keep the source address, show alternatives, and require review for any consequential location action.