<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: btejaswi91</title>
    <description>The latest articles on DEV Community by btejaswi91 (@btejaswi91).</description>
    <link>https://dev.to/btejaswi91</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F695332%2F1abce37c-6d7d-43c4-9467-f96eabc453f0.png</url>
      <title>DEV Community: btejaswi91</title>
      <link>https://dev.to/btejaswi91</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/btejaswi91"/>
    <language>en</language>
    <item>
      <title>Model View Intent arch in Jetpack Compose UI</title>
      <dc:creator>btejaswi91</dc:creator>
      <pubDate>Wed, 05 Mar 2025 17:36:45 +0000</pubDate>
      <link>https://dev.to/btejaswi91/model-view-intent-in-jetpack-compose-ui-k75</link>
      <guid>https://dev.to/btejaswi91/model-view-intent-in-jetpack-compose-ui-k75</guid>
      <description>&lt;p&gt;*&lt;em&gt;Why MVI Architecture *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are already MVC, MVP and MVVM for building mobile applications. &lt;/p&gt;

&lt;p&gt;Why MVI, what's new in that? Touted as better than MVI, but how? &lt;/p&gt;

&lt;p&gt;Here are a few things recommended about MVI presentational arch pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supports Unidirectional Data Flow&lt;/strong&gt;: As recommended by google. &lt;strong&gt;Immutability&lt;/strong&gt;: State, if immutable, helps in reducing bugs, when data is passed around. &lt;br&gt;
&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Clear separation between UI, state, and logic. &lt;br&gt;
Reactive UI: Works well with reactive programming (e.g., Kotlin Flow, RxJava). &lt;br&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Reducers(Pure functions) and clear state transitions make testing easier. &lt;br&gt;
&lt;strong&gt;Predictable State Management&lt;/strong&gt;:All updates are handled through the state, making the flow easy to debug. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to Use&lt;/strong&gt;:when Complex state management is required involving lot of data Apps with heavy user interaction &amp;amp; those with requiring real-time updates, more significantly when state change is predictable and error free as in case of financial applications.&lt;/p&gt;

&lt;p&gt;Ex: ecomm &amp;amp; social media apps including chat screens that frequently change data &amp;amp; needing predictable, error free state updates.&lt;/p&gt;

&lt;p&gt;Let's begin:&lt;br&gt;
MVI Architecture is a presentational architecture pattern(MVx) for building complex user interfaces. &lt;/p&gt;

&lt;p&gt;Key components involved:&lt;br&gt;
Essential: Intent, Model, State, ViewModel ,Action, Reducer&lt;br&gt;
(Simple implementations can use just these)&lt;/p&gt;

&lt;p&gt;Optional: Effect, and Middleware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4f2z6d9cioa59gkl2d5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4f2z6d9cioa59gkl2d5.png" alt="Image description" width="800" height="729"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feif6s2gt84vzobzhzua1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feif6s2gt84vzobzhzua1.png" alt="Image description" width="800" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example of middleware intercepting intents:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqq583e2fiarho4dopiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqq583e2fiarho4dopiu.png" alt="Image description" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, middleware is integrated into the BaseViewModel as an open function that can be overridden by subclasses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Middleware&lt;/strong&gt; can:&lt;/p&gt;

&lt;p&gt;Log intents for debugging or analytics.&lt;/p&gt;

&lt;p&gt;Validate or block intents based on conditions.&lt;/p&gt;

&lt;p&gt;Modify intents before they are processed.&lt;/p&gt;

&lt;p&gt;The processIntent function ensures that intents are passed through middleware before being handled.&lt;/p&gt;

&lt;p&gt;This approach makes the BaseViewModel highly flexible and reusable for various use cases.&lt;/p&gt;

&lt;p&gt;Let's get into the details:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzwx8z8escwrp6jyev9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzwx8z8escwrp6jyev9s.png" alt="Image description" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gyp4z1evm4u09d3b3wk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gyp4z1evm4u09d3b3wk.png" alt="Image description" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwlcna91rmm0eni4dlw1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flwlcna91rmm0eni4dlw1.png" alt="Image description" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s see how this works in a ChatViewModel that handles real-time updates and background tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevtledo3ghpfat7bsdx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevtledo3ghpfat7bsdx6.png" alt="Image description" width="800" height="847"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How Dispatchers Are Used in the Example&lt;br&gt;
connectToChat:&lt;/p&gt;

&lt;p&gt;Uses runOnBackground to simulate a network call on Dispatchers.IO.&lt;/p&gt;

&lt;p&gt;Updates the state and emits effects on the main thread using updateState and emitEffect.&lt;/p&gt;

&lt;p&gt;sendMessage:&lt;/p&gt;

&lt;p&gt;Simulates sending a message on Dispatchers.IO.&lt;/p&gt;

&lt;p&gt;Updates the state on the main thread.&lt;/p&gt;

&lt;p&gt;receiveMessage:&lt;/p&gt;

&lt;p&gt;Updates the state and emits effects on the main thread.&lt;/p&gt;

&lt;p&gt;Benefits of Using Dispatchers&lt;br&gt;
Responsive UI:&lt;/p&gt;

&lt;p&gt;Ensures that UI updates and side effects always happen on the main thread.&lt;/p&gt;

&lt;p&gt;Efficient Background Tasks:&lt;/p&gt;

&lt;p&gt;Offloads heavy operations (e.g., network calls) to background threads.&lt;/p&gt;

&lt;p&gt;Thread Safety:&lt;/p&gt;

&lt;p&gt;Prevents crashes or undefined behavior caused by updating the UI from a background thread.&lt;/p&gt;

&lt;p&gt;Few things to note wrt to why StateFlow is used to represent UI State and not SharedFlow and SharedFlow for Intent, Actions and Events and &lt;br&gt;
StateFlow for State&lt;br&gt;
Why?&lt;/p&gt;

&lt;p&gt;State represents the current UI state (e.g., loading, success, error).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;StateFlow is designed for state persistence&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;It holds the latest value and replays it to new collectors (e.g., the UI).&lt;/p&gt;

&lt;p&gt;Ensures the UI always has the latest state when it (re)subscribes (e.g., after rotation).&lt;/p&gt;

&lt;p&gt;Example: If the UI is in a "loading" state, new subscribers (like a recreated Activity) immediately see the loading state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frt4ykew9um13z9iho6bg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frt4ykew9um13z9iho6bg.png" alt="Image description" width="800" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SharedFlow for Events (Intents, Actions, Effects)&lt;br&gt;
Why?&lt;/p&gt;

&lt;p&gt;Intents, Actions, and Effects represent events (e.g., button clicks, navigation, toasts).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SharedFlow is designed for event streaming&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Events are ephemeral and should not be replayed to new collectors.&lt;/p&gt;

&lt;p&gt;Avoids duplicate processing (e.g., showing a toast twice after rotation).&lt;/p&gt;

&lt;p&gt;Example: A "Show Toast" effect should trigger only once, even if the UI resubscribes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc393hqfdmaeh8232x2gm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc393hqfdmaeh8232x2gm.png" alt="Image description" width="800" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnijgciumd24azvw9ixaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnijgciumd24azvw9ixaj.png" alt="Image description" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Differences&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zfrbnkuyl36pjuht35p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zfrbnkuyl36pjuht35p.png" alt="Image description" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Matters in MVI&lt;/strong&gt;&lt;br&gt;
StateFlow ensures the UI always reflects the latest state (e.g., after screen rotation).&lt;/p&gt;

&lt;p&gt;SharedFlow ensures events are processed exactly once (no duplicates).&lt;/p&gt;

&lt;p&gt;The main purpose of this article was to provide with the MVI framework implementation:&lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  For code that works, please check MainActivity.kt, DomainData.kt &amp;amp; app/build.gradle.kts files from my &lt;a href="https://github.com/btejaswi91/MyApplication" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;**&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
