Skip to main content

Import the api package

The namespaces are extension properties. Without the second import, RunAnywhere.llm does not resolve, and the error message points at the property rather than the missing import.

Initialize in Application.onCreate

Phase 2 runs in the background, so initializing at launch gives it time to finish before anything needs it.

Let generation load the model

Generation auto-loads and downloads when needed. Reach for models.load when you want to control when the cost is paid, such as warming a model behind a splash screen.

Collect in viewModelScope

The flow is cancelled when the ViewModel clears, so a generation cannot outlive the screen it belongs to.

Stream anything a person waits for

A 200-token reply takes seconds. Streaming turns that into words appearing immediately.

Cap output length

maxOutputTokens is the biggest lever on latency and battery.

Unload what you are not using

Holding a language model, a speech model, and a vision model at once on a phone is how you get ERROR_CODE_INSUFFICIENT_MEMORY.

Trim conversations

History grows until it exceeds the context window. Keep the system message and the recent turns.

Never swallow CancellationException

Catching it breaks structured concurrency: the coroutine keeps running after its scope is gone.

Close what holds hardware

Voice sessions hold the microphone; AudioRecord and AudioTrack hold audio devices. Close them in onCleared, or in a finally.

Use structured output rather than asking nicely

Asking for JSON in a system prompt works most of the time, which is the problem.
CONSTRAINED is not implemented and throws.

Test on an ARM64 device

The NPU backend is arm64 only and absent from x86_64 emulators. Performance measured on an emulator means nothing.

Keep the Hugging Face token out of source

Hold it in EncryptedSharedPreferences or the Keystore, never in code, assets, or logs.