On this page
A good summary saves time. A bad one misleads, which is worse than no summary. Summarization quality depends on three things: choosing the right model for the input length, structuring long inputs sensibly, and making it easy for users to check the source.
Choose the engine by input size and sensitivity
| Input | Engine | Why |
|---|---|---|
| Short, private text (notes, chats) in a supported language | ML Kit Summarization (Gemini Nano) | On-device, free per request, offline |
| Long documents (reports, PDFs) | Cloud Gemini (long context) | Large context windows, better reasoning |
| Very long or many documents | Chunk + map-reduce, or a backend pipeline | Bounded cost and latency per call |
On-device summarization
For short text, the ML Kit Summarization API is the simplest option. See the full lifecycle (status check, download, streaming) in Gemini Nano and ML Kit GenAI. Remember its documented constraints: input under roughly 4,000 tokens, a few supported languages, foreground-only use and supported devices.
Cloud summarization with a structured prompt
class CloudSummarizer {
private val model = Firebase.ai(backend = GenerativeBackend.googleAI()).generativeModel(
modelName = "gemini-3.8-flash", // check current model names
generationConfig = generationConfig { temperature = 0.2f; maxOutputTokens = 600 },
systemInstruction = content {
text(
"Summarize the provided document faithfully. Use only information in the document. " +
"If something is unclear, say so. Output 3-5 bullet points, then one line 'Action items:' if any."
)
},
)
fun summarizeStream(document: String): Flow<String> =
model.generateContentStream("<document>\n$document\n</document>").mapNotNull { it.text }
suspend fun summarize(text: String): String = model.generateContent("<document>\n$text\n</document>").text.orEmpty()
}Chunking long text (map-reduce)
class MapReduceSummarizer(private val summarizer: CloudSummarizer) {
/** Split at paragraph boundaries into chunks of at most [maxChars]. */
fun chunk(text: String, maxChars: Int = 12_000): List<String> {
val chunks = mutableListOf<String>()
val current = StringBuilder()
text.split("\n\n").forEach { paragraph ->
if (current.length + paragraph.length > maxChars && current.isNotEmpty()) {
chunks += current.toString(); current.clear()
}
current.append(paragraph).append("\n\n")
}
if (current.isNotBlank()) chunks += current.toString()
return chunks
}
suspend fun summarize(text: String): String = coroutineScope {
val parts = chunk(text)
if (parts.size == 1) return@coroutineScope summarizer.summarize(parts.single())
val partials = parts
.chunked(4) // limit parallelism (rate limits)
.flatMap { batch -> batch.map { async { summarizer.summarize(it) } }.awaitAll() }
summarizer.summarize(partials.joinToString("\n\n")) // reduce step
}
}Character counts are only a rough proxy for tokens. If you need exact limits, use the SDK's token-counting API. Very large paragraphs may also need splitting.
Streaming UI and trust
@Composable
fun SummaryPanel(summary: String, isStreaming: Boolean, onViewSource: () -> Unit) {
Card(Modifier.fillMaxWidth()) {
Column(Modifier.padding(16.dp)) {
Text("AI summary", style = MaterialTheme.typography.titleSmall)
Text(summary, Modifier.padding(vertical = 8.dp))
if (isStreaming) LinearProgressIndicator(Modifier.fillMaxWidth())
Text("Summaries can miss or misstate details.", style = MaterialTheme.typography.labelSmall)
TextButton(onClick = onViewSource) { Text("Read the full text") }
}
}
}Caching and cost
- Cache summaries keyed by a content hash plus prompt version, so the same document isn't summarized twice.
- Summarize on demand (button), not automatically for every item.
- Limit output length and choose a fast model tier for short inputs. See Tokens, Latency and Cost.
Use cases
Chat catch-up
"Summarise the last 200 messages" on-device for privacy, where supported.
Long reports
Cloud summarization with action items, streamed as it generates.
Reading list
Cached TL;DRs for saved articles, generated when the user taps "Summarise".
Accuracy pitfalls
- Summaries can omit critical caveats. Offer "read full text" and avoid summaries for legal or medical decisions.
- Models may add plausible but absent facts. Instruct "use only the document", keep temperature low, and evaluate with real samples.
- Map-reduce can lose cross-chunk context. Use overlap, or long-context models when possible.
Frequently asked questions
Can I summarize PDFs?
Extract text first (on-device PDF text extraction or a backend), or send the PDF to a multimodal cloud model that accepts documents. See AI Document Summarizer.
How do I support Hindi and other languages?
Check language support per engine. Cloud models generally support more languages than current on-device summarization.
Should I store summaries?
Caching improves cost and speed, but treat summaries as derived personal data, and delete them with the source.
Conclusion
Route summarization by length and sensitivity: on-device for short private text, cloud long-context models for big documents, and map-reduce when inputs exceed limits. Stream results, label them as AI-generated, link back to the source, and cache to control cost.
Next step: summarize images instead of text with Image Understanding and Description.
Official references
๐ฑ Apps built by Yunok Tech
Real Android apps on Google Play, free to download.
Walzi4K wallpapers for lock and home screenGet it โธ
NotiVaultNotification history: recover dismissed notificationsGet it โธ
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.