<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Home on Chanzmao ʕ•ᴥ•ʔ Bear Blog</title>
		<link>https://chanzmao.benigumo.com/</link>
		<description>Recent content in Home on Chanzmao ʕ•ᴥ•ʔ Bear Blog</description>
		<generator>Hugo</generator>
		<language>en-US</language>
		
		
		
			<copyright>(c) 2026 chanzmao</copyright>
		
		
			<lastBuildDate>Tue, 28 Jul 2026 05:37:51 +0900</lastBuildDate>
		
			<atom:link href="https://chanzmao.benigumo.com/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>View and State Separation Is No Longer the Main Story in Jetpack Compose</title>
				<link>https://chanzmao.benigumo.com/view-and-state-separation-is-no-longer-the-main-story-in-jetpack-compose/</link>
				<pubDate>Tue, 28 Jul 2026 05:37:51 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/view-and-state-separation-is-no-longer-the-main-story-in-jetpack-compose/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-07-28.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;For years, Android developers learned the same architectural principle:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Separate the View from the State.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In the XML View system, this was essential.&lt;/p&gt;&#xA;&lt;p&gt;The View was mutable. Updating the UI meant calling methods like &lt;code&gt;setText()&lt;/code&gt;, &lt;code&gt;setVisibility()&lt;/code&gt;, or &lt;code&gt;notifyDataSetChanged()&lt;/code&gt;. As applications grew, mixing UI updates with business logic quickly became difficult to maintain.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;State&#xA;  |&#xA;ViewModel&#xA;  |&#xA;View (XML)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This architecture made sense because the View itself owned a large part of the UI state.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Navigation 3: Does ViewModel Still Need to Be a State Holder?</title>
				<link>https://chanzmao.benigumo.com/navigation-3-does-viewmodel-still-need-to-be-a-state-holder/</link>
				<pubDate>Sun, 26 Jul 2026 08:29:50 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/navigation-3-does-viewmodel-still-need-to-be-a-state-holder/</guid>
				<description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Compose and Navigation 3 are changing what ViewModel is responsible for.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-07-26.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;For years, Android developers followed one simple rule:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Put your screen state into a ViewModel.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;It wasn&amp;rsquo;t just a recommendation—it was one of the foundations of Android architecture.&lt;/p&gt;&#xA;&lt;p&gt;A ViewModel survived configuration changes, &lt;strong&gt;&lt;code&gt;SavedStateHandle&lt;/code&gt;&lt;/strong&gt; helped restore state after process death, and Activities and Fragments no longer needed to worry about holding screen state themselves.&lt;/p&gt;&#xA;&lt;p&gt;As a result, ViewModel naturally became the home for almost every piece of screen state.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Navigation 3 Navigation Graph Patterns</title>
				<link>https://chanzmao.benigumo.com/navigation-3-navigation-graph-patterns/</link>
				<pubDate>Fri, 24 Jul 2026 08:59:12 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/navigation-3-navigation-graph-patterns/</guid>
				<description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Extension Functions, Sealed NavKeys, and Nested NavDisplay&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-07-24.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Navigation 3 no longer uses nested navigation graphs like &lt;code&gt;navigation()&lt;/code&gt; in the old Navigation Component.&lt;/p&gt;&#xA;&lt;p&gt;Instead, you organize screens using one of these three patterns.&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-group-entries-with-extension-functions&#34;&gt;1. Group entries with extension functions&lt;/h2&gt;&#xA;&lt;p&gt;Split screen definitions by feature or module.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// AuthModule.kt&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;EntryProviderScope&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;lt;&lt;/span&gt;NavKey&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;gt;.&lt;/span&gt;authGraph&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entry&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;lt;&lt;/span&gt;Login&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt; LoginScreen&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entry&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;lt;&lt;/span&gt;SignUp&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt; SignUpScreen&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// AppNavigation.kt&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; entryProvider &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; entryProvider &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    authGraph&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entry&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;lt;&lt;/span&gt;Home&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt; HomeScreen&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NavDisplay&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    backStack &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; backStack&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryProvider &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; entryProvider&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This keeps navigation definitions modular while sharing a single NavBackStack.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Understanding dropUnlessResumed: Preventing Double Navigation in Navigation 3</title>
				<link>https://chanzmao.benigumo.com/understanding-dropunlessresumed-preventing-double-navigation-in-navigation-3/</link>
				<pubDate>Wed, 22 Jul 2026 12:39:48 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/understanding-dropunlessresumed-preventing-double-navigation-in-navigation-3/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-07-22.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;When using Navigation 3, navigating to another screen is as simple as updating the &lt;code&gt;NavBackStack&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For example:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Button&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    onClick &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        backStack&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;add&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;Detail&lt;span style=&#34;color:#1f2328&#34;&gt;())&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Text&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Detail&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This looks perfectly fine, but there&amp;rsquo;s a subtle problem.&lt;/p&gt;&#xA;&lt;p&gt;If the user taps the button twice in quick succession, &lt;code&gt;backStack.add()&lt;/code&gt; may be called twice before the current screen finishes transitioning. As a result, the same destination can be added to the back stack multiple times.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Navigation 3: High-Level vs. Low-Level NavDisplay APIs</title>
				<link>https://chanzmao.benigumo.com/navigation-3-high-level-vs.-low-level-navdisplay-apis/</link>
				<pubDate>Mon, 20 Jul 2026 00:26:57 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/navigation-3-high-level-vs.-low-level-navdisplay-apis/</guid>
				<description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;A practical comparison of NavDisplay(backStack) and NavDisplay(entries).&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-07-20.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-navdisplayentries-can-preserve-ui-state-across-multiple-navbackstacks&#34;&gt;Why &lt;code&gt;NavDisplay(entries)&lt;/code&gt; can preserve UI state across multiple NavBackStacks&lt;/h2&gt;&#xA;&lt;p&gt;Navigation 3 provides multiple ways to use &lt;code&gt;NavDisplay&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For a single back stack, this is usually enough:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NavDisplay&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    backStack &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; backStack&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryProvider &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; entryProvider &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;// ... &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But when each tab has its own &lt;code&gt;NavBackStack&lt;/code&gt;, the lower-level &lt;strong&gt;entries API&lt;/strong&gt; gives us more control.&lt;/p&gt;&#xA;&lt;h2 id=&#34;high-level-api-navdisplaybackstack&#34;&gt;High-Level API: &lt;code&gt;NavDisplay(backStack)&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; homeBackStack &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; rememberNavBackStack&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;Home&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; searchBackStack &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; rememberNavBackStack&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;Search&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; currentBackStack &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;currentTab&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;Tab&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;Home &lt;span style=&#34;color:#0550ae&#34;&gt;-&amp;gt;&lt;/span&gt; homeBackStack &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;Tab&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;Search &lt;span style=&#34;color:#0550ae&#34;&gt;-&amp;gt;&lt;/span&gt; searchBackStack&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NavDisplay&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    backStack &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; currentBackStack&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryProvider &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; entryProvider &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57606a&#34;&gt;// ... &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is simple and often all you need.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Stop Passing Everything Down the Compose Tree: 4 Ways to Eliminate Prop Drilling</title>
				<link>https://chanzmao.benigumo.com/stop-passing-everything-down-the-compose-tree-4-ways-to-eliminate-prop-drilling/</link>
				<pubDate>Fri, 10 Jul 2026 03:24:04 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/stop-passing-everything-down-the-compose-tree-4-ways-to-eliminate-prop-drilling/</guid>
				<description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;From Slot APIs to scoped ViewModels, here are four Compose patterns that keep deeply nested UI trees clean and maintainable.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-07-10.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Jetpack Compose encourages building UIs from small, reusable composables. As an application grows, however, those composables naturally become deeply nested.&lt;/p&gt;&#xA;&lt;p&gt;A common consequence is prop drilling: passing the same data or callbacks through multiple intermediate composables that don&amp;rsquo;t actually use them.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Parent&#xA;  ↓&#xA;Root&#xA;  ↓&#xA;Content&#xA;  ↓&#xA;Card&#xA;  ↓&#xA;UserName&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, Root, Content, and Card simply forward parameters to UserName. They don&amp;rsquo;t consume the data themselves—they merely act as relays.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Keep UI-Only Logic in the UI with snapshotFlow</title>
				<link>https://chanzmao.benigumo.com/keep-ui-only-logic-in-the-ui-with-snapshotflow/</link>
				<pubDate>Mon, 06 Jul 2026 22:33:31 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/keep-ui-only-logic-in-the-ui-with-snapshotflow/</guid>
				<description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Not every piece of UI state belongs in your ViewModel. Scroll position, selection, and other UI-only state can stay in the UI. snapshotFlow lets you react to those changes while keeping your architecture simple and idiomatic.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-07-06.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;When working with Jetpack Compose, it&amp;rsquo;s easy to fall into the habit of sending every state change to the ViewModel.&lt;/p&gt;&#xA;&lt;p&gt;For example:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Scroll position&lt;/li&gt;&#xA;&lt;li&gt;The currently visible item&lt;/li&gt;&#xA;&lt;li&gt;The selected tab&lt;/li&gt;&#xA;&lt;li&gt;TextField input&lt;/li&gt;&#xA;&lt;li&gt;Whether a FAB should be visible&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;But does your ViewModel really need to know about all of these?&lt;/p&gt;</description>
			</item>
			<item>
				<title>Stop Guessing When to Restore Scroll Position in Compose</title>
				<link>https://chanzmao.benigumo.com/stop-guessing-when-to-restore-scroll-position-in-compose/</link>
				<pubDate>Mon, 22 Jun 2026 21:54:12 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/stop-guessing-when-to-restore-scroll-position-in-compose/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-06-22-snapshotflow.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Restoring a scroll position in Jetpack Compose looks simple at first.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; gridState &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; rememberLazyStaggeredGridState&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    initialFirstVisibleItemIndex &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; savedIndex&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    initialFirstVisibleItemScrollOffset &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; savedOffset&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, this approach only works if the items have already been laid out. When your data is loaded asynchronously, the grid often starts with zero items, so the initial scroll position is ignored.&lt;/p&gt;&#xA;&lt;p&gt;Many developers try to solve this by calling &lt;code&gt;scrollToItem()&lt;/code&gt; inside a &lt;code&gt;LaunchedEffect&lt;/code&gt;, but there&amp;rsquo;s another problem:&lt;/p&gt;</description>
			</item>
			<item>
				<title>SavedStateHandle in the Navigation 3 Era</title>
				<link>https://chanzmao.benigumo.com/savedstatehandle-in-the-navigation-3-era/</link>
				<pubDate>Thu, 18 Jun 2026 08:30:04 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/savedstatehandle-in-the-navigation-3-era/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-06-08-nav3-era.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;With Navigation 3, the role of &lt;code&gt;SavedStateHandle&lt;/code&gt; has become much clearer.&lt;/p&gt;&#xA;&lt;p&gt;Use &lt;code&gt;NavKey&lt;/code&gt; for navigation and screen arguments.&lt;/p&gt;&#xA;&lt;p&gt;Use &lt;code&gt;ViewModel&lt;/code&gt; for normal UI state management.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;SavedStateHandle&lt;/code&gt; only for lightweight UI state that should survive process death.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;responsibilities&#34;&gt;Responsibilities&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NavKey&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; Navigation and screen arguments&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ViewModel&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; Regular UI state&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; Survives configuration changes&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SavedStateHandle&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; Lightweight state restored after process death&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A common mistake is putting everything into &lt;code&gt;SavedStateHandle&lt;/code&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>When Should You Use snapshotFlow in Jetpack Compose?</title>
				<link>https://chanzmao.benigumo.com/when-should-you-use-snapshotflow-in-jetpack-compose/</link>
				<pubDate>Mon, 15 Jun 2026 04:21:15 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/when-should-you-use-snapshotflow-in-jetpack-compose/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-06-15-snapshotflow.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Jetpack Compose provides several ways to react to state changes. Among them, &lt;code&gt;snapshotFlow&lt;/code&gt; is often misunderstood.&lt;/p&gt;&#xA;&lt;p&gt;Many developers either overuse it or never use it at all.&lt;/p&gt;&#xA;&lt;p&gt;The key idea is simple:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Use &lt;code&gt;snapshotFlow&lt;/code&gt; when you need to convert Compose state into a Kotlin Flow and perform side effects.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;If you&amp;rsquo;re only updating the UI, &lt;code&gt;snapshotFlow&lt;/code&gt; is usually the wrong tool.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-snapshotflow-actually-does&#34;&gt;What snapshotFlow Actually Does&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;snapshotFlow&lt;/code&gt; observes Compose state and emits new values as a Flow whenever that state changes.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Two Simple ADB Commands for Android State Restoration Testing</title>
				<link>https://chanzmao.benigumo.com/two-simple-adb-commands-for-android-state-restoration-testing/</link>
				<pubDate>Sat, 13 Jun 2026 09:09:36 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/two-simple-adb-commands-for-android-state-restoration-testing/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-06-13-script.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;When building Android apps, I frequently test two scenarios:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Configuration Changes&lt;/li&gt;&#xA;&lt;li&gt;Process Death&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Both affect UI state, but they exercise different parts of your app.&lt;/p&gt;&#xA;&lt;h2 id=&#34;testing-configuration-changes&#34;&gt;Testing Configuration Changes&lt;/h2&gt;&#xA;&lt;p&gt;A configuration change recreates the Activity while keeping the process alive. Typical examples include screen rotation, locale changes, and font scale changes.&lt;/p&gt;&#xA;&lt;p&gt;The following command rotates the device to landscape, then back to portrait:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# Disable auto-rotation so the device stays in a fixed orientation&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adb shell settings put system accelerometer_rotation &lt;span style=&#34;color:#0550ae&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# Rotate the device to landscape (Configuration Change occurs)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adb shell settings put system user_rotation &lt;span style=&#34;color:#0550ae&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# Wait for Activity recreation to complete&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sleep &lt;span style=&#34;color:#0550ae&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# Rotate the device back to portrait (another Configuration Change)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adb shell settings put system user_rotation &lt;span style=&#34;color:#0550ae&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;# Re-enable auto-rotation&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;adb shell settings put system accelerometer_rotation &lt;span style=&#34;color:#0550ae&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Expected behavior:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Kotlin Generic Type Declarations: Common Patterns and Examples</title>
				<link>https://chanzmao.benigumo.com/kotlin-generic-type-declarations-common-patterns-and-examples/</link>
				<pubDate>Wed, 10 Jun 2026 00:00:20 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/kotlin-generic-type-declarations-common-patterns-and-examples/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-06-10-generic.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Generics &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; allow you to write reusable, type-safe code without committing to a specific type upfront.&lt;/p&gt;&#xA;&lt;p&gt;They&amp;rsquo;re commonly used in collections, classes, functions, interfaces, and function types throughout Kotlin.&lt;/p&gt;&#xA;&lt;p&gt;This article walks through some of the most common generic type declaration patterns you&amp;rsquo;ll encounter in real-world Kotlin code.&lt;/p&gt;&#xA;&lt;h3 id=&#34;list&#34;&gt;List&lt;/h3&gt;&#xA;&lt;p&gt;Specify the type of elements stored in a list.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; names&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; List&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; listOf&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Bob&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Only &lt;code&gt;String&lt;/code&gt; values can be stored in this list.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Kotlin 2.4 Collection Literals and Type Inference</title>
				<link>https://chanzmao.benigumo.com/kotlin-2.4-collection-literals-and-type-inference/</link>
				<pubDate>Mon, 08 Jun 2026 10:46:24 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/kotlin-2.4-collection-literals-and-type-inference/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/2026-06-08.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Kotlin 2.4 introduces experimental support for collection literals, allowing collections to be created using square brackets.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Experimental&#xA;&lt;strong&gt;Support for collection literals&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Support for collection literals&#xA;Kotlin 2.4.0 introduces experimental support for collection literals. You can now create collections in a simpler and more concise way using brackets [].&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://kotlinlang.org/docs/whatsnew24.html#support-for-collection-literals&#34;&gt;https://kotlinlang.org/docs/whatsnew24.html#support-for-collection-literals&lt;/a&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-gradle&#34; data-lang=&#34;gradle&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kotlin &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    jvmToolchain&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    compilerOptions &lt;span style=&#34;color:#0550ae&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         freeCompilerArgs&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;-Xcollection-literals&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s compare the inferred types of several common collection APIs.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; names &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; mutableListOf&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Joe&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// MutableList&amp;lt;String&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; names &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; listOf&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Joe&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// List&amp;lt;String&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; names &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; listOf&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Joe&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;).&lt;/span&gt;toMutableList&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// MutableList&amp;lt;String&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; names &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; arrayOf&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Joe&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;Alice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// Array&amp;lt;String&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With collection literals enabled:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Who Owns Your ViewModel? Lifetime, Scope, and the Three Owners in Navigation 3</title>
				<link>https://chanzmao.benigumo.com/who-owns-your-viewmodel-lifetime-scope-and-the-three-owners-in-navigation-3/</link>
				<pubDate>Sat, 06 Jun 2026 13:00:34 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/who-owns-your-viewmodel-lifetime-scope-and-the-three-owners-in-navigation-3/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://chanzmao.benigumo.com/images/vm-owners.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Choosing a ViewModel scope is really asking one question: &lt;em&gt;when something dies, should the ViewModel die with it?&lt;/em&gt; Get that right and state flows naturally through your app. Get it wrong and you&amp;rsquo;re either losing state too early or holding onto it long after it&amp;rsquo;s useful.&lt;/p&gt;&#xA;&lt;p&gt;In Navigation 2, this was mostly handled for you. In Navigation 3, you&amp;rsquo;re in charge — and &lt;strong&gt;the defaults changed in a way that will surprise you&lt;/strong&gt; if you&amp;rsquo;re migrating from Navigation2.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Why Most Tech Blogs Die Fast</title>
				<link>https://chanzmao.benigumo.com/why-most-tech-blogs-die-fast/</link>
				<pubDate>Sat, 06 Jun 2026 00:41:26 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/why-most-tech-blogs-die-fast/</guid>
				<description>&lt;p&gt;Let’s be honest for a second: the shelf life of a technical blog post is brutally short.&lt;/p&gt;&#xA;&lt;p&gt;It’s an open secret in the dev community, but one we usually choose to ignore. Think about it. You spend an entire weekend fighting a bizarre configuration bug, finally figure it out, set up a flawless GitHub repo, and write up a beautiful step-by-step tutorial. Fast forward a year—sometimes just a few months—and that article is practically a ghost town, buried under a mountain of framework updates and new tools.&lt;/p&gt;</description>
			</item>
			<item>
				<title>A Cleaner Way to Pass Navigation Arguments in Navigation 3</title>
				<link>https://chanzmao.benigumo.com/a-cleaner-way-to-pass-navigation-arguments-in-navigation-3/</link>
				<pubDate>Fri, 05 Jun 2026 08:11:30 +0900</pubDate>
				<guid>https://chanzmao.benigumo.com/a-cleaner-way-to-pass-navigation-arguments-in-navigation-3/</guid>
				<description>&lt;p&gt;Recently I came across an interesting article about using &lt;strong&gt;Hilt Assisted Injection with Jetpack Navigation 3&lt;/strong&gt; instead of relying on &lt;code&gt;SavedStateHandle&lt;/code&gt; for passing navigation arguments to a &lt;code&gt;ViewModel&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The idea is simple: rather than having a &lt;code&gt;ViewModel&lt;/code&gt; read navigation arguments from &lt;code&gt;SavedStateHandle&lt;/code&gt;, pass the route object directly through Assisted Injection.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-traditional-approach&#34;&gt;The Traditional Approach&lt;/h2&gt;&#xA;&lt;p&gt;For a long time, many Android apps have used &lt;code&gt;SavedStateHandle&lt;/code&gt; to retrieve navigation arguments:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;DetailViewModel&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    savedStateHandle&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; SavedStateHandle&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; ViewModel&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#cf222e&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;val&lt;/span&gt; route &lt;span style=&#34;color:#1f2328&#34;&gt;=&lt;/span&gt; savedStateHandle&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;toRoute&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;lt;&lt;/span&gt;DetailRoute&lt;span style=&#34;color:#1f2328&#34;&gt;&amp;gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works well, but it also means the &lt;code&gt;ViewModel&lt;/code&gt; knows about navigation-specific APIs.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Markdown Syntax Guide</title>
				<link>https://chanzmao.benigumo.com/markdown-syntax-guide/</link>
				<pubDate>Fri, 03 Jan 2020 00:00:00 +0000</pubDate>
				<guid>https://chanzmao.benigumo.com/markdown-syntax-guide/</guid>
				<description>&lt;p&gt;For a quick cheatsheet, check out &lt;a href=&#34;https://simplemde.com/markdown-guide&#34;&gt;https://simplemde.com/markdown-guide&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;This article offers a sample of basic Markdown syntax that can be used in Hugo content files, also it shows whether basic HTML elements are decorated with CSS in a Hugo theme.&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
