πŸ€– Android AI and Generative AI

AI Tokens, Latency, and Cost Optimization for Mobile Apps

AI features have a running cost per request and a latency users feel on every tap. Both are driven mostly by tokens: how many you send, how many you generate, and which model processes them. Here's how to measure and reduce them without hurting quality.

✍️ Yunok Tech πŸ“… Updated ⏱ 3 min read 🎯 Advanced
On this page
  1. Tokens 101
  2. Where the tokens go in a chat
  3. Cost levers, in order of impact
  4. Latency: what users feel
  5. Trimming chat history
  6. Rate limits and retries
  7. Budgets and limits
  8. Examples
  9. Frequently asked questions
  10. Conclusion

A chat feature costs almost nothing in testing with five users. At 50,000 daily users, each sending ten messages with growing conversation history, the bill becomes a product decision. Meanwhile, users judge the feature by how quickly the first words appear. Tokens connect both problems.

Tokens 101

  • Models process text as tokens: chunks of characters. In English, a token averages a few characters. Other scripts, such as Hindi, may use more tokens per word.
  • You pay for input tokens (system instruction + context + history + user message) and output tokens, often at different rates.
  • Images, audio and documents also consume tokens.
  • Latency grows with input size (processing) and output length (generation).
Measure before optimisingKotlin
val tokens = model.countTokens(prompt)              // Firebase AI Logic: count tokens for a request
Log.d("AI", "input tokens=${tokens.totalTokens}")
// Response usage metadata reports prompt/candidate token counts when available:
// response.usageMetadata?.promptTokenCount, response.usageMetadata?.candidatesTokenCount

Where the tokens go in a chat

Token growth in multi-turn chat Each turn resends the system instruction and the entire history. Bars for turns one to five grow longer as history accumulates, so input tokens per request grow over the conversation. Trimming or summarizing history caps the growth. turn 1 turn 2 turn 3 turn 5 trimmed system history new message summary + recent turns
In chat, history dominates input cost. Capping it is usually the single biggest saving.

Cost levers, in order of impact

  1. Model tiering: use the smallest model that passes your evaluation, such as a Flash-Lite-class model for classification, short rewrites and extraction, and reserve larger models for hard reasoning.
  2. Trim context: keep the last N turns, and summarise older ones into a short memory. Send only relevant retrieved passages, not whole documents.
  3. Cap output: set maxOutputTokens, and ask for concise formats ("3 bullets").
  4. Cache: deduplicate identical requests (hash of prompt version + input). Use provider-side context caching for large repeated prefixes where supported.
  5. Move work on-device: Gemini Nano for supported tasks and devices costs nothing per request.
  6. Avoid accidental calls: no AI on every keystroke, scroll or screen open without user intent.

Latency: what users feel

  • Time to first token (TTFT) matters most for perceived speed. Stream responses so text appears immediately. See Streaming AI Responses in Compose.
  • Smaller prompts and smaller models reduce TTFT.
  • Show progress states ("Thinking…") and allow cancelling.
  • Prefetch or precompute where the action is predictable, for example summaries of items the user is likely to open, but only within budget.

Trimming chat history

HistoryTrimmer.ktKotlin
data class Turn(val role: String, val text: String)

class HistoryTrimmer(private val maxTurns: Int = 10, private val maxChars: Int = 8_000) {
    fun trim(history: List<Turn>, memorySummary: String?): List<Turn> {
        val recent = history.takeLast(maxTurns).toMutableList()
        // Drop oldest until under the character budget (rough token proxy)
        while (recent.sumOf { it.text.length } > maxChars && recent.size > 2) recent.removeAt(0)
        return buildList {
            memorySummary?.let { add(Turn("user", "Summary of earlier conversation: $it")) }
            addAll(recent)
        }
    }
}

Rate limits and retries

Retry only what's retryableKotlin
suspend fun <T> withAiRetry(maxAttempts: Int = 3, block: suspend () -> T): T {
    var delayMs = 500L
    repeat(maxAttempts - 1) {
        try { return block() }
        catch (e: Exception) {
            if (e is CancellationException) throw e
            val retryable = e is IOException || e is QuotaExceededException || e is ServerException
            if (!retryable) throw e
            delay(delayMs + Random.nextLong(0, 250))        // backoff + jitter
            delayMs *= 2
        }
    }
    return block()
}

QuotaExceededException and ServerException are Firebase AI Logic types. Adapt the check to your SDK or backend errors. Don't retry invalid requests or safety blocks.

Budgets and limits

  • Per-user daily request or token caps (server-side, or at least client-side for Firebase setups).
  • Budget alerts in your cloud billing.
  • Track cost per feature and per active user. See Monitoring AI.

Examples

Support chat

A small model for intent classification, a larger model only for complex answers, history summarisation and cached FAQ answers.

Summaries

A cache keyed by content hash and on-demand generation: the same article is never summarised twice.

Smart replies

On-device where possible, with zero per-request cost and instant responses.

Frequently asked questions

Does a lower temperature reduce cost?

No. Temperature affects randomness, not token count. Output length limits and concise instructions reduce cost.

Are images expensive?

They consume tokens depending on resolution and provider rules. Downscale images to what the task needs.

How do I estimate monthly cost?

Multiply requests per user Γ— users Γ— (input tokens Γ— input price + output tokens Γ— output price), using current provider pricing. See Choosing an AI Model for a Kotlin helper.

Conclusion

Tokens drive both cost and latency. Measure them, pick the smallest adequate model, trim history and context, cap outputs, cache, move suitable tasks on-device, stream for perceived speed, and enforce budgets and retries deliberately.

Next step: get better results from fewer tokens with Prompt Engineering for Android Developers.

Official references

πŸ“± Apps built by Yunok Tech

Real Android apps on Google Play, free to download.

See all our apps β†’

Ready to build real Android applications?

Every AI feature still runs inside an Android app that has to be fast, reliable and well structured. Strengthen the Kotlin, Jetpack Compose and architecture skills that AI integrations depend on, then apply these AI concepts with confidence.

Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.

Explore the Android course and take your next step as an Android developer.

Share: LinkedIn X / Twitter WhatsApp