<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Suleyman Fatih Giris on Medium]]></title>
        <description><![CDATA[Stories by Suleyman Fatih Giris on Medium]]></description>
        <link>https://medium.com/@girisfth?source=rss-cacdfbac1fb3------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*8FWqOWr__h21wK6BHnST_g.jpeg</url>
            <title>Stories by Suleyman Fatih Giris on Medium</title>
            <link>https://medium.com/@girisfth?source=rss-cacdfbac1fb3------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 18 May 2026 11:46:22 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@girisfth/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Theming basics in Android]]></title>
            <link>https://proandroiddev.com/theming-basics-in-android-13c57bc20605?source=rss-cacdfbac1fb3------2</link>
            <guid isPermaLink="false">https://medium.com/p/13c57bc20605</guid>
            <category><![CDATA[android-theme]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[android-styles]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Suleyman Fatih Giris]]></dc:creator>
            <pubDate>Fri, 07 May 2021 21:41:56 GMT</pubDate>
            <atom:updated>2021-05-08T09:25:19.573Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*sI0ZlINE5b4o01pg" /><figcaption>Photo by <a href="https://unsplash.com/@steve_j?utm_source=medium&amp;utm_medium=referral">Steve Johnson</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Theming the app could be one of the most confusing topics in Android development. It is getting harder to maintain the styles of your components and theming of your app while the project is getting bigger. If you don’t have a good design system, you might have inconsistent designs and colors in the app. Having a good understanding of styling &amp; theming will help you create UIs consistent across the app. Also if you are thinking about migrating to Compose, a poor design system might create more complexity.</p><p>Having a good design system requires to have a proper styling &amp; theming setup. This helps us to have consistent and reusable styles for our components. But how do we actually have a proper styling &amp; theming setup?</p><p>Well, this question does not have only one answer but it can be divided into 5 pieces.</p><ul><li>Attributes</li><li>Default style</li><li>Style vs Theme</li><li>Theme overlay</li><li>TextAppearance</li></ul><h4>Attributes</h4><p>Everything starts with an attribute. Without attributes, nothing in XML would have any characteristic that we can define. <em>Attributes</em> are named values that have their definition in attrs.xml file. An attribute can be defined for a view as well as a theme. For instance, android:layout_width attribute is a view attribute whereas colorPrimary is a theme attribute.</p><p>A view attribute is set in the view’s XML either by setting directly on the view tag or indirectly by using style(will be mentioned later). Let’s look at how we can set the background of a button to red with android:backgroundTint view attribute.</p><blockquote>Note: In order to access the built-in attributes, android prefix is used.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/93a928f0daebe48af8afe33585f4bab4/href">https://medium.com/media/93a928f0daebe48af8afe33585f4bab4/href</a></iframe><p>Let’s say you want to change its background to white. You can do this by setting the android:backgroundTint attribute to white.</p><p>This is fine if you will only change a single button. But what about if you would like to change all the red buttons to white? It can be achieved by:</p><ul><li>Using a theme attribute for android:backgroundTint</li><li>Creating and applying a style to all buttons</li></ul><blockquote>A <strong>theme attribute</strong> is an attribute that does not belong to any view and can be changed at the theme level.</blockquote><p>In order to use a theme attribute for android:backgroundTint, let&#39;s first define a custom theme attribute called myButtonBackground in attrs.xml.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/46b28d4e66db531d54173b8b0505463b/href">https://medium.com/media/46b28d4e66db531d54173b8b0505463b/href</a></iframe><p>An attribute’s type is set with format field. The format can be given as a single type or multiple, for example with android:background format=&quot;reference|color&quot; which accepts both references to a drawable resource (“reference”) and color (“color”).</p><p>You can now use myButtonBackground attribute to set your button&#39;s background. But before that, you need to set a value to myButtonBackground. It must be defined either in the theme or the theme overlay that’s going to be used.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2fef62f29c8736ba9e3cbb370c79fb0a/href">https://medium.com/media/2fef62f29c8736ba9e3cbb370c79fb0a/href</a></iframe><p>Then you can use this attribute to set the background of your buttons.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0355527e2e7a49f1ad4c535c7f2a0420/href">https://medium.com/media/0355527e2e7a49f1ad4c535c7f2a0420/href</a></iframe><p>If you change the attribute value, then the background of all buttons using ?attr/myButtonBackground attribute as its background will change. Alternatively, you can use ?myButtonBackground as a short hand instead of ?attr/myButtonBackground.</p><p>But setting android:backgroundTint to myButtonBackground for all buttons might be overwhelming. In order to overcome this, we will be creating a style and applying it to all buttons using a default style.</p><h4>Default style</h4><p>Have you ever noticed that even if you don&#39;t give any background to the button, you get a background drawable? This is because the Button component has a default style as any other view. A <em>default style</em> is a style that is used as a view’s base style.</p><p>Let&#39;s check the button&#39;s default style.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1551f48807393fe5c4bc29515f5243b6/href">https://medium.com/media/1551f48807393fe5c4bc29515f5243b6/href</a></iframe><p>Button’s default style is set through R.attr.buttonStyle theme attribute. So it means that you can change the default style of all buttons in your app with this attribute.</p><p>Let’s change the default style of the button in our theme so that the background will be red.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8d01fbc83aa390feddd1bd557cf11c85/href">https://medium.com/media/8d01fbc83aa390feddd1bd557cf11c85/href</a></iframe><p>Then whenever you create a button, you will get this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/238/1*uawNQkQmjaxpeDEFr4uSLg.png" /><figcaption>A button with a red background</figcaption></figure><p>Isn’t this more like a text with a red background? This is because MyButton style does not inherit from any styles. For this reason, all buttons will only contain the background attribute in their default style. Let’s check how the default button style looks like in AppCompat.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9a942cefd5f24a28b8a6437ae80cf869/href">https://medium.com/media/9a942cefd5f24a28b8a6437ae80cf869/href</a></iframe><p>As you can see, these attributes are the base style for the button. Let’s give Widget.AppCompat.Button as a parent to the MyButton style and change the background attribute with backgroundTint since we only want to change the color not the drawable.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d4760ee43462c2f59434ae39b5f3c2fd/href">https://medium.com/media/d4760ee43462c2f59434ae39b5f3c2fd/href</a></iframe><p>Then we get a button with a red background 🎉.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/323/1*3th4_jnOK7WZDJh3lSbVWA.png" /><figcaption>A button with a red background tint</figcaption></figure><h4>Style vs Theme</h4><p>We have mentioned both style and theme but what is the difference between them? Both <a href="https://developer.android.com/guide/topics/ui/look-and-feel/themes">style and theme are set of attributes</a> but the difference is what they apply to. Styles are meant to be applied to views and themes to an activity or entire app. Because of this reason, a style should only contain view attributes and a theme should only contain theme attributes.</p><p>You can change the style of a view in 3 ways:</p><ul><li>Changing the view attribute on the layout file</li><li>Creating a new style and applying it with views style attribute on the layout file</li><li>Specifying a default style</li></ul><p>Let’s see how we can change the background of a button in the layout file.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fdd013b8835ba1a1f26649b83b10fb7f/href">https://medium.com/media/fdd013b8835ba1a1f26649b83b10fb7f/href</a></iframe><p>Now let’s check how we can create a style and apply it to this button.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8313c610b32f3a82a5b7f5c34bb46cf7/href">https://medium.com/media/8313c610b32f3a82a5b7f5c34bb46cf7/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/41d9c23b86e22e30fea3abb2eecb3899/href">https://medium.com/media/41d9c23b86e22e30fea3abb2eecb3899/href</a></iframe><p>Applying a style only takes the <em>view attributes</em> into an account. If you try to set any <em>theme attribute</em> inside MyButton style, it will not work. In order to give an example, we will:</p><ul><li>Use colorPrimary theme attribute inside background drawable of the button</li><li>Change the value of colorPrimary inside the MyButton style</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/35233ec8b6e3a4e232414d8001fe754c/href">https://medium.com/media/35233ec8b6e3a4e232414d8001fe754c/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/86cdc394e113d4f03abadac53f08c7a7/href">https://medium.com/media/86cdc394e113d4f03abadac53f08c7a7/href</a></iframe><p>Then even though we set the primary color as red, we get a button with a purple background.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/337/1*HZSziRtm7Bg6-sxwRAGG1w.png" /><figcaption>Button with a purple background</figcaption></figure><p>This is because a view only knows about its own attributes; Button isn’t aware of the colorPrimary attribute so it’s ignored.</p><p>A view gets the view attributes from the layout file or the style attribute. If a view style includes a theme attribute, it will be ignored.</p><p>Then, how do we actually change the theme attributes only for a single view? Here is where <em>theme overlay </em>comes into play.</p><h4>Theme Overlay</h4><p><em>Theme overlay</em> is a technique used to override theme attributes for any view or view group. Theme overlays are very useful when you update the theme of a specific part of your app.</p><p>Applying a theme overlay consists of 2 steps:</p><ul><li>Create a style that consists of theme attributes desired to be changed</li><li>Apply this style on the layout file by using android:theme or programmatically by using ContextThemeWrapper</li></ul><p>Let’s continue with the aforementioned scenario where we are changing the button background color by the colorPrimary theme attribute. First, we need to create a style for a theme overlay where we set colorPrimary.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7c7ba43de971ae101ae97706a3542baa/href">https://medium.com/media/7c7ba43de971ae101ae97706a3542baa/href</a></iframe><blockquote>A theme overlay does not have any parent.</blockquote><p>Furthermore, it is better to start naming the style with ThemeOverlay since it will make it easier to distinguish from the other styles. This naming technique is used in <a href="https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/theme/res/values/themes_overlay.xml">Material Components</a> and <a href="https://github.com/hjanetzek/android-support-v7-appcompat/blob/master/res/values/themes.xml#L64">AppCompat</a> too.</p><p>Let’s apply this overlay to a button in the layout file.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9599fdd1443b21b530c3b9ac17bc4eb5/href">https://medium.com/media/9599fdd1443b21b530c3b9ac17bc4eb5/href</a></iframe><p>Bear in mind that if a theme overlay is applied to a view group, <a href="https://ataulm.com/2019/11/09/visualising-theme-overlays.html">it will apply to all of its descendants too</a>. In other words, the theme of every view group’s descendant is overlaid when a theme overlay is applied to a view group.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cbd2c94fd691af90253d4e7ca1270959/href">https://medium.com/media/cbd2c94fd691af90253d4e7ca1270959/href</a></iframe><p>We can also apply a theme overlay programmatically wrapping the context of the view with ContextThemeWrapper.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d44b4f722abde9cb49928dfd4f9129c7/href">https://medium.com/media/d44b4f722abde9cb49928dfd4f9129c7/href</a></iframe><blockquote>ContextThemeWrapper creates a new context (wrapping the given one) with its own theme.</blockquote><h4>TextAppearance</h4><p>TextAppearance is a class that contains data for only styling the TextView`s text-related attributes (For instance textColor, textSize but <strong>not </strong>view related attributes like<strong> </strong>maxLines or drawableTop etc.).</p><p>TextAppearance is set by android:textAppearance attribute on the TextView. android:textAppearance attribute works the same with style attribute. The main difference is the precedence order of them. style takes precedence over android:textAppearance meaning that style will always override the common attributes.</p><p>You might be asking why do we need it since we can give everything in style? The answer is having a way to set only text-related attributes makes it reusable for all TextViews whilst leaving the style attribute free.</p><p>For instance, let’s create a text appearance for a header.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/79202620427e022c85fda639c1c23252/href">https://medium.com/media/79202620427e022c85fda639c1c23252/href</a></iframe><p>Now, you can use this text appearance to make any TextView a header.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/afef997f6d7bf196a8ff71d0aa09b91e/href">https://medium.com/media/afef997f6d7bf196a8ff71d0aa09b91e/href</a></iframe><p>As you can see, the style attribute for TextView is free and can be used to customize other view attributes. You can also set android:textAppearance by creating a style.</p><p>Let’s create a single-line header style.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/306c9ca8a09476c9a719c66b543830cd/href">https://medium.com/media/306c9ca8a09476c9a719c66b543830cd/href</a></iframe><p>You can now set this style using style attribute and reuse this style for any text.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7900640333ca483f3f378063812d888e/href">https://medium.com/media/7900640333ca483f3f378063812d888e/href</a></iframe><p>If you want to dive deep into text appearances and the precedence of styles more, I highly recommend you to read <a href="https://medium.com/androiddevelopers/whats-your-text-s-appearance-f3a1729192d">this article</a>.</p><h4>Conclusion</h4><p>Attributes are a key concept in styling &amp; theming. Use view attributes to style a view and theme attributes for the application, Activity, or view hierarchy. If you want to change the style for all instances of a given view type throughout the app, default styles are the way to go. Theme overlays are used to override the theme attributes and you can even use them for views in a given view hierarchy. Text appearances can help you to shape your TextViews text-related attributes with android:textAppearance, while leaving style attribute free.</p><p><em>Thanks </em><a href="https://medium.com/u/c09b24c8e7b2"><em>Ataul Munim</em></a><em> and </em><a href="https://medium.com/u/22c02a30ae04"><em>Nick Butcher</em></a><em> for the reviews.</em></p><h4>References</h4><p><a href="https://medium.com/androiddevelopers/android-styling-themes-vs-styles-ebe05f917578">Android styling: themes vs styles</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FOwkf8DhAOSo%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DOwkf8DhAOSo&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FOwkf8DhAOSo%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/78870f287ae0605545b21bb7bbf73fe7/href">https://medium.com/media/78870f287ae0605545b21bb7bbf73fe7/href</a></iframe><ul><li><a href="https://ataulm.com/2020/05/07/refactoring-themes-with-style-default-styles.html">Refactoring Android Themes with Style: Default Styles - Ataul Munim</a></li><li><a href="https://ataulm.com/2020/05/28/refactoring-themes-with-style-theme-overlays.html">Refactoring Android Themes with Style: Theme Overlays - Ataul Munim</a></li><li><a href="https://ataulm.com/2019/11/09/visualising-theme-overlays.html">Visualising Theme Overlays - Ataul Munim</a></li><li><a href="https://medium.com/androiddevelopers/whats-your-text-s-appearance-f3a1729192d">What’s your text’s appearance?</a></li></ul><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fq_LJG4VuU3Q&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dq_LJG4VuU3Q&amp;image=http%3A%2F%2Fi.ytimg.com%2Fvi%2Fq_LJG4VuU3Q%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/2f4234ca40d0bd7102bd6be9790f13a4/href">https://medium.com/media/2f4234ca40d0bd7102bd6be9790f13a4/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=13c57bc20605" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/theming-basics-in-android-13c57bc20605">Theming basics in Android</a> was originally published in <a href="https://proandroiddev.com">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Animating the Compose Galaxy]]></title>
            <link>https://proandroiddev.com/animating-the-compose-galaxy-cfaea9dd8d09?source=rss-cacdfbac1fb3------2</link>
            <guid isPermaLink="false">https://medium.com/p/cfaea9dd8d09</guid>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[jetpack-compose]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Suleyman Fatih Giris]]></dc:creator>
            <pubDate>Wed, 31 Mar 2021 22:32:25 GMT</pubDate>
            <atom:updated>2021-03-31T22:32:25.013Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*mMlWcdWhKcMJq0uw" /><figcaption>Photo by <a href="https://unsplash.com/@ryan_hutton_?utm_source=medium&amp;utm_medium=referral">Ryan Hutton</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Since Jetpack Compose has joined our lives, it has been changing the way of our thinking and coding day by day. But more importantly, creating UI’s is becoming much easier compared to the old Android view system. This empowers developers to learn and adapt to the Compose environment in a much faster way (especially for animations 🥳).</p><p>After I started playing with Compose, I have built the following Compose Galaxy. In this post, I will share my learnings about animations in Jetpack Compose while building the Compose Galaxy.</p><h3>JavaScript is not available.</h3><p>There is so much fun with #JetpackCompose animation apis. Everything is random is this screen 😎 Even the number of sides of the shining stars 🌟 pic.twitter.com/JdiZuxQKHj</p><blockquote><strong>Disclaimer:</strong> Compose version used in this post is 1.0.0-beta02 and there might be API changes in the future.</blockquote><blockquote>You can access the Compose Galaxy source code from <a href="https://github.com/fgiris/ComposeGalaxy">here</a>.</blockquote><h3>Draw into Canvas</h3><p>First things first. We need to draw something to the screen in order to animate. <a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/Canvas.html">Canvas</a> composable can be used to draw any custom shape that can be represented in the coordinate system. In order to create a canvas, just use Canvas(modifier: Modifier, onDraw: DrawScope.() -&gt; Unit) composable function and place your drawings inside onDraw lambda. <a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope">DrawScope</a> provides stateless APIs to perform drawing into the canvas meaning that no need for maintaining the underlying canvas state.</p><p>Let’s draw a simple circle.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c002512742417015e1bf3869b9deacd1/href">https://medium.com/media/c002512742417015e1bf3869b9deacd1/href</a></iframe><p>Then we will have a circle in the middle of the screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/180/1*Ew47FbsopURqJFQ_sVuhNQ.png" /><figcaption>Circle in the middle of the screen</figcaption></figure><h3>Animation</h3><p>This is looking great but isn&#39;t it a bit boring? Let’s bring this little one alive. Luckily, we have very handy animation APIs in Compose. Let’s look at some of them and their use cases.</p><h4>animate*AsState</h4><p><a href="https://developer.android.com/jetpack/compose/animation#animate-as-state">animate*AsState</a> is the simplest animation API that is used to animate a <em>single</em> value. You only need to give the target value and whenever the target value changes the animation will get triggered again. Compose supports some of the commonly used data types like <em>Int</em>, <em>Float</em>, <em>Dp</em>, <em>Color</em>. But you can still use it to animate any type of value using <a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/package-summary?hl=hu#animatevalueasstate">animateValueAsState</a>. Additionally, no animate*AsState is cancellable without removing this composable function from the tree.</p><p>Let’s fade in the circle using <a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/package-summary?hl=hu#animatefloatasstate">animateAsFloat</a> by changing its alpha on click.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/20a0ebfef7fee3a0fce50a886be74295/href">https://medium.com/media/20a0ebfef7fee3a0fce50a886be74295/href</a></iframe><p>Then we get:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/156/1*LOmjiXpLyqUobuY0h7RdSQ.gif" /><figcaption>Fading in the circle</figcaption></figure><p>animate*AsState is very handy if you need to animate a single value. But what if you want to animate multiple values simultaneously? Then the answer is updateTransition.</p><h4>updateTransition</h4><p><a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/package-summary?hl=hu#updatetransition">updateTransition</a> creates a transition that manages running animations between given states. It gives you an opportunity to animate multiple values simultaneously. Remember that the transition created with this <strong>composable</strong> function only acceptsFiniteAnimationSpec to animate the values. It means that you can only create finite animations with this transition but not infinite ones.</p><p>Let’s use updateTransition both to fade in the circle and increase its radius simultaneously.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/53b4f419f44a0a182e91d899fdae3247/href">https://medium.com/media/53b4f419f44a0a182e91d899fdae3247/href</a></iframe><p>Here are the simultaneous animations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/156/1*gBZ1rszrnFxFPp49eiqDVA.gif" /><figcaption>Fading in the circle and animating its radius simultaneously</figcaption></figure><p>Note that the animation here is behaving like a one-shot animation and not repeating itself (It seems like repeating because of the gif image but the animation itself is not repeating). You could easily make it repeatable by wrapping the animation spec with repeatable() . But still repeatable != infinite. Let’s look into how we can create infinite animations.</p><h4>rememberInfiniteTransition</h4><p><a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/package-summary?hl=hu#rememberinfinitetransition">rememberInfiniteTransition</a> creates a transition that runs infinite animations. Note that this is also a <strong>composable</strong> function and <strong>cannot</strong> be called from a non-composable block.</p><p>Let’s add an infinite blinking animation to the circle.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7066d203051e444c81cba64e6488a06f/href">https://medium.com/media/7066d203051e444c81cba64e6488a06f/href</a></iframe><h4>Animatable</h4><p>Both <strong><em>updateTransition</em></strong> and <strong><em>rememberInfiniteTransition</em></strong> works really well inside the composable blocks. The animation created with these transitions happens during composition. But what if your animation is independent of composition and the animation itself is not the only source of truth (For instance touch events such as animating a circle to the point where the click happens) This is where <a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/package-summary?hl=hu#animatable"><strong>Animatable</strong></a> comes into play. Animatable is a float value holder which can be used to animate any float value without needing to be called from a composable block. It provides animateTo and animateDecay suspend functions that are used to start an animation.</p><p>Let’s move the circle to a random point every time the user clicks on the canvas.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/360978da516d77ef830e520d73ade019/href">https://medium.com/media/360978da516d77ef830e520d73ade019/href</a></iframe><p>Here is the result.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/156/1*hRQ2ntqlajBNqEka-Mnlvg.gif" /><figcaption>A circle moving to a random point on each click</figcaption></figure><blockquote>Avoid starting animation inside onDraw block since it might be called many times during recomposition.</blockquote><h4>TargetBasedAnimation</h4><p>Even though most of the aforementioned high-level APIs will be sufficient for most of the use cases, there are some cases we need to control the animation timing manually. (For instance, pausing and continuing the same animation) <a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/package-summary?hl=hu#targetbasedanimation">TargetBasedAnimation</a> gives you an opportunity to control the animation playtime by yourself. Both the start and target values should be specified when creating the TargetBasedAnimation .</p><p>Let’s pause and resume moving the circle on each user click.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4e9da3ba6a2ebca121f26dcd30afd330/href">https://medium.com/media/4e9da3ba6a2ebca121f26dcd30afd330/href</a></iframe><p>And the result is:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/156/1*s3M2WFpx3jBa4hf8RCQteA.gif" /><figcaption>Pausing and resuming the animation of a circle</figcaption></figure><h4>DecayAnimation</h4><p><a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/package-summary?hl=hu#decayanimation">DecayAnimation</a> also gives you control over the animation playtime. Unlike TargetBasedAnimation, there is no target value for DecayAnimation. You only give an initial value and a velocity, then the target value is calculated based upon those values. You can think of DecayAnimation like an animation calculating engine which gives you the right animation value calculated from the value and the velocity for the corresponding playtime. If you do not need to control the animation time, you should be using Animatable.animateDecay instead of DecayAnimation.</p><blockquote>It is <a href="https://developer.android.com/reference/kotlin/androidx/compose/animation/core/DecayAnimation">not recommended</a> to use DecayAnimation unless you need to control the animation timing manually.</blockquote><p>Let’s pause and resume moving a car image using DecayAnimation on each click.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f688516288da5a0b6d1263d98263fed0/href">https://medium.com/media/f688516288da5a0b6d1263d98263fed0/href</a></iframe><p>Then we have:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/156/1*enooSyxGNJPbDZkE367u5w.gif" /><figcaption>Pausing and resuming the animating car image with <strong>DecayAnimation</strong></figcaption></figure><h4>Conclusion</h4><p>Animations have never been so easy like in Compose. If you want to animate a single value then use animate*AsState. But if you need multiple animations simultaneously, then updateAnimation is the way. You can repeat your animations by wrapping your animation spec with repeatable. If you want to repeat animations infinitely, prefer using rememberInfiniteTransition. Animatable is used when your animation is not the only source of truth. Also do not prefer using TargetBasedAnimation and DecayAnimation unless there is a need to control the animation timing manually.</p><p><em>Thanks </em><a href="https://medium.com/u/74e42aad30e"><em>Adam Bennett</em></a><em> and </em><a href="https://twitter.com/doris4lt"><em>Doris Liu</em></a><em> for the reviews.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cfaea9dd8d09" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/animating-the-compose-galaxy-cfaea9dd8d09">Animating the Compose Galaxy</a> was originally published in <a href="https://proandroiddev.com">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hilt Migration Guide]]></title>
            <link>https://proandroiddev.com/hilt-migration-guide-54c48ca18353?source=rss-cacdfbac1fb3------2</link>
            <guid isPermaLink="false">https://medium.com/p/54c48ca18353</guid>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[dependency-injection]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[dagger]]></category>
            <category><![CDATA[hilts]]></category>
            <dc:creator><![CDATA[Suleyman Fatih Giris]]></dc:creator>
            <pubDate>Fri, 14 Aug 2020 16:27:31 GMT</pubDate>
            <atom:updated>2020-08-14T16:27:31.516Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*oDm2U_HEKC1JNSN8" /><figcaption>Photo by <a href="https://unsplash.com/@andrewtneel?utm_source=medium&amp;utm_medium=referral">Andrew Neel</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Dagger is an advanced dependency injection library and it is not easy to understand at the first glance for most developers. Using Dagger in Android requires much more effort for framework classes since it requires some boilerplate code. Hilt helps to reduce Dagger’s complexity and boilerplates with a set of ready components, scopes, and annotations.</p><p>In this post, we will see the Hilt migration of a sample app that uses <em>dagger-android</em> for DI. The migration will be in the order as shown below.</p><ul><li>Application class</li><li>Dagger components and modules</li><li>Activities &amp; Fragments</li><li>ViewModels</li><li>WorkManager</li><li>Tests</li></ul><p>You can also check out the changes from the Hilt migration <a href="https://github.com/fgiris/LiveDataWithFlowSample/pull/1">pull request</a> for the sample app used in this post.</p><blockquote><strong>Note:</strong> This migration relies on Hilt version 2.28-alpha.</blockquote><p>Before starting the migration, you need to add Hilt dependencies to your grade files.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1e6f980e777cf1a9a7d17aa0e686c0b4/href">https://medium.com/media/1e6f980e777cf1a9a7d17aa0e686c0b4/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8a7dc72fc118ce4b9fd908cf67242ace/href">https://medium.com/media/8a7dc72fc118ce4b9fd908cf67242ace/href</a></iframe><h4>Application Class</h4><p>The first thing you will do is to add@HiltAndroidApp annotation to the Application class.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/88afbf220b3ef408b54a8d4f89067907/href">https://medium.com/media/88afbf220b3ef408b54a8d4f89067907/href</a></iframe><p>It is better to keep the old dagger-android implementation in the application class since the migration will be done incrementally. It will give a chance to make a sanity check during the migration.</p><h4>Dagger Components and Modules</h4><p>Hilt provides ApplicationComponent which is to replace components which are annotated with@Singleton. In order to remove the AppComponent in this sample app, all modules are annotated with InstallIn(Applicationcomponent::class).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f2d6746fdf601fb79b70aff8455302a2/href">https://medium.com/media/f2d6746fdf601fb79b70aff8455302a2/href</a></iframe><p>After adding the annotation to all modules, AppComponent could safely be removed.</p><p>Additionally, there is no need to provide a context since Hilt provides @ApplicationContext and @ActivityContext annotations to get different contexts. Any injected context in this sample app is annotated with @ApplicationContext.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/167853c45c753db25dac924f08b641d6/href">https://medium.com/media/167853c45c753db25dac924f08b641d6/href</a></iframe><blockquote>Remember to include AndroidInjectionModule with one of your modules in order to be able to inject the activities and fragments without Hilt.</blockquote><p>The last thing before making a sanity check is to tell Hilt how to inject AndroidInjector which is used in AndroidInjectionModule with using an entry point.</p><blockquote>An <strong>entry point</strong> is a bridge between Hilt and the objects which cannot get its dependencies by Hilt.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fcedec16c9ad93baa21af52546e0eba6/href">https://medium.com/media/fcedec16c9ad93baa21af52546e0eba6/href</a></iframe><p><strong>Checkpoint: </strong>If you run the app, everything should be working fine. You can check <a href="https://github.com/google/dagger/issues/1902">this issue</a> if you see any error similar to “<em>Expected @HiltAndroidApp to have a value. Did you forget to apply the Gradle Plugin?”.</em></p><h4>Activities &amp; Fragments</h4><p>Hilt provides <a href="https://dagger.dev/hilt/android-entry-point">@AndroidEntryPoint</a> annotation which can also be used for activities and fragments. When migrating activities and fragments, all needs to be done is to add @AndroidEntryPoint annotation and remove the boilerplate code for dagger injection with HasAndroidInjector. Since this app is using DaggerAppCompatActivity and DaggerFragment, replacing them with AppCompatActivity and Fragment is sufficient.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d06697bdf86b4b851d85b7b8a1a3e011/href">https://medium.com/media/d06697bdf86b4b851d85b7b8a1a3e011/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5b12129767a858bd9d6e26702a7250b3/href">https://medium.com/media/5b12129767a858bd9d6e26702a7250b3/href</a></iframe><p>Now, Dagger modules ActivityBuilderModule,FragmentBuilderModule and AndroidInjectionModule can be removed. Also, DaggerApplication can be replaced by Application, since there is no need for AndroidInjection. You can see these changes from this <a href="https://github.com/fgiris/LiveDataWithFlowSample/pull/1/commits/ed092f139b00e4ac0e151be6e88557803861838c">commit</a>.</p><p><strong>Checkpoint:</strong> Run the app and everything should be working fine.</p><blockquote><strong>Note:</strong> Currently, Hilt does not support Kotlin default args. You can check the issue from <a href="https://github.com/google/dagger/issues/1904#issuecomment-644192826">here</a>.</blockquote><h4>ViewModels</h4><p>In order to inject a ViewModel with Hilt, Jetpack integrations for ViewModel should be added to the project. This library provides @ViewModelInject annotation which is used for ViewModel constructor injection.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/29346ac0419d009a22b9c45ea3f67034/href">https://medium.com/media/29346ac0419d009a22b9c45ea3f67034/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ede39098ffdeefd77ea0e43aa136fbbd/href">https://medium.com/media/ede39098ffdeefd77ea0e43aa136fbbd/href</a></iframe><p>viewModels() extension could be used in an activity or a fragment to get a ViewModel injected using ViewModelInject. Use activityViewModels() extension to scope the ViewModel to an activity in a fragment.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0c41fb740c34dc005417c4ba01df5643/href">https://medium.com/media/0c41fb740c34dc005417c4ba01df5643/href</a></iframe><p>After applying these changes to all ViewModels, ViewModelModule and ViewModelProviderFactory could be removed.</p><p><strong>Checkpoint:</strong> Run the app and everything should be working fine.</p><blockquote><strong>Note 1:</strong> If the ViewModel is scoped to a navigation graph, defaultViewModelProviderFactory could be used as a factory.</blockquote><blockquote><strong>Note 2:</strong> SavedStateHandle requires to be annotated with @Assisted when it is injected to a ViewModel.</blockquote><h4>WorkManager</h4><p>Injecting WorkManager also requires Jetpack integrations.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7b92e73e8ecf2e436ad9036d819953e4/href">https://medium.com/media/7b92e73e8ecf2e436ad9036d819953e4/href</a></iframe><p>@WorkerInject annotation is used to inject a worker.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3716b9b91196acadc9fc5ce95d978909/href">https://medium.com/media/3716b9b91196acadc9fc5ce95d978909/href</a></iframe><p>In order to inject the worker factory to the graph, Jetpack integrations provideHiltWorkerFactory which could be used the setup the work manager configurations in the application class.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2a6d501fae4402381e215d8eb52985cb/href">https://medium.com/media/2a6d501fae4402381e215d8eb52985cb/href</a></iframe><blockquote><strong>Note:</strong> Do not forget to <a href="https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration#remove-default">remove the default </a><a href="https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration#remove-default">WorkManager initialization</a> in the Manifest.</blockquote><h4>Testing</h4><p>The sample app uses dagger for integration tests. TestCoroutineModule is used in TestAppComponent to replace the CoroutineModule used in production. Also, CustomTestRunner is used to override the application with LiveDataWithFlowTestApplication. Let’s start migrating tests to Hilt with adding Hilt dependencies to the gradle file.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9231fd2b3423849da73644f9434b6a63/href">https://medium.com/media/9231fd2b3423849da73644f9434b6a63/href</a></iframe><p>LiveDataWithFlowTestApplication could be removed since Hilt provides HiltTestApplication.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9e8fc800f2037df7c3d8956cee1f1526/href">https://medium.com/media/9e8fc800f2037df7c3d8956cee1f1526/href</a></iframe><p>In order to remove TestAppComponent and use ApplicationComponent by Hilt, TestCoroutineModule should be installed in ApplicationComponent.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/af78265fc117398177f177d865343535/href">https://medium.com/media/af78265fc117398177f177d865343535/href</a></iframe><p>Bear in mind that there are 2 coroutine modules installed in ApplicationComponent now. Luckily, Hilt can uninstall modules too with @UninstallModules annotation.</p><p>Moreover, every test needs to be annotated with @HiltAndroidTest and HiltAndroidRule should be used in these tests.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d9335b4595b3bfb0aace1b36442e0ce/href">https://medium.com/media/1d9335b4595b3bfb0aace1b36442e0ce/href</a></iframe><p>If there is more than one rule, then HiltAndroidRule needs to be executed in the first order. You can check how to give an order to the test rules from <a href="https://developer.android.com/training/dependency-injection/hilt-testing#multiple-testrules">docs</a>.</p><blockquote><strong>Note:</strong> UsinglaunchFragmentInContainer is currently not possible with Hilt since it uses a hardcoded activity that does not have a Hilt annotation. You can check the workaround from <a href="https://github.com/android/architecture-samples/blob/dev-hilt/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/HiltExt.kt#L38">here</a>.</blockquote><p><strong>Checkpoint: </strong>If you run the tests, everything should be working fine.</p><p>Even though it takes some time to migrate Dagger to Hilt, it is a powerful library and makes developers&#39; life easier by removing lots of boilerplate codes. It also simplifies the Dagger’s complexity with its handy annotations. In short, you won’t regret it after migrating to Hilt!</p><p>Thanks <a href="https://medium.com/u/3b5622dd813c">Manuel Vivo</a> for reviewing this post.</p><h4>References</h4><ul><li><a href="https://developer.android.com/training/dependency-injection/hilt-android">Dependency injection with Hilt</a></li><li><a href="https://codelabs.developers.google.com/codelabs/android-dagger-to-hilt/">Migrating your Dagger app to Hilt</a></li><li><a href="https://dagger.dev/hilt/migration-guide">Migrating to Hilt</a></li><li><a href="https://developer.android.com/training/dependency-injection/hilt-jetpack">Hilt and Jetpack integrations</a></li><li><a href="https://medium.com/androiddevelopers/dependency-injection-on-android-with-hilt-67b6031e62d">Dependency Injection on Android with Hilt</a></li><li><a href="https://medium.com/androiddevelopers/hilt-adding-components-to-the-hierarchy-96f207d6d92d">Hilt — Adding components to the hierarchy</a></li><li><a href="https://medium.com/androiddevelopers/migrating-the-google-i-o-app-to-hilt-f3edf03affe5">Migrating the Google I/O app to Hilt</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=54c48ca18353" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/hilt-migration-guide-54c48ca18353">Hilt Migration Guide</a> was originally published in <a href="https://proandroiddev.com">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using LiveData & Flow in MVVM — Part III]]></title>
            <link>https://proandroiddev.com/using-livedata-flow-in-mvvm-part-iii-8703d305ca73?source=rss-cacdfbac1fb3------2</link>
            <guid isPermaLink="false">https://medium.com/p/8703d305ca73</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <category><![CDATA[android-app-development]]></category>
            <dc:creator><![CDATA[Suleyman Fatih Giris]]></dc:creator>
            <pubDate>Tue, 14 Apr 2020 18:28:34 GMT</pubDate>
            <atom:updated>2020-04-14T18:28:34.282Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sv11z5rRtCIvEiO_0CO2mA.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@roshnisidapara?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Roshni Sidapara</a> on <a href="https://unsplash.com/s/photos/traffic-jam?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><h3>Using LiveData &amp; Flow in MVVM — Part III</h3><h4>Unit Testing LiveData &amp; Coroutines and Flow</h4><p>We have seen using LiveData &amp; Flow and only Flow in MVVM architecture in <a href="https://proandroiddev.com/using-livedata-flow-in-mvvm-part-i-a98fe06077a0">Part I</a> and <a href="https://proandroiddev.com/using-livedata-flow-in-mvvm-part-ii-252ec15cc93a">Part II</a>. In this post, we will see how to test LiveData &amp; Coroutines and Flow. We will be solving a common race condition problem between LiveData and Coroutines with <em>TestCoroutineDispatcher</em>. After that, we will see how easy to test the Flow 😎</p><p>You can access the sample project from 👇</p><p><a href="https://github.com/fgiris/LiveDataWithFlowSample/tree/fgiris/android_turkiye_work_around">https://github.com/fgiris/LiveDataWithFlowSample/tree/fgiris/android_turkiye_work_around</a></p><h4>Unit Testing LiveData &amp; Coroutines ⚒</h4><p>You might have seen your branch builds 💚 locally, but whenever you push it to remote your build gets 🔴. When you check the logs, you see that one of the tests which you have already added is failing because of LiveData not giving you the correct value. But why? Is it because of LiveData or Coroutines?</p><p>One of the common problems, when you are testing Coroutines with LiveData, is a race condition. You have to be very careful about the Dispatchers, Looper … If you do not have proper test rules for them, your mind could be blown and you can say “Let’s just comment out, and we can look at it later” (!).</p><p>To prevent this to happen, let’s start with a very simple function in the repository.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/25389d9c7333764217cfc9aa2772b08b/href">https://medium.com/media/25389d9c7333764217cfc9aa2772b08b/href</a></iframe><p>We will be testing if this function returns a success value.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0903ad9023b0bd731c1213a771b0e9f9/href">https://medium.com/media/0903ad9023b0bd731c1213a771b0e9f9/href</a></iframe><p>We need to call the suspend function from a coroutine scope and this is why <em>runBlocking </em>is used here. This test function passes successfully ✅</p><p>What about ViewModel? Let’s go ahead and see how fetchWeatherForecastSuspendCase function is used in the ViewModel.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5411d1e952722eab4599163924d41192/href">https://medium.com/media/5411d1e952722eab4599163924d41192/href</a></iframe><p>The important thing here is we are starting a new coroutine in the function we will test. We will be testing if fetchWeatherForecast function first returns Loading and then Success.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fc701e7d07f8533e60c974bfb6fa7bdf/href">https://medium.com/media/fc701e7d07f8533e60c974bfb6fa7bdf/href</a></iframe><p>runBlocking is used since we have a suspend delay function to wait for an actual response. I know using delay is not a good solution, but this is a very basic example and we will fix it later, no worries 😊</p><p>When you run this test, you will get <em>RunTimeException </em>for getting the main <em>Looper</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*1hLy5euQjKZ8g89fzoI5WQ.png" /><figcaption>Main Looper not mocked in unit tests</figcaption></figure><p>The reason for this from the <a href="http://tools.android.com/tech-docs/unit-testing-support#TOC-Method-...-not-mocked.-">official docs</a>:</p><blockquote>The android.jar file that is used to run unit tests does not contain any actual code — that is provided by the Android system image on real devices. Instead, all methods throw exceptions (by default). This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito).</blockquote><p>It says that there is no access to the Android system image (which includes the main Looper for your application) in unit tests. To fix this, we have 2 options.</p><ul><li>Enabling default values for the unit tests in the gradle file. (<a href="https://developer.android.com/training/testing/unit-testing/local-unit-tests.html#error-not-mocked"><strong>Not recommended</strong></a>)</li><li>Adding <a href="https://developer.android.com/reference/android/arch/core/executor/testing/InstantTaskExecutorRule.html"><em>InstantTaskExecutorRule</em></a> which overrides isMainThread method which will call to get the main looper. It also changes the background executor for Architecture Components, in order to execute them synchronously in the tests.</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5efdd9470b55b4ac4c2729afaa6752b9/href">https://medium.com/media/5efdd9470b55b4ac4c2729afaa6752b9/href</a></iframe><p>Let’s run the test again after adding the <em>InstantTaskExecutorRule</em> rule.</p><p>It does not let it pass again 🚷 🚯 🚳 🚱…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2IGPw0RfoWd-z0cwpyNp6w.png" /><figcaption>Failure for the main dispatcher initialization</figcaption></figure><p>Now it is complaining for the main dispatcher not to be initialized. The reason for this is <em>Dispatchers.Main</em> requires main Looper which is not available in the unit tests. So the solution is to override <em>Dispatchers.Main</em> with <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-dispatcher/"><em>TestCoroutineDispatcher</em></a>.</p><p>Let’s write a general rule to use <em>TestCoroutineDispatcher</em>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/63bd82c90db1feb9238608191e32eb48/href">https://medium.com/media/63bd82c90db1feb9238608191e32eb48/href</a></iframe><p>You can find the whole implementation of this rule from <a href="https://github.com/android/plaid/blob/master/test_shared/src/main/java/io/plaidapp/test/shared/MainCoroutineRule.kt">here</a>. We are simply setting the main dispatcher to <em>TestCoroutineDispatcher </em>whenever a test is started. Let’s add this rule in our test too and run it again.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/66f8244a27342120f3fe484794a5fd0a/href">https://medium.com/media/66f8244a27342120f3fe484794a5fd0a/href</a></iframe><p>Voilà 🎉 Our test passes after all these processes.</p><blockquote><strong>TestCoroutineDispatcher</strong><em> </em>has <strong>runBlockingTest</strong> which will immediately progress delays with a virtual clock. It can be used for faster tests instead of <strong>runBlocking</strong>.</blockquote><p>But wait, we were using <em>Dispatcher.Main,</em> which is mainly suitable for UI operations, to make a network request in ViewModel. Let’s go back and replace that with <em>Dispatchers.IO</em> which is essentially a better option for network requests.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/821ce1caa5612769961dcff0315d0068/href">https://medium.com/media/821ce1caa5612769961dcff0315d0068/href</a></iframe><p>After changing the dispatcher with <em>Dispatchers.IO</em>, the test is failing again 🤦🏼. The reason is we only override the main dispatcher. However, when you start a new coroutine with other dispatchers, that coroutine will be executed in a different thread.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/426/1*aUwWd16YOGGTGaCyqBvplQ.png" /><figcaption>Dispatchers.IO uses a different thread</figcaption></figure><p>Can we also override the other dispatchers with a function like Dispatchers.setMain? Unfortunately not. This is why we need to inject the dispatchers.</p><blockquote>Always inject the dispatchers for better testability.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b95ead974dcdb62c4308446b14ae3047/href">https://medium.com/media/b95ead974dcdb62c4308446b14ae3047/href</a></iframe><p>We need to give the same test dispatcher to the ViewModel when it is created in the tests.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/52408b2322fb744c661ccea597bb7a37/href">https://medium.com/media/52408b2322fb744c661ccea597bb7a37/href</a></iframe><p>After that our test passes even if we use a different dispatcher.</p><p>It is time to remove the delay to wait for the api call. Since we are using <em>runBlockingTest</em> and all delay functions will be immediately progressed, you can choose to write a 100 seconds delay like delay(100000),which is hopefully bigger than each of your api call’s response time and test the api call after that delay. But it is a very bad solution 🤮</p><p>Fortunately, you can resume and pause the test dispatcher in order not to start a new coroutine while doing some tests. This lets us control any new coroutine which is started in the test function.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7510b9392ecfabea35b6557c35484a86/href">https://medium.com/media/7510b9392ecfabea35b6557c35484a86/href</a></iframe><p>We just controlled the coroutine execution and our test passes 💪🏻.</p><h4>Testing Flow 🚀</h4><p>Testing Flow is much easier than testing LiveData &amp; Coroutines. Because Flow is providing all of the data in the same coroutine context in which the Flow is collected, there is no race condition in the collector side. So, this lets us test the data sequentially without pausing or resuming anything.</p><p>Let’s use this simple function which returns a flow of data in the repository.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f2feb7ca03e790a44712e5ee96214185/href">https://medium.com/media/f2feb7ca03e790a44712e5ee96214185/href</a></iframe><p>We will test if this function loading first and then giving a success response. We can use the <strong><em>collect</em></strong> <a href="https://kotlinlang.org/docs/reference/coroutines/flow.html#terminal-flow-operators"><em>terminal operator</em></a> for starting the data collection in the test.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1b48d5286acf513752c51b0d62817258/href">https://medium.com/media/1b48d5286acf513752c51b0d62817258/href</a></iframe><p>Since we don&#39;t have an index of data, let&#39;s use <strong><em>collectIndexed</em></strong> operator.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8a9517e40209dc7e04e127063adb7cb0/href">https://medium.com/media/8a9517e40209dc7e04e127063adb7cb0/href</a></iframe><p>Alternatively, you can convert Flow to a list with <strong><em>toList</em></strong> operator and test the list 🔥</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fdda7e28caf5f5cc767ecc888b21ba39/href">https://medium.com/media/fdda7e28caf5f5cc767ecc888b21ba39/href</a></iframe><p>Controlling and testing the data flow becomes very easy with Flow operators.</p><blockquote>Note: You can convert LiveData to a Flow with using <a href="https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/FlowLiveData.kt#86"><strong>asFlow</strong></a><em> </em>extension and test the Flow instead of LiveData. The created Flow will only contain the latest value and then observe the updates from LiveData. Since fetching response &amp; updating LiveData happens in our ViewModel initialization, it does not fit well for our test cases.</blockquote><p>If you are testing LiveData &amp; Coroutines, make sure to inject all dispatchers and use <strong><em>TestCoroutineDispatcher</em></strong>. Also, don&#39;t forget to make use of <strong><em>runBlockingTest</em></strong> to skip delays in your tests. If you are starting a new coroutine inside a test function, use the pause and resume functions in the test dispatcher to properly test the LiveData value. Additionally, you can prefer using <strong><em>asFlow</em></strong> extension and test Flow instead of LiveData 🤟🏻</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8703d305ca73" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/using-livedata-flow-in-mvvm-part-iii-8703d305ca73">Using LiveData &amp; Flow in MVVM — Part III</a> was originally published in <a href="https://proandroiddev.com">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using LiveData & Flow in MVVM — Part II]]></title>
            <link>https://proandroiddev.com/using-livedata-flow-in-mvvm-part-ii-252ec15cc93a?source=rss-cacdfbac1fb3------2</link>
            <guid isPermaLink="false">https://medium.com/p/252ec15cc93a</guid>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Suleyman Fatih Giris]]></dc:creator>
            <pubDate>Fri, 07 Feb 2020 22:12:24 GMT</pubDate>
            <atom:updated>2020-02-07T22:12:24.307Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*wsRkOk7n3dqNKEbn" /><figcaption>Photo by <a href="https://unsplash.com/@fabioha?utm_source=medium&amp;utm_medium=referral">fabio</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><h3>Using LiveData &amp; Flow in MVVM — Part II</h3><p>We have seen how to use Flow in the repository layer and how to change the app theme with Flow &amp; LiveData in <a href="https://proandroiddev.com/using-livedata-flow-in-mvvm-part-i-a98fe06077a0">Part I</a>. In this post, we will see how to remove LiveData (even MediatorLiveData) and use <strong>only</strong> Flow in all layers. We will also dive deep into the common Flow operators like <em>map</em>, <em>filter</em>, <em>transform,</em> and more. In the end, we will implement a search bar example given by <a href="https://medium.com/u/83518fe480be">Sean McQuillan</a> in “<a href="https://fragmentedpodcast.com/episodes/187/">Fragmented Podcast — 187: Coroutines with Manuel Vivo &amp; Sean McQuillan</a>” with using Channel and Flow.</p><p>You can access the sample project from <a href="https://github.com/fgiris/LiveDataWithFlowSample">here</a>.</p><blockquote>Disclaimer: Some of the Flow apis used in this post are still experimental. They are subject to change in the future.</blockquote><h4>Say 👋 to LiveData</h4><p>Using LiveData ensures that you will not be leaking any resources if the lifecycle owner does not exist anymore. What if I tell that you can <strong>almost</strong>* (explained later why not the same but almost) get the same benefit with using Flow?</p><p>Let’s see how we can do it.</p><h4>Repository</h4><p>The repository layer remains the same since we are already returning Flow.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/51968050cee4eedb6907bbb1abc33df2/href">https://medium.com/media/51968050cee4eedb6907bbb1abc33df2/href</a></iframe><h4>ViewModel</h4><p>Instead of converting Flow to LiveData with asLiveData, we just use Flow in ViewModel.</p><p>Before it was like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/73e18f0fe43da5d8ce6ec35573341001/href">https://medium.com/media/73e18f0fe43da5d8ce6ec35573341001/href</a></iframe><p>With only Flow, it becomes:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/95ec2f1d0c790de2e8c34c1a12f34a29/href">https://medium.com/media/95ec2f1d0c790de2e8c34c1a12f34a29/href</a></iframe><p>But, wait. <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/map.html"><em>map</em></a> is missing 🤔 Let’s add it so that it converts Celsius to Fahrenheit when mapping.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cb2fa620393d7ef48efd36765728f603/href">https://medium.com/media/cb2fa620393d7ef48efd36765728f603/href</a></iframe><p>You might want to show loading in UI, then <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-start.html"><em>onStart</em></a><em> </em>is the perfect place<em>.</em></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3682fe099936864ebfed78b437616886/href">https://medium.com/media/3682fe099936864ebfed78b437616886/href</a></iframe><p>If you want to filter values, then go ahead. You have <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/filter.html"><em>filter</em></a> operator.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cbc3d6d2215e9377ccdb6ac3a55517bc/href">https://medium.com/media/cbc3d6d2215e9377ccdb6ac3a55517bc/href</a></iframe><p>You can also make a transformation on data with <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/transform.html"><em>transform</em></a> operator which gives you the flexibility to emit as many as you want for a single value.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8970ab657d99a3d450d927fa683a325d/href">https://medium.com/media/8970ab657d99a3d450d927fa683a325d/href</a></iframe><p>Since <em>Flow</em> is sequential, the total execution time of collecting a value is the sum of all operators&#39; execution time. If you have a long-running operation in operators, you can use <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/buffer.html"><em>buffer</em></a><em> </em>so that the execution of all operators until <em>buffer</em> will be handled in a different coroutine than the coroutine in which the flow is collected. This makes the total execution faster.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3b76cfafe46b89ae31235873a5e573ee/href">https://medium.com/media/3b76cfafe46b89ae31235873a5e573ee/href</a></iframe><p>What if you do not want to collect the same value multiple times? Then you can just use <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/distinct-until-changed.html"><em>distinctUntilChanged</em></a> operator which only sends the value when it is different than the previous one.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ed7d4c7d933aceeb4ed08b54ae705c9a/href">https://medium.com/media/ed7d4c7d933aceeb4ed08b54ae705c9a/href</a></iframe><p>Let’s say you only want to cache the modified data before showing in the UI. You can make use of <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/on-each.html"><em>onEach</em></a> operator to do your work for each value.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4a36b46ff35d33a661ee3092ab16c88a/href">https://medium.com/media/4a36b46ff35d33a661ee3092ab16c88a/href</a></iframe><p>If you are doing some heavy work in all operators, you can simply change the context of the whole operators’ execution by using the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow-on.html"><em>flowOn</em></a> operator.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2a58d0eaf44a4a07fa54744a7c424f1e/href">https://medium.com/media/2a58d0eaf44a4a07fa54744a7c424f1e/href</a></iframe><p>What about errors? Simply use the <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/catch.html"><em>catch</em></a> operator to catch any error in the down stream flow.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/670679d77742dd1242dfc34096187914/href">https://medium.com/media/670679d77742dd1242dfc34096187914/href</a></iframe><p>What if we have another flow that is to be merged with _weatherForecast flow? (You might think this as a <em>MediatorLiveData</em> having multiple <em>LiveData</em> sources) You can use <em>merge</em> function to merge any number of flows.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f356affa97e3071ec5cbd81feed67508/href">https://medium.com/media/f356affa97e3071ec5cbd81feed67508/href</a></iframe><p>Finally, our ViewModel looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ef5a80a0fa49b214394f8743587fe778/href">https://medium.com/media/ef5a80a0fa49b214394f8743587fe778/href</a></iframe><p>The only thing left is to <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/collect.html"><em>collect</em></a> the flow from the fragment.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b4f1c33a6cca50302ad65ad4a91d8109/href">https://medium.com/media/b4f1c33a6cca50302ad65ad4a91d8109/href</a></iframe><p>These are just some of the Flow operators. You can find the whole list of operators from <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/index.html">here</a>.</p><blockquote>Note: Removing LiveData adds extra work for configuration changes. In order to retain configuration changes, you need to cache the latest value. You can check how <a href="https://github.com/dropbox/Store">Dropbox Store</a> library handles caching from <a href="https://github.com/dropbox/Store/blob/master/store/src/main/java/com/dropbox/android/external/store4/impl/RealStore.kt">here</a>.</blockquote><h4>Search bar using Channel and Flow</h4><p>In <a href="https://fragmentedpodcast.com/episodes/187/">this</a> podcast, <a href="https://medium.com/u/83518fe480be">Sean McQuillan</a> gave an example of how to create a search bar using <em>Channel</em> and <em>Flow</em>. The idea is to have a search bar with a filtered list. Whenever the user types something to the search bar, the list is filtered with the text in the search bar. This is done by saving the text value in the channel and observing changes with flow through this channel.</p><p>To demonstrate this example, let’s have a city list and a search bar. In the end, it will look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*IyiA-deC06c0wIyXu9Sl7g.gif" /><figcaption>Filtering cities with using channel and flow</figcaption></figure><p>We will have an EditText in the Fragment. Whenever the text is updated, we will send it to the channel which is stored in ViewModel.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8b505f4b36d41090f00b10e7ead2a91f/href">https://medium.com/media/8b505f4b36d41090f00b10e7ead2a91f/href</a></iframe><p>When the channel gets updated with the latest value, we will filter the cities and send the list to the subscribers.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c880781a073868f17e89cd6f648928fc/href">https://medium.com/media/c880781a073868f17e89cd6f648928fc/href</a></iframe><p>Then, just observe the changes in the fragment.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9fc43ecfec7605256f0fec536910e331/href">https://medium.com/media/9fc43ecfec7605256f0fec536910e331/href</a></iframe><p>Well, we just implemented a searching and filtering mechanism with using channel and flow 👊</p><h3>What’s next</h3><p>In this post, we have seen how to replace LiveData with Flow in MVVM architecture. Also, we implemented a filtering mechanism with Channel &amp; Flow.</p><p>In the next post, I will be explaining how to test LiveData &amp; Flow. Stand by!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=252ec15cc93a" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/using-livedata-flow-in-mvvm-part-ii-252ec15cc93a">Using LiveData &amp; Flow in MVVM — Part II</a> was originally published in <a href="https://proandroiddev.com">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using LiveData & Flow in MVVM — Part I]]></title>
            <link>https://proandroiddev.com/using-livedata-flow-in-mvvm-part-i-a98fe06077a0?source=rss-cacdfbac1fb3------2</link>
            <guid isPermaLink="false">https://medium.com/p/a98fe06077a0</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[kotlin]]></category>
            <dc:creator><![CDATA[Suleyman Fatih Giris]]></dc:creator>
            <pubDate>Tue, 21 Jan 2020 23:11:43 GMT</pubDate>
            <atom:updated>2020-01-21T23:11:43.865Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s-fuR5JP20GsZzp5e356LQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@lysanderyuen?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Lysander Yuen</a> on <a href="https://unsplash.com/s/photos/fix?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><h3>Using LiveData &amp; Flow in MVVM — Part I</h3><p>Lately, I have been searching for the best practices of Kotlin Flow in MVVM architecture. After I have answered <a href="https://stackoverflow.com/a/58775840/9620805">this</a> question about LiveData and Flow, I’ve decided to write this post. In this post, I will be explaining how to use Flow with LiveData in the MVVM pattern. Then we will see how to change the app theme by using Flow.</p><p>You can access the sample project from here:</p><p><a href="https://github.com/fgiris/LiveDataWithFlowSample.git">fgiris/LiveDataWithFlowSample</a></p><blockquote>Disclaimer: This post assumes that you are already familiar with Flow. If you are not, I suggest you check <a href="https://kotlinlang.org/docs/reference/coroutines/flow.html#asynchronous-flow">docs</a> and <a href="https://medium.com/@elizarov/cold-flows-hot-channels-d74769805f9">this article</a> by <a href="https://medium.com/u/4762e889f8fc">Roman Elizarov</a>.</blockquote><h4>What is Flow?</h4><blockquote><strong>Flow</strong> is a reactive stream in the coroutines library which is able to return multiple values from a suspend function [<a href="https://kotlinlang.org/docs/reference/coroutines/flow.html#asynchronous-flow">1</a>].</blockquote><p>Even though the use case of Flow seems very similar to LiveData, it has more advantages like:</p><ul><li>Asynchronous by itself with structured concurrency <em>[</em><a href="https://medium.com/@elizarov/structured-concurrency-722d765aa952"><em>2</em></a><em>]</em></li><li>Simple to transform data with operators like <em>map, filter …</em></li><li>Easy to test</li></ul><h4>How to use Flow in MVVM</h4><p>If your app has MVVM architecture, you normally have a data layer (repository, data source, etc.), ViewModel and view (Fragment or Activity). You would probably be using LiveData for data transfers and transformations between these layers. But what is the main purpose of LiveData? Is it designed to make data transformation?</p><blockquote>LiveData was never designed as a fully fledged reactive stream builder .</blockquote><p>says <a href="https://medium.com/u/e0a4c9469bb5">Jose Alcérreca</a> in Android Dev Summit 2019. Since LiveData is a lifecycle aware component, it is best to use it in view and ViewModel layer. But how about the data layer? I think the biggest problem of using LiveData in the repository level is all data transformation will be done on the main thread unless you start a coroutine and do the work inside. This is why you might prefer suspend functions in the data layer.</p><p>Let’s say you want to fetch weather forecast data from the network. Then it will be similar as below with suspend function in your repository.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/93e72f59c740892b5947b8ac63334c1c/href">https://medium.com/media/93e72f59c740892b5947b8ac63334c1c/href</a></iframe><p>You can call this function with <em>viewModelScope</em> in ViewModel.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c473429bdc2ea8d6467fbcc3d06a08fc/href">https://medium.com/media/c473429bdc2ea8d6467fbcc3d06a08fc/href</a></iframe><p>This approach works fine with one-shot requests which are run each time when they are called [<a href="https://link.medium.com/ZsIhAoWzp3">3</a>]. But how about when fetching data streams?</p><p>Here is where Flow comes into play. If you want to fetch real-time updates from your server, you can do this with Flow without any concern of leaking resources since structured concurrency forces you to do so.</p><p>Let’s convert our repository so that it returns Flow.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/15e4d5c6fc10b50bf3af88ea56137a11/href">https://medium.com/media/15e4d5c6fc10b50bf3af88ea56137a11/href</a></iframe><p>Now, we are able to return multiple values from a suspend function. You can use <em>asLiveData</em> extension function to convert Flow to LiveData in ViewModel.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/32d5dc491889f442a300ce67fe26b606/href">https://medium.com/media/32d5dc491889f442a300ce67fe26b606/href</a></iframe><p>This looks pretty much the same as using LiveData since there is no data transformation. Let’s see fetching real-time updates from the repository.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/73e18f0fe43da5d8ce6ec35573341001/href">https://medium.com/media/73e18f0fe43da5d8ce6ec35573341001/href</a></iframe><p>When you are fetching real-time weather forecast data, all data transformation inside map function will be done asynchronously with the scope in which Flow is collected.</p><blockquote>Note: You can achieve the same functionality for data transformation by using liveData builder if you are not using Flow in the repository.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0a24646fa02f7333f6fe80bbb3b7f858/href">https://medium.com/media/0a24646fa02f7333f6fe80bbb3b7f858/href</a></iframe><p>To get back to real-time data fetch with Flow again, we can see that it is not blocking the UI by updating the text field while observing the data stream.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7374401763bd18ede46fe97c58645bc2/href">https://medium.com/media/7374401763bd18ede46fe97c58645bc2/href</a></iframe><p>Then it will look like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/540/1*CuYol8OE5mRYMI3mgBtYuw.gif" /><figcaption>Updating text while observing data stream</figcaption></figure><h4>Changing the theme of your app with Flow 🌈</h4><p>Since Flow can emit real-time updates, we can think of user input as an update and send it through Flow. In order to do that, let’s create a theme data source that has a theme channel for broadcasting updates.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2beb641e82e8173dd97078fea2be756b/href">https://medium.com/media/2beb641e82e8173dd97078fea2be756b/href</a></iframe><p>As you see, there is no direct access to themeChannel from outside. themeChannel is converted to Flow before it is sent.</p><p>It is better to consume theme updates in activity level since all updates from other fragments can be safely observed.</p><p>Let’s fetch the theme updates in ViewModel:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/437c37fce94f0de2f4cc12b91b2fc6a5/href">https://medium.com/media/437c37fce94f0de2f4cc12b91b2fc6a5/href</a></iframe><p>And it can easily be observed in the activity:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0ac50ce42a665c127f9e651984723e28/href">https://medium.com/media/0ac50ce42a665c127f9e651984723e28/href</a></iframe><p>The only thing left is to push the button in the fragment ⏯</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dd9e46fe25d3adaa6c8ff3907c5b3948/href">https://medium.com/media/dd9e46fe25d3adaa6c8ff3907c5b3948/href</a></iframe><p>Voilà! Just changed the theme with Flow 🔥</p><figure><img alt="Changing the app theme with using Flow" src="https://cdn-images-1.medium.com/max/540/1*ylRyOUT94hRDuhnZ-0xObA.gif" /></figure><h4>What’s next</h4><p>In this post, we have seen how to use Flow for repository and LiveData for ViewModel in MVVM architecture. Also, we changed the app theme using Flow &amp; LiveData.</p><p>In the next post, I will be explaining about using <strong>only</strong> Flow in all layers. Stay tuned!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a98fe06077a0" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/using-livedata-flow-in-mvvm-part-i-a98fe06077a0">Using LiveData &amp; Flow in MVVM — Part I</a> was originally published in <a href="https://proandroiddev.com">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>