<?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: Ritwik Jamuar</title>
    <description>The latest articles on DEV Community by Ritwik Jamuar (@codewithjams).</description>
    <link>https://dev.to/codewithjams</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%2F1086969%2F18a9cefc-19d0-4d17-bc5b-1d411a0c575a.jpeg</url>
      <title>DEV Community: Ritwik Jamuar</title>
      <link>https://dev.to/codewithjams</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codewithjams"/>
    <language>en</language>
    <item>
      <title>Jetpack Compose + MVI - Part 2: Testing</title>
      <dc:creator>Ritwik Jamuar</dc:creator>
      <pubDate>Thu, 25 May 2023 12:30:00 +0000</pubDate>
      <link>https://dev.to/codewithjams/jetpack-compose-mvi-part-2-testing-376n</link>
      <guid>https://dev.to/codewithjams/jetpack-compose-mvi-part-2-testing-376n</guid>
      <description>&lt;p&gt;Previously, I had discussed how to handle any side effect that led us to discover what purpose a &lt;code&gt;MiddleWare&lt;/code&gt; and &lt;code&gt;Reducer&lt;/code&gt; should carry on.&lt;/p&gt;

&lt;p&gt;Now, it's time to do some testing of our code. But before we proceed, it's good to take an overview of code we've incorporated so far:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Unit Testing
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;MVI + Redux&lt;/strong&gt; Design Pattern, we can Unit Test following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Reducer&lt;/code&gt;: Test out the UI State Management.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MiddleWare&lt;/code&gt;: Test out the side-effects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reducer
&lt;/h3&gt;

&lt;p&gt;Testing &lt;code&gt;Reducer&lt;/code&gt; is straightforward: We assert that for a given current &lt;code&gt;State&lt;/code&gt; of UI and an &lt;code&gt;Action&lt;/code&gt; supplied, when reduced should churn out the &lt;code&gt;State&lt;/code&gt; we expect.&lt;/p&gt;

&lt;p&gt;Taking our below &lt;code&gt;Reducer&lt;/code&gt; into consideration:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;we add test cases like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Note that I'm just expecting a certain &lt;code&gt;State&lt;/code&gt; for my &lt;code&gt;Reducer&lt;/code&gt; to transform to.&lt;/p&gt;

&lt;h3&gt;
  
  
  MiddleWare
&lt;/h3&gt;

&lt;p&gt;Taking our &lt;code&gt;MiddleWare&lt;/code&gt; into consideration:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Testing &lt;code&gt;MiddleWare&lt;/code&gt; is tricky: The method &lt;code&gt;process()&lt;/code&gt; of &lt;code&gt;MiddleWare&lt;/code&gt; does not return anything.&lt;/p&gt;

&lt;p&gt;However, we can test what &lt;code&gt;Action&lt;/code&gt;s our &lt;code&gt;MiddleWare&lt;/code&gt; propagates back to &lt;code&gt;Store&lt;/code&gt;. This testing for action itself can be thought of as a side-effect.&lt;/p&gt;

&lt;p&gt;So, we create a general purpose &lt;code&gt;MiddleWare&lt;/code&gt; that captures &lt;code&gt;Action&lt;/code&gt; dispatched from &lt;code&gt;Store&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then, when creating test class for &lt;code&gt;MiddleWare&lt;/code&gt;, we inject the &lt;code&gt;Store&lt;/code&gt; manually with &lt;code&gt;ActionCaptureMiddleWare&lt;/code&gt; as one of the &lt;code&gt;MiddleWare&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Finally, we assert using &lt;code&gt;ActionCaptureMiddleWare&lt;/code&gt; to check if a certain &lt;code&gt;Action&lt;/code&gt; is captured or should not be captured &lt;code&gt;Action&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instrumentation Testing
&lt;/h2&gt;

&lt;p&gt;In this testing, the focus area is Views. Objective for testing UI is to test for a given Test Case, UI should behave as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI Test in Jetpack Compose
&lt;/h3&gt;

&lt;p&gt;Jetpack Compose testing libraries allows us to Test an individual &lt;code&gt;@Composable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Library in highlight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;androidTestImplementation&lt;/span&gt; &lt;span class="nf"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'androidx.compose:compose-bom:2023.05.01'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;androidTestImplementation&lt;/span&gt; &lt;span class="s1"&gt;'androidx.compose.ui:ui-test-junit4'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All views in Jetpack Compose are represented as their View Tree. Beside view, there exists a &lt;a href="https://developer.android.com/jetpack/compose/semantics"&gt;Semantic Tree&lt;/a&gt; in parallel with View Tree. This Semantic Tree is useful in Android Framework as it is used by Accessibility Services and Testing frameworks.&lt;/p&gt;

&lt;p&gt;Here, each node in this Semantic Tree is a semantic image of same view from View Tree and is represented by &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteraction"&gt;&lt;code&gt;SemanticsNodeInteraction&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;SemanticsNodeInteraction&lt;/code&gt; is accessible from &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/test/junit4/ComposeContentTestRule"&gt;&lt;code&gt;ComposeContentTestRule&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you see from it's documentation, ComposeContentTestRule implements &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider"&gt;&lt;code&gt;SemanticsNodeInteractionsProvider&lt;/code&gt;&lt;/a&gt; which contains method that provides the &lt;code&gt;SemanticsNodeInteraction&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, to get hold of a particular &lt;code&gt;SemanticsNodeInteraction&lt;/code&gt;, we must provide a &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsMatcher"&gt;&lt;code&gt;SemanticMatcher&lt;/code&gt;&lt;/a&gt; to the method &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/test/SemanticsNodeInteractionsProvider#onNode(androidx.compose.ui.test.SemanticsMatcher,kotlin.Boolean)"&gt;&lt;code&gt;onNode()&lt;/code&gt;&lt;/a&gt; of &lt;code&gt;ComposeContentTestRule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Upon getting hold of a &lt;code&gt;SemanticsNodeInteraction&lt;/code&gt;, then we can perform assertions on it. One example of assertion in &lt;code&gt;SemanticsNodeInteraction&lt;/code&gt; is whether the view is actually shown in the UI or not, or if view is clickable, and such.&lt;/p&gt;

&lt;p&gt;Here's the Cheat-Sheet for combining &lt;code&gt;SemanticMatcher&lt;/code&gt;s and Finder methods:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vrbUgFc9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/images/jetpack/compose/compose-testing-cheatsheet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vrbUgFc9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.android.com/images/jetpack/compose/compose-testing-cheatsheet.png" alt="Compose Testing Cheat-Sheet" width="800" height="1132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, before start performing testing, we have to populate the &lt;code&gt;@Composable&lt;/code&gt; under &lt;code&gt;setContent()&lt;/code&gt; method of &lt;code&gt;ComposeContentTestRule&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  UI Test in Action
&lt;/h3&gt;

&lt;p&gt;Before we start our test, fetching the UI element should be figured out, remember, &lt;code&gt;@Composable&lt;/code&gt; does not use &lt;code&gt;id&lt;/code&gt; like XMLs do.&lt;/p&gt;

&lt;p&gt;One way is to use &lt;code&gt;hasText(text = ?) : SemanticsMatcher&lt;/code&gt; which provides all &lt;code&gt;SemanticsNodeInteraction&lt;/code&gt; that matches our supplied text.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

        &lt;span class="nf"&gt;onNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hasText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TEXT_TO_FIND"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="c1"&gt;// Perform assertions&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This works, but is not reliable and can prove cumbersome especially if the supplied text is displayed over more than one &lt;code&gt;@Composable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A better approach I find useful is to use &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier#%28androidx.compose.ui.Modifier%29.testTag%28kotlin.String%29"&gt;&lt;code&gt;testTag&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;testTag&lt;/code&gt; is one of the attributes of &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier#%28androidx.compose.ui.Modifier"&gt;&lt;code&gt;Modifier&lt;/code&gt;&lt;/a&gt;. It means, &lt;code&gt;testTag&lt;/code&gt; can be added to almost any &lt;code&gt;@Composable&lt;/code&gt;, especially the ones we want to test on.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

        &lt;span class="nf"&gt;onNodeWithTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testTag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SOME_TEST_TAG"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="c1"&gt;// Perform assertions&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So, refactored the Screen to use &lt;code&gt;testTag&lt;/code&gt; like below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now, before implementing the test, here's the formula for performing test on any composable, which makes use of &lt;code&gt;ComposeContentTestRule&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;STEP 1: Show the Composable UI under the method &lt;code&gt;setContent&lt;/code&gt; of &lt;code&gt;ComposeContentTestRule&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeUITest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Rule&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComposeContentTestRule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createComposeRule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;SomeScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;STEP 2: Using &lt;code&gt;ComposeContentTestRule&lt;/code&gt;, get hold of any &lt;code&gt;SemanticsNodeInteraction&lt;/code&gt; using &lt;code&gt;testTag&lt;/code&gt; to perform assertions on it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeUITest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Rule&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComposeContentTestRule&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createComposeRule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="c1"&gt;// Perform assertions here&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;ComposeContentTestRule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;SemanticsNodeInteraction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nf"&gt;onNodeWithTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testTag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SOME_EXAMPLE_TAG"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With above steps in mind, this is how Test Class for &lt;code&gt;ExampleScreen&lt;/code&gt; is implemented:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Notice that I have created another Composable TestScreen. This is done because our &lt;code&gt;ExampleScreen&lt;/code&gt; is implemented best when coupled with &lt;code&gt;ExampleViewModel&lt;/code&gt;. And when we use &lt;code&gt;MVIViewModel&lt;/code&gt;, we get &lt;code&gt;viewState&lt;/code&gt;, which get &lt;code&gt;collectAsState()&lt;/code&gt;. So anytime &lt;code&gt;ExampleReducer&lt;/code&gt; changes the &lt;code&gt;ExampleState&lt;/code&gt;, &lt;code&gt;ExampleScreen&lt;/code&gt; is going to be recomposed. So wrapped &lt;code&gt;ExampleScreen&lt;/code&gt; in another Composable to avoid recomposition and retain the same instance of &lt;code&gt;MVIViewModel&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;MVI + Redux&lt;/strong&gt;, Unit Testing the logical components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Reducer&lt;/code&gt; can be tested for their role in changing the &lt;code&gt;State&lt;/code&gt; of UI.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MiddleWare&lt;/code&gt; can be tested for their propagation of &lt;code&gt;Action&lt;/code&gt; to &lt;code&gt;Store&lt;/code&gt;, giving a view on what are they supposed to propagate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With &lt;strong&gt;Jetpack Compose UI Testing&lt;/strong&gt;, any &lt;code&gt;@Composable&lt;/code&gt; can be tested for correctness, leading to a more bug-free UIs.&lt;/p&gt;

&lt;p&gt;With this, I conclude the series.&lt;/p&gt;

&lt;p&gt;Here's link to my implementation of all Tutorials:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ritwikjamuar"&gt;
        ritwikjamuar
      &lt;/a&gt; / &lt;a href="https://github.com/ritwikjamuar/ComposeSample"&gt;
        ComposeSample
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Experimentation of screens with Jetpack Compose.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Compose Sample&lt;/h1&gt;
&lt;p&gt;Experimentation of screens with Jetpack Compose.&lt;/p&gt;
&lt;h2&gt;
Description&lt;/h2&gt;
&lt;p&gt;This project contains some very basic UI screens (Login for example with just barebones). While UI may be simplistic, most detail to attention has been paid on Design Pattern and Testing (Both Unit &amp;amp; Instrumentation)
This project is also my first exposure to &lt;a href="https://developer.android.com/jetpack/compose/documentation" rel="nofollow"&gt;Jetpack Compose&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
Chapters&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ritwikjamuar/ComposeSampledocumentation/CHAPTER01.md"&gt;Chapter 1: Tour de Design Pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ritwikjamuar/ComposeSampledocumentation/CHAPTER02.md"&gt;Chapter 2: Testing Tentacles&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ritwikjamuar/ComposeSampledocumentation/CHAPTER0201.md"&gt;Chapter 2.1: Unit Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ritwikjamuar/ComposeSampledocumentation/CHAPTER0202.md"&gt;Chapter 2.2: Instrumentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
License&lt;/h2&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;MIT License
Copyright (c) 2023 Ritwik Jamuar

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ritwikjamuar/ComposeSample"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Thank You!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Jetpack Compose + MVI - Part 1: Side Effects</title>
      <dc:creator>Ritwik Jamuar</dc:creator>
      <pubDate>Wed, 24 May 2023 12:30:00 +0000</pubDate>
      <link>https://dev.to/codewithjams/jetpack-compose-mvi-part-1-side-effects-12k5</link>
      <guid>https://dev.to/codewithjams/jetpack-compose-mvi-part-1-side-effects-12k5</guid>
      <description>&lt;p&gt;Previously, I had introduced the mechanics of a &lt;strong&gt;MVI + Redux&lt;/strong&gt; Design Pattern and implemented it as an example.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/the4sjvlkqtllfl328u0.gif" rel="noopener noreferrer"&gt;
      dev-to-uploads.s3.amazonaws.com
    &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;The UI is DaVinci-esque ¬‿¬ but has one problem: &lt;strong&gt;Button does nothing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We would make the click of Button to emulate a REST API Response. This would mean that UI should show progress or some indicator that operation is ongoing.&lt;/p&gt;

&lt;p&gt;To emulate a REST API Call, we need a Repository:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;fetchSomething()&lt;/code&gt; provides a &lt;code&gt;Boolean&lt;/code&gt; flag that indicates whether fetching was success or not.&lt;/p&gt;

&lt;p&gt;Now, since performing REST API Call is considered side-effect, we create a &lt;code&gt;MiddleWare&lt;/code&gt; to handle such side-effect, and here comes &lt;code&gt;ExampleMiddleWare&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter &lt;code&gt;MiddleWare&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To recap, the purpose of &lt;code&gt;MiddleWare&lt;/code&gt; is to handle side-effects (or &lt;code&gt;Action&lt;/code&gt; that does not make sense to a &lt;code&gt;Reducer&lt;/code&gt;). MiddleWare uses store to propagate another Action, whose processing is upto &lt;code&gt;Reducer&lt;/code&gt; or another &lt;code&gt;MiddleWare&lt;/code&gt; in the &lt;code&gt;Store&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But before we start shaping the &lt;code&gt;MiddleWare&lt;/code&gt; for our example, we must add actions that triggers the execution of this &lt;code&gt;MiddleWare&lt;/code&gt; and prompts to change the state once the MiddleWare is finished. &lt;/p&gt;

&lt;p&gt;This means adding some actions in already existing &lt;code&gt;ExampleAction&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, we implement our &lt;code&gt;MiddleWare&lt;/code&gt; as below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Take a look at the method &lt;code&gt;onButtonClicked()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Whenever we receive an intent that Button is clicked, we perform REST API Call.&lt;/p&gt;

&lt;p&gt;To make user aware of such, we propagate an action to Show Loading, and when the value is collected, we propagate an action to Hide Loading.&lt;/p&gt;

&lt;p&gt;In order for our &lt;code&gt;MiddleWare&lt;/code&gt; to work, we must incorporate it to &lt;code&gt;Store&lt;/code&gt; in the MVIViewModel:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Because we wish to update our UI whenever Showing or Hiding progress is propagated, we add a field in our &lt;code&gt;State&lt;/code&gt; to support that.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next, we update our &lt;code&gt;Reducer&lt;/code&gt; to accommodate for new &lt;code&gt;Action&lt;/code&gt;s, i.e. showing and hiding Progress&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Back to UI
&lt;/h2&gt;

&lt;p&gt;So, we add a Progress Bar to our screen using &lt;a href="https://developer.android.com/reference/com/google/android/material/progressindicator/LinearProgressIndicator"&gt;&lt;code&gt;LinearProgressIndicator&lt;/code&gt;&lt;/a&gt;. To add some animating effect, wrapped the &lt;code&gt;LinearProgressIndicator&lt;/code&gt; under &lt;a href="https://developer.android.com/jetpack/compose/animation/composables-modifiers#animatedvisibility"&gt;&lt;code&gt;AnimatedVisibility&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This results in our UI to look like this:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qf7fstn1op1s54l6ymqs.gif" rel="noopener noreferrer"&gt;
      dev-to-uploads.s3.amazonaws.com
    &lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Side-Effects revisited
&lt;/h2&gt;

&lt;p&gt;Above is one demonstration of handling REST API Call as side-effect.&lt;/p&gt;

&lt;p&gt;But remember, &lt;strong&gt;&lt;code&gt;MiddleWare&lt;/code&gt; does not have to propagate any action&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here are some examples that does not propagate anything:&lt;/p&gt;

&lt;h4&gt;
  
  
  1 : Logging
&lt;/h4&gt;

&lt;p&gt;We want to log our Action and State of our Store for logging and debugging purposes. Logging is again another use case of side-effect, which then translates to &lt;code&gt;MiddleWare&lt;/code&gt; as below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This &lt;code&gt;MiddleWare&lt;/code&gt; is general-purpose in nature and can be used with any &lt;code&gt;Store&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2 : Navigation
&lt;/h4&gt;

&lt;p&gt;Navigating to another &lt;code&gt;Activity&lt;/code&gt;/&lt;code&gt;Fragment&lt;/code&gt; can also be thought of as a side-effect, which can be translated to a &lt;code&gt;MiddleWare&lt;/code&gt; as below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The lambda &lt;code&gt;onNavigate&lt;/code&gt; is handled by consumer for them to figure out on what action and state they perform navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;The point is, &lt;strong&gt;&lt;code&gt;MiddleWare&lt;/code&gt; can be thought of as a silo that is designed for a singular or a set of purpose&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Meanwhile &lt;code&gt;Reducer&lt;/code&gt; has one role and one role only: &lt;strong&gt;For a given &lt;code&gt;Action&lt;/code&gt; that is considered state changing, &lt;code&gt;Reducer&lt;/code&gt; reduces current &lt;code&gt;State&lt;/code&gt; to a new one&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next post, will be a discussion around Testing.&lt;/p&gt;

&lt;p&gt;Thank You!&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Jetpack Compose + MVI - Part 0 : Introduction</title>
      <dc:creator>Ritwik Jamuar</dc:creator>
      <pubDate>Tue, 23 May 2023 05:36:59 +0000</pubDate>
      <link>https://dev.to/codewithjams/jetpack-compose-mvi-part-0-introduction-knk</link>
      <guid>https://dev.to/codewithjams/jetpack-compose-mvi-part-0-introduction-knk</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I have been living under rock for some time since the Jetpack Compose has been out in release in July 2021. I have sticked myself to XMLs and View/Data Bindings. Under same time, I started exploring &lt;a href="https://medium.com/swlh/mvi-architecture-with-android-fcde123e3c4a"&gt;MVI&lt;/a&gt; Design Pattern and find it fascinating as it has clear state management of UI.&lt;/p&gt;

&lt;p&gt;Fast forward present day, I finally got the zest to try out Jetpack Compose and ride aboard the hype-train.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Let's start with an example:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Resulting the UI to be rendered like this:&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZXGtrEsp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/stmae9xrqyda80fd31qz.png" class="article-body-image-wrapper"&gt;&lt;img alt="Light" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZXGtrEsp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/stmae9xrqyda80fd31qz.png" width="800" height="1733"&gt;&lt;/a&gt;
       
  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yeE2jqy9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hy1huo2hz4ssy7ag178.png" class="article-body-image-wrapper"&gt;&lt;img alt="Dark" src="https://res.cloudinary.com/practicaldev/image/fetch/s--yeE2jqy9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hy1huo2hz4ssy7ag178.png" width="800" height="1733"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;I know, DaVinci would rip his Mona Lisa off for my design ¬‿¬&lt;br&gt;
Anyway...&lt;/p&gt;


&lt;h2&gt;
  
  
  Tour de Design Pattern
&lt;/h2&gt;

&lt;p&gt;I came across a great implementation of MVI Design Pattern coupled with &lt;a href="https://redux.js.org/tutorials/essentials/part-1-overview-concepts"&gt;Redux&lt;/a&gt; by &lt;a href="https://twitter.com/AdamMc331"&gt;Adam McNeilly&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AdamMc331"&gt;
        AdamMc331
      &lt;/a&gt; / &lt;a href="https://github.com/AdamMc331/MVIExample"&gt;
        MVIExample
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A sample app showing how to build an app using the MVI architecture pattern. 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
MVI Example&lt;/h1&gt;
&lt;p&gt;This application was streamed live on Twitch to demonstrate how to build an application using MVI.&lt;/p&gt;
&lt;p&gt;You can find the VOD here for now: &lt;a href="https://www.twitch.tv/videos/1036306656" rel="nofollow"&gt;https://www.twitch.tv/videos/1036306656&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And on YouTube: &lt;a href="https://www.youtube.com/watch?v=wTJX_lWdh60" rel="nofollow"&gt;https://www.youtube.com/watch?v=wTJX_lWdh60&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Much of the codebase is documented, but you can expect a blog post coming soon as well.&lt;/p&gt;
&lt;h2&gt;
MVI Diagram&lt;/h2&gt;
&lt;p&gt;During the stream we created a diagram to understand the flow of data in an MVI application, which you can find here. This may be helpful to review before looking into the codebase:&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/AdamMc331/MVIExampleassets/MVIDiagram.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q71y1Ddr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/AdamMc331/MVIExampleassets/MVIDiagram.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/AdamMc331/MVIExample"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;To summarise the content of Repository, here are the core concepts:&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;State&lt;/code&gt; is a representation of UI.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;An &lt;code&gt;Action&lt;/code&gt; is an intent taken by User from the UI.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A &lt;code&gt;Reducer&lt;/code&gt; takes an &lt;code&gt;Action&lt;/code&gt; and transform the current &lt;code&gt;State&lt;/code&gt; to a new &lt;code&gt;State&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;While &lt;code&gt;Reducer&lt;/code&gt; is great at handling the state of UI, it is useless when concerned with executing some non-&lt;code&gt;State&lt;/code&gt; operations (Performing REST API Call, Logging, Navigate to another Activity/Fragment for examples). These kind of operations can be thought of as a side-effect. And, to handle side-effects, we create an abstraction called &lt;code&gt;MiddleWare&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we encounter an unknown entity called &lt;code&gt;Store&lt;/code&gt;. Don't you worry, it is what orchestrates the above components involved. To orchestrate the components, Store can leverage Kotlin Coroutines, more precisely StateFlow that can help achieve collecting the state without depending on AndroidX LiveData. Below is the implementation to showcase such:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Well, &lt;code&gt;dispatch()&lt;/code&gt; is what triggers every component to receive some &lt;code&gt;Action&lt;/code&gt; and perform respective executions.&lt;/p&gt;

&lt;p&gt;There's a reason &lt;code&gt;dispatch()&lt;/code&gt; chosen to be &lt;code&gt;suspend&lt;/code&gt;ing. You see, there can be myriad of side-effects that are blocking in nature, so it makes sense that &lt;code&gt;MiddleWare&lt;/code&gt;s can perform blocking operations out-of-the-box.&lt;/p&gt;

&lt;p&gt;Lastly, since &lt;code&gt;Store&lt;/code&gt;'s method &lt;code&gt;dispatch()&lt;/code&gt; is a &lt;code&gt;suspend&lt;/code&gt;ing method, it means this method must be executed from a &lt;code&gt;CoroutineContext&lt;/code&gt;. There are two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Activity&lt;/code&gt;: &lt;code&gt;Activity&lt;/code&gt; consists of &lt;code&gt;lifecycleScope&lt;/code&gt;. But Activity is prone to be destroyed in the event of a configuration change or low memory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ViewModel&lt;/code&gt;: &lt;code&gt;ViewModel&lt;/code&gt; consists of &lt;code&gt;viewModelScope&lt;/code&gt;. Since &lt;code&gt;ViewModel&lt;/code&gt; at least survives the configuration change, it becomes ideal candidate to host the &lt;code&gt;Store&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, much of the code for ViewModel can be repetitive for every implementation with Store, so we can simplify this by creating an abstraction:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;By default, &lt;code&gt;dispatchActionToStore()&lt;/code&gt; will always execute the blocking operations in Main (read UI) Thread. If there's a need that a blocking operation be operated under a certain thread (say IO for REST API Calls, Computation for general purpose processing and such), pass the value of dispatcher as well.&lt;/p&gt;



&lt;h2&gt;
  
  
  Example Implementation in Action
&lt;/h2&gt;



&lt;p&gt;Since our &lt;code&gt;ExampleScreen&lt;/code&gt; only shows one text, so we added this attribute like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Our &lt;code&gt;ExampleScreen&lt;/code&gt; has two intent from User: Change the Input Text and Handle click of Button.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;ExampleReducer&lt;/code&gt; changes the &lt;code&gt;ExampleState&lt;/code&gt; based on the dispatched &lt;code&gt;ExampleAction&lt;/code&gt; from &lt;code&gt;Store&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;ExampleViewModel&lt;/code&gt; receives events from UI which are then transformed to &lt;code&gt;ExampleAction&lt;/code&gt; for dispatching this &lt;code&gt;Action&lt;/code&gt; to &lt;code&gt;Store&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;ExampleActivity&lt;/code&gt; hosts our &lt;code&gt;@Composable ExampleState&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You may ask where is &lt;code&gt;ExampleMiddleWare.kt&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Since the button is not doing anything at the moment (as evident from the &lt;code&gt;ExampleReducer.kt&lt;/code&gt;) and there's no UI to showcase such side-effect, it's parked for now.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next part.&lt;/p&gt;

&lt;p&gt;Thank You!&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
