<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ androiddev - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ androiddev - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 25 May 2026 05:06:44 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/androiddev/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Add Swipe Animations to a CardView in an Android App ]]>
                </title>
                <description>
                    <![CDATA[ By Gourav Khunger If you're building an Android app, you should consider adding animations. They can improve your app's user experience and increase retention.  These days, if you see an app that has no animation, it can feel odd and out-dated. And s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/add-swipe-animations-to-a-card-view-in-android-app/</link>
                <guid isPermaLink="false">66d45edb052ad259f07e4ad2</guid>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ androiddev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kotlin ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 15 Nov 2021 16:09:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/11/Swiping-Animation-Android-Views.gif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Gourav Khunger</p>
<p>If you're building an Android app, you should consider adding animations. They can improve your app's user experience and increase retention. </p>
<p>These days, if you see an app that has no animation, it can feel odd and out-dated. And since interactive experiences are kind of the new norm, you'll want to figure out ways to set your app apart.</p>
<h2 id="heading-what-well-build-here">What We'll Build Here</h2>
<p>Now, it might seem difficult to make your app stand out if you just have something basic like a quote sharing app (which is what we are going to work on here). It can be hard to hook the user and keep them interested.</p>
<p>Of course, you could just add two simple buttons to load the next/previous quote and call it a day. But that's pretty basic and any app could do that! Even if you're just building a simple side-project, there's no trade-off for good UX :)</p>
<p>So what we'll do in this tutorial is drop the buttons, and instead have logic where a user can swipe the card to the left. When they've swiped far enough, the app will load a new card with a new quote.</p>
<p>By the end of this post, you will learn how to make a really smooth animated card which a user can swipe that can perform whatever action you choose. Here's a demo of how it works:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/iHxFjvI4x.gif" alt="Animation showing smooth slide to refresh swiping animation on a android cardview." width="600" height="400" loading="lazy"></p>
<p>Amazing, right? Let's get into it!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>For this tutorial, we will use Kotlin as the programming language for our app – but you can easily translate the code to Java and it would work the same.</p>
<p>For reference, this is the quote card that we wish to enable the swipe feature on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/9CVHyoJfV.png" alt="Android card view with a quote." width="600" height="400" loading="lazy"></p>
<p>It is an androidX <code>CardView</code> with a bunch of <code>TextView</code>s and an <code>ImageView</code>. There's also a <code>ProgressBar</code> that gets shown while loading a new quote.</p>
<p>We won't be making the XML code for the user interface. You can <a target="_blank" href="https://github.com/gouravkhunger/QuotesApp/blob/main/app/src/main/res/layout/fragment_quote.xml">get the layout</a> I used here from the GitHub repository, or build your own.</p>
<p><a target="_blank" href="https://github.com/gouravkhunger/QuotesApp">Here's the complete code</a> for our Quotes app, if you wish to check it out. It uses the MVVM design pattern, but this article doesn't rely on what pattern you use for the business logic of your app, as we'll just be working on the UI part.</p>
<p>Now, we're ready to make that awesome swipe interface!</p>
<h2 id="heading-how-to-handle-swipes-in-our-app">How to Handle Swipes in Our App</h2>
<p>To handle swipes, we first need to set a touch listener on the card. Each time an action is performed on the card, the touch listener is called. Within the listener, we will add the logic to do the math and perform the animations.</p>
<p>Here is the blueprint of the touch listener we will be using:</p>
<pre><code class="lang-kotlin">quoteCard.setOnTouchListener(
    View.OnTouchListener { view, event -&gt;
        <span class="hljs-keyword">when</span> (event.action) {
            MotionEvent.ACTION_MOVE -&gt; {
                <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Handle ACTION_MOVE</span>
            }
            MotionEvent.ACTION_UP -&gt; {
                <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Handle ACTION_UP</span>
            }
        }

        <span class="hljs-comment">// required to by-pass lint warning</span>
        view.performClick()
        <span class="hljs-keyword">return</span><span class="hljs-symbol">@OnTouchListener</span> <span class="hljs-literal">true</span>
    }
)
</code></pre>
<p>Here, we are specifically listening for 2 actions on the card – the <code>ACTION_MOVE</code> and the <code>ACTION_UP</code>.</p>
<ul>
<li>The <code>ACTION_MOVE</code> event is called when a user starts swiping the card, that is, moving it.</li>
<li>The <code>ACTION_UP</code> is called when a user lifts their finger from the card, basically, when they release it.</li>
</ul>
<p>There are many other action events that we can override, such as <code>ACTION_DOWN</code> that's called when a person gets hold of the view, but we don't need them for this feature.</p>
<p>The basic setup for the card is done, so let's figure out the swiping logic.</p>
<h3 id="heading-the-math-behind-the-swipe-action">The math behind the swipe action</h3>
<p>First, let's re-think <strong>what we want to achieve</strong>. Implementing functionality is easier when you know exactly what you wish to have. Your code will also make more sense when your requirements are clear.</p>
<p>Here, we have a quote card. We want users to be able to swipe it only to the left, and if the minimum threshold to load a new quote is reached, it should move back to its original position and load a new quote.</p>
<p>Now, to achieve this, let's think of it in terms of the card. Let's define the mean position as the center of the card.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/dEnpWr7e4.png" alt="Mean Position of Quote Card" width="600" height="400" loading="lazy">
<em>Mean Position of the Card</em></p>
<p>We want the card to swipe if and only if the user swipes it to the left of the mean position.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/7epeWn53S.gif" alt="Animation illustrating user swipes to the left of the Quote Card" width="600" height="400" loading="lazy">
<em>Swipe only if moved towards the left of mean position</em></p>
<p>So how can we make this happen? </p>
<p>You guessed it – we will calculate the mean position and on the <code>ACTION_MOVE</code> event, we will check if the user swiped to the left and move the card accordingly.</p>
<h3 id="heading-how-to-implement-the-swipe-logic">How to implement the swipe logic</h3>
<p>To implement the logic, we first need to have the starting position of the card, which is fairly easy to calculate. We will just make sure that it is calculated with respect to the full-screen width, not just the card's width.</p>
<p>Place these lines of code before the <code>when(event.action)</code> statement:</p>
<pre><code class="lang-kotlin">quoteCard.setOnTouchListener(
    View.OnTouchListener { view, event -&gt;

        <span class="hljs-comment">// variables to store current configuration of quote card.</span>
        <span class="hljs-keyword">val</span> displayMetrics = resources.displayMetrics
        <span class="hljs-keyword">val</span> cardWidth = quoteCard.width
        <span class="hljs-keyword">val</span> cardStart = (displayMetrics.widthPixels.toFloat() / <span class="hljs-number">2</span>) - (cardWidth / <span class="hljs-number">2</span>)

        <span class="hljs-keyword">when</span> (event.action) {
            ...
        }
        ...
    }
)
</code></pre>
<p>First we get the <code>displayMetrics</code> from resources, which will give us the width of the screen using <code>displayMetrics.widthPixels.toFloat()</code>.</p>
<p>Then we get the <code>cardWidth</code> using the <code>width</code> property of the <code>quoteCard</code>.</p>
<p>Finally, we calculate the starting position of the card using the formula <code>(width of screen/2) - (cardWidth/2)</code>. Essentially, this gives us the x-coordinate of this position of the card:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/NiH3lsseM.gif" alt="Animation highlighting starting position of Quote Card" width="600" height="400" loading="lazy">
<em>Starting position of card.</em></p>
<p>Now, let's implement the code for the <code>ACTION_MOVE</code> event.</p>
<h3 id="heading-how-to-handle-the-actionmove-event">How to handle the <code>ACTION_MOVE</code> event</h3>
<p>Inside the <code>ACTION_MOVE</code> block, we first initialise the <code>newX</code> variable that holds the new x-coordinate that the card has been swiped to.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> newX = event.rawX
</code></pre>
<p><code>event.rawX</code> gives us the absolute value of the new coordinate with respect to the screen width.</p>
<p><code>newX</code> will contain the x-coordinate where the user's finger is, at any given moment. The value <code>0.0</code> for <code>newX</code> means that the user swiped to the left-most part of the screen. And for my emulator, <code>1080.0</code> represents the right-most edge of the screen.</p>
<p>Since, we want the card to swipe only if <code>newX</code> is less than the mean position of the card, we will place an if-condition here to verify that this is the case.</p>
<p>Think of this with simple values. Let's suppose that the mean position of the card is at x-coordinate <code>540.0</code> (small x-coordinate) and the user swipes to <code>710.0</code> (bigger x-coordinate). But we don't want them to be able to swipe to the right. And if the user swipes to <code>320.0</code> (smaller x-coordinate), then we need to carry out the swipe and move the card to the new position.</p>
<p>Here's the code to implement the above logic:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">if</span> (newX - cardWidth &lt; cardStart) { <span class="hljs-comment">// or newX &lt; cardStart + cardWidth</span>
    quoteCard.animate().x(
        min(cardStart, newX - (cardWidth / <span class="hljs-number">2</span>))
    )
    .setDuration(<span class="hljs-number">0</span>)
    .start()
}
</code></pre>
<p>We subtract <code>cardWidth</code> from <code>newX</code> because <code>newX</code> is an absolute value which is not relative to the card. It has a higher value because <code>cardStart</code> is towards the start of the screen, and <code>newX</code> is initially somewhere in the middle (a user would generally swipe from the middle).</p>
<p>We want to compare the value of <strong>shift</strong> in the x-coordinate and median to the value of <code>cardStart</code>, not the value of <strong><code>newX</code></strong>, so we take this into account by subtracting <code>cardWidth</code>.</p>
<p>Then, we carry out the animation using <code>quoteCard.animate()</code> and we change its x coordinate using the <code>x()</code> function.</p>
<p>Now, why do we do <code>min(cardStart, newX - (cardWidth/2))</code>?</p>
<p>This is very interesting and intuitive to understand. From the beginning, we are emphasizing that the card should move only to the left and not to the right. </p>
<p><code>newX - (cardWidth/2))</code> is nothing but the swiped distance towards the left (so subtraction is involved – for the right side, it should be added).</p>
<p>The <code>min()</code> function here returns the minimum of the two values provided. If the swiped distance is less than the <code>cardStart</code>, it is returned, otherwise <code>cardStart</code> is used. This is the condition we want to meet and <code>min()</code> makes it really easy to handle.</p>
<p><code>setDuration(0)</code> ensures that the animation is carried instantaneously (which keeps swiping from feeling laggy). <code>start()</code> actually starts the animation with the given properties.</p>
<p>This animation will clear any doubt your have on how this works:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/other.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Visualisation of the aforementioned concept</em></p>
<p>(I don't have expertise on making animations, this was the best I could come up with.)</p>
<p>Here is the final code for the <code>ACTION_MOVE</code> event:</p>
<pre><code class="lang-kotlin">MotionEvent.ACTION_MOVE -&gt; {
    <span class="hljs-comment">// get the new coordinate of the event on X-axis</span>
    <span class="hljs-keyword">val</span> newX = event.rawX

    <span class="hljs-comment">// carry out swipe only if newX - cardWidth &lt; cardStart, that is</span>
    <span class="hljs-comment">// the card is swiped to the left side, not to the right</span>
    <span class="hljs-keyword">if</span> (newX - cardWidth &lt; cardStart) {
        quoteCard.animate()
            .x(
                min(cardStart, newX - (cardWidth / <span class="hljs-number">2</span>))
            )
        .setDuration(<span class="hljs-number">0</span>)
        .start()
    }
}
</code></pre>
<p>You can also include a <code>TextView</code> to the UI that reflects when the user should release the card. Place this code inside the above <code>if</code> statement too:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">if</span> (quoteCard.x &lt; MIN_SWIPE_DISTANCE) textView.text = getString(R.string.releaseCard)
<span class="hljs-keyword">else</span> textView.text = getString(R.string.infoText)
</code></pre>
<p>where <code>MIN_SWIPE_DISTANCE</code> is <code>-250</code>:</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// -250 produces best result, feel free to change to your liking</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> MIN_SWIPE_DISTANCE = -<span class="hljs-number">250</span> <span class="hljs-comment">// User should move alteast -250 from mean position to load new quote</span>
</code></pre>
<p>Now, the <code>ACTION_MOVE</code> event is handled properly. Let's write the code to handle the <code>ACTION_UP</code> event, that is, when the card is released.</p>
<h3 id="heading-how-to-handle-the-actionup-event">How to handle the <code>ACTION_UP</code> event</h3>
<p>For the <code>ACTION_UP</code> event, we want the card to come back to its original position, wait for about <code>100</code> milliseconds, then load a new quote.</p>
<p>The logic to animate the card is similar, but this time we will make its animation duration about <code>150</code> millisecond to make it look smooth.</p>
<p>First, create a variable <code>currentX</code> that holds the current value of the x coordinate of the quote card. We'll use this variable later.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">var</span> currentX = quoteCard.x
</code></pre>
<p>Then, start the animation on the card. Pass the <code>cardStart</code> variable to the <code>x()</code> function to make it return to its original position and set the duration to <code>150</code>.</p>
<pre><code class="lang-kotlin">quoteCard.animate()
    .x(cardStart)
    .setDuration(<span class="hljs-number">150</span>)
<span class="hljs-comment">// continued below</span>
</code></pre>
<p>This time, we set a listener on the animation. A listener is something that keeps an eye on the animation. By using it, we can perform actions on various animation events such as start, end, resume, and more.</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// continuation</span>
.setListener(
    <span class="hljs-keyword">object</span> : AnimatorListenerAdapter() {
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAnimationEnd</span><span class="hljs-params">(animation: <span class="hljs-type">Animator</span>)</span></span> {
            viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
                delay(<span class="hljs-number">100</span>)
                <span class="hljs-comment">// check if the swipe distance was more than</span>
                <span class="hljs-comment">// minimum swipe required to load a new quote</span>
                <span class="hljs-keyword">if</span> (currentX &lt; MIN_SWIPE_DISTANCE) {
                    <span class="hljs-comment">// Add logic to load a new quote if swiped adequately</span>
                    viewModel.getRandomQuote()
                    currentX = <span class="hljs-number">0f</span>
                }
            }
        }
    }
)
.start()
</code></pre>
<p>We set a listener to look for the ending of the animation by overriding the <code>onAnimationEnd()</code> function. </p>
<p>As soon as the animation ends, we launch a coroutine (similar to Threads in Java but much more efficient) with a delay of 100 milliseconds. It then checks if the user had swiped further than the <code>MIN_SWIPE_DISTANCE</code> needed to load a new quote. The variable <code>currentX</code> is used for the comparison here.</p>
<p>If the user actually swipes passing the minimum distance, the coroutine is delayed for <code>100</code> milliseconds. Then the view model loads a new random quote from the API, also resetting the <code>currentX</code> variable to <code>0f</code>.</p>
<p>The final code for the <code>ACTION_UP</code> event looks like this:</p>
<pre><code class="lang-kotlin">MotionEvent.ACTION_UP -&gt; {
    <span class="hljs-keyword">var</span> currentX = quoteCard.x
    quoteCard.animate()
        .x(cardStart)
        .setDuration(<span class="hljs-number">150</span>)
        .setListener(<span class="hljs-keyword">object</span> : AnimatorListenerAdapter() {
            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAnimationEnd</span><span class="hljs-params">(animation: <span class="hljs-type">Animator</span>)</span></span> {
                viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
                    delay(<span class="hljs-number">100</span>)
                    <span class="hljs-comment">// check if the swipe distance was more than</span>
                    <span class="hljs-comment">// minimum swipe required to load a new quote</span>
                    <span class="hljs-keyword">if</span> (currentX &lt; MIN_SWIPE_DISTANCE) {
                        <span class="hljs-comment">// Add logic to load a new quote if swiped adequately</span>
                        viewModel.getRandomQuote()
                        currentX = <span class="hljs-number">0f</span>
                    }
                }
            }
        })
        .start()
    textView.text = getString(R.string.infoText)
}
</code></pre>
<h2 id="heading-final-code">Final Code</h2>
<p>This is the final code for the complete <code>onTouchListener()</code>:</p>
<pre><code class="lang-kotlin">quoteCard.setOnTouchListener(
    View.OnTouchListener { v, event -&gt;

        <span class="hljs-comment">// variables to store current configuration of quote card.</span>
        <span class="hljs-keyword">val</span> displayMetrics = resources.displayMetrics
        <span class="hljs-keyword">val</span> cardWidth = quoteCard.width
        <span class="hljs-keyword">val</span> cardStart = (displayMetrics.widthPixels.toFloat() / <span class="hljs-number">2</span>) - (cardWidth / <span class="hljs-number">2</span>)

        <span class="hljs-keyword">when</span> (event.action) {
            MotionEvent.ACTION_UP -&gt; {
                <span class="hljs-keyword">var</span> currentX = quoteCard.x
                quoteCard.animate()
                    .x(cardStart)
                    .setDuration(<span class="hljs-number">150</span>)
                    .setListener(
                        <span class="hljs-keyword">object</span> : AnimatorListenerAdapter() {
                            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAnimationEnd</span><span class="hljs-params">(animation: <span class="hljs-type">Animator</span>)</span></span> {
                                viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Default) {
                                    delay(<span class="hljs-number">100</span>)

                                    <span class="hljs-comment">// check if the swipe distance was more than</span>
                                    <span class="hljs-comment">// minimum swipe required to load a new quote</span>
                                    <span class="hljs-keyword">if</span> (currentX &lt; MIN_SWIPE_DISTANCE) {
                                        <span class="hljs-comment">// Add logic to load a new quote if swiped adequately</span>
                                        viewModel.getRandomQuote()
                                        currentX = <span class="hljs-number">0f</span>
                                    }
                                }
                            }
                        }
                    )
                    .start()
                textView.text = getString(R.string.infoText)
            }
            MotionEvent.ACTION_MOVE -&gt; {
                <span class="hljs-comment">// get the new co-ordinate of X-axis</span>
                <span class="hljs-keyword">val</span> newX = event.rawX

                <span class="hljs-comment">// carry out swipe only if newX &lt; cardStart, that is,</span>
                <span class="hljs-comment">// the card is swiped to the left side, not to the right</span>
                <span class="hljs-keyword">if</span> (newX - cardWidth &lt; cardStart) {
                    quoteCard.animate()
                        .x(
                            min(cardStart, newX - (cardWidth / <span class="hljs-number">2</span>))
                        )
                        .setDuration(<span class="hljs-number">0</span>)
                        .start()
                    <span class="hljs-keyword">if</span> (quoteCard.x &lt; MIN_SWIPE_DISTANCE) 
                        textView.text = getString(R.string.releaseCard)
                    <span class="hljs-keyword">else</span> textView.text = getString(R.string.infoText)
                }
            }
        }

        <span class="hljs-comment">// required to by-pass lint warning</span>
        v.performClick()
        <span class="hljs-keyword">return</span><span class="hljs-symbol">@OnTouchListener</span> <span class="hljs-literal">true</span>
    }
}
</code></pre>
<p>Congrats! In this tutorial, we've implemented animation that lets a user swipe a card containing a quote to get a new quote.</p>
<p>Don't forget to download the app and test it out yourself. Stars and contributions on the <a target="_blank" href="https://github.com/gouravkhunger/QuotesApp">GitHub repository</a> are welcomed!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Now you have learned how to animate a card and handle animation listeners on it. This helps create better UX that makes your app stand out.</p>
<p>Using the knowledge you gained in this post, you can now create most of the following animations for views in Android:</p>
<ul>
<li><strong>Programmatically create sliding animations for Android views.</strong></li>
</ul>
<p>Just as we did in this tutorial.</p>
<ul>
<li><strong>Left to right animation</strong></li>
</ul>
<p>This is fairly simple, just turn the subtraction in the variables to addition and <code>&lt;</code> signs in the <code>if</code> statements to <code>&gt;</code> signs. With these few tweaks here and there, the right to left animations in card view can be turned into left to right ones!</p>
<ul>
<li><strong>You can also show and hide views using animations.</strong></li>
</ul>
<p>For this, you have to keep track of the start position and end position then animate them with <code>alpha()</code> from <code>0</code> to <code>1</code>. For an example, you can refer to my library <a target="_blank" href="https://github.com/gouravkhunger/AccoLib">Accolib</a> to create animated FAQ accordions.</p>
<ul>
<li><strong>Basic animated layout changes can be achieved with view animations.</strong></li>
</ul>
<p>Thanks a lot for reading so far, I hope this post added some value. Subscribe to my newsletter at <a target="_blank" href="https://genicsblog.com">Genics Blog</a> to stay updated with my future articles!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An Introduction to Android Menus ]]>
                </title>
                <description>
                    <![CDATA[ There are three types of menus in Android: Popup, Contextual and Options.  Each one has a specific use case and code that goes along with it. To learn how to use them, read on. Each menu must have an XML file related to it which defines its layout. T... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/android-menus-introduction/</link>
                <guid isPermaLink="false">66ba4fd6cabb4cb0aaa837f1</guid>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ androiddev ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tomer ]]>
                </dc:creator>
                <pubDate>Wed, 03 Apr 2019 21:30:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9ca3ad740569d1a4ca5d36.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There are three types of menus in Android: Popup, Contextual and Options. </p>
<p>Each one has a specific use case and code that goes along with it. To learn how to use them, read on.</p>
<p>Each menu must have an XML file related to it which defines its layout. These are the tags associated with the menu option:</p>
<p><code>&lt;menu&gt;</code> - This is the container element for your menu (similar to LinearLayout)</p>
<p><code>&lt;item&gt;</code> - This denotes an item and is nested inside of the menu tag. Be aware that an item element can hold a <code>&lt;menu&gt;</code> element to represent a submenu</p>
<p><code>&lt;group&gt;</code> - This is used to signify a certain property or feature to a couple of menu items (I.E. state/visibility)</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">menu</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attr">xmlns:app</span>=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span>
    <span class="hljs-attr">xmlns:actionProviderClass</span>=<span class="hljs-string">"http://schemas.android.com/tools"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">item</span> <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/item1"</span>
        <span class="hljs-attr">android:icon</span>=<span class="hljs-string">"@drawable/ic_baseline_check_circle_24px"</span>
        <span class="hljs-attr">android:title</span>=<span class="hljs-string">"item1"</span>
        <span class="hljs-attr">app:showAsAction</span>=<span class="hljs-string">"always"</span>
        /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">item</span> <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/item2"</span>
        <span class="hljs-attr">android:icon</span>=<span class="hljs-string">"@drawable/ic_baseline_copyright_24px"</span>
        <span class="hljs-attr">android:title</span>=<span class="hljs-string">"item2"</span>
        <span class="hljs-attr">app:showAsAction</span>=<span class="hljs-string">"always"</span>
        /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">item</span> <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/item3"</span>
        <span class="hljs-attr">android:icon</span>=<span class="hljs-string">"@drawable/ic_baseline_favorite_24px"</span>
        <span class="hljs-attr">android:title</span>=<span class="hljs-string">"item3"</span>
        <span class="hljs-attr">app:showAsAction</span>=<span class="hljs-string">"always"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">item</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">menu</span>&gt;</span>
</code></pre>
<p>As shown in the code snippet above, each menu item has various attributes associated with it. I’ll detail the main ones here, but if you want to see what else you can add, go <a target="_blank" href="https://developer.android.com/guide/topics/resources/menu-resource.html">here</a>.</p>
<ul>
<li><strong>id</strong> - This is a unique identifier for the item in the menu. You can use this to see exactly which item the user clicked</li>
<li><strong>icon</strong> - If you want to show an icon associated with that menu item</li>
<li><strong>title</strong> - Text that will be shown in the menu for that item</li>
<li><strong>showAsAction</strong> - This attribute should only be used when using a menu in an activity that uses an <a target="_blank" href="https://developer.android.com/training/appbar/index.html">application bar</a>(or as it is also referred to, the action bar). It controls when and how this item should appear as an action in the application bar. There are five values: always, never, ifRoom, withText, and collapseActionView</li>
</ul>
<pre><code class="lang-xml">android:showAsAction="always|never|ifRoom|withText|collapseActionView"
</code></pre>
<p>I’ll elaborate on the meaning of each of these values in the next section.</p>
<p>In addition, you need to add the relevant onCreate menu method to your activity.</p>
<pre><code class="lang-java"><span class="hljs-comment">//Options Menu</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">onCreateOptionsMenu</span><span class="hljs-params">(Menu menu)</span> </span>{
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.options_menu, menu);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onCreateOptionsMenu(menu);
}

<span class="hljs-comment">//Context Menu</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreateContextMenu</span><span class="hljs-params">(ContextMenu menu, View v,
                                ContextMenu.ContextMenuInfo menuInfo)</span> </span>{
  <span class="hljs-keyword">super</span>.onCreateContextMenu(menu, v, menuInfo);
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.context, menu);
}
</code></pre>
<h2 id="heading-options-menu">Options Menu</h2>
<p>This menu is usually found at the top of your application and in it, you should place actions that affect the application as a whole. These could be the application’s settings or a search box.</p>
<p>Using the menu layout from above, we get the following options menu:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/1_OAoK8LfsBWCcfQmuZ-tYJQ.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As promised, let’s go over the values that can be given for the showAsAction attribute:</p>
<ul>
<li>always - will always show in the action bar</li>
<li>never - will never show, and therefore will be available through the <a target="_blank" href="https://www.techotopia.com/index.php/Creating_and_Managing_Overflow_Menus_on_Android">overflow menu</a></li>
<li>ifRoom - only if there is sufficient space in the action bar, then it would be shown. Keep in mind that per the documentation, there is a limit to how many icons you can have on the action bar.</li>
<li>withText-will include the item’s title in the action bar</li>
<li>collapseActionView - if this item has an action view associated with it, it will become collapsible(from API 14 and above)</li>
</ul>
<p>If we go ahead and change the last item in our menu to <strong><em>showAsAction=”never”</em></strong>, we get the following:</p>
<p><img src="https://miro.medium.com/max/789/1*D_7gZSLnlahTs1hCna76mw.jpeg" alt="Image for post" width="600" height="400" loading="lazy">
<em>The third menu item moved to the overflow menu</em></p>
<h2 id="heading-contextual-menu">Contextual Menu</h2>
<p>This menu appears when a user performs a long click on one of your UI elements. The options found in this menu affect what UI element the user made the click on. It is common to use this type of menu in list or grid views, where the user’s interaction with each item can lead to a specific action.</p>
<p><em>Imagine a scenario where you have an application with an image, and you want to present to the user several choices when they click on the image.</em></p>
<p>A context menu can appear in two ways :</p>
<ol>
<li>A floating menu</li>
<li>An action bar at the top of your application</li>
</ol>
<p>We will only demonstrate how to use the first option, but you can read more about the second option <a target="_blank" href="https://developer.android.com/guide/topics/ui/menus#CAB">here</a>.</p>
<p>Using the following XML:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">menu</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">item</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/share"</span>
        <span class="hljs-attr">android:title</span>=<span class="hljs-string">"Share"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">item</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/Mail"</span>
        <span class="hljs-attr">android:title</span>=<span class="hljs-string">"Mail"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">item</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/MoreInfo"</span>
        <span class="hljs-attr">android:title</span>=<span class="hljs-string">"More Information"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">menu</span>&gt;</span>
</code></pre>
<p>And adding the following code to our main activity:</p>
<pre><code class="lang-java"> <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> </span>{
       <span class="hljs-keyword">super</span>.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       TYPE_OF_LAYOUT layout = (TYPE_OF_LAYOUT)findViewById(R.id.main_layout);
       registerForContextMenu(layout);
  }
</code></pre>
<p>We will get the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/1_knvV4O1gDMNiW0n8z6TahQ.png" alt="Image" width="600" height="400" loading="lazy">
<em>When performing a long click on the text, the context menu appears</em></p>
<h2 id="heading-popup-menu">Popup Menu</h2>
<p>A popup menu is a type of menu that displays items in a vertical list. This list is attached to the view the user has clicked on to invoke this menu. It is important to keep in mind, that when choosing a popup menu, you do not want the user’s choice to affect the previous content the user pressed.</p>
<p>We will use the same menu XML layout as before, but we will need to add the following code to our activity:</p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">showPopupMenu</span><span class="hljs-params">(View view)</span> </span>{
  PopupMenu popup = <span class="hljs-keyword">new</span> PopupMenu(<span class="hljs-keyword">this</span>, view);
  MenuInflater inflater = popup.getMenuInflater();
  inflater.inflate(R.menu.actions, popup.getMenu());
  popup.show();
}
</code></pre>
<p>We will get the same result as the previous screenshot, but without the need for the user to perform a long click.</p>
<h2 id="heading-icons-in-popup-menus">Icons In Popup Menus</h2>
<p>Now I know what you are probably here for: <strong><em>you want to know how you can add icons to the menus</em></strong>.</p>
<p>While I will show an example of how to do this, it is wise to understand that this is a feature that is not enabled for popup menus and may cause unexpected behavior. You can achieve this by using reflection to turn on a flag called <strong>setForceShowIcon</strong>.</p>
<pre><code class="lang-java"><span class="hljs-comment">//popup is an instance of PopupMenu</span>

<span class="hljs-keyword">try</span> {
      Field[] fields = popup.getClass().getDeclaredFields();
      <span class="hljs-keyword">for</span> (Field field : fields) {
          <span class="hljs-keyword">if</span> (<span class="hljs-string">"mPopup"</span>.equals(field.getName())) {
              field.setAccessible(<span class="hljs-keyword">true</span>);
              Object menuPopupHelper = field.get(popup);
              Class&lt;?&gt; classPopupHelper = Class.forName(menuPopupHelper
                      .getClass().getName());
              Method setForceIcons = classPopupHelper.getMethod(
                      <span class="hljs-string">"setForceShowIcon"</span>, <span class="hljs-keyword">boolean</span>.class);
              setForceIcons.invoke(menuPopupHelper, <span class="hljs-keyword">true</span>);
              <span class="hljs-keyword">break</span>;
          }
      }
  } <span class="hljs-keyword">catch</span> (Throwable e) {
      e.printStackTrace();
  }
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/1__UE6Zw86AlJ50OD6Gj2L7w.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I’ve just scratched the surface with Android menus, but hopefully, it is enough to inspire you to dig deeper.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Why your Push Notifications never see the light of day ]]>
                </title>
                <description>
                    <![CDATA[ By Neil Mathew Push Notifications fail on specific Android phones. Here’s why. I recently added support for Push Notifications in the Kayako App. I tested and shipped it. And I thought I did pretty good job. But then one by one, my users start commen... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-your-push-notifications-never-see-the-light-of-day-3fa297520793/</link>
                <guid isPermaLink="false">66c36779b737bb2ce707322f</guid>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ androiddev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ push notification ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 28 Oct 2017 18:55:46 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*1KfeXO-IedHQ9cUI83cV3g.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Neil Mathew</p>
<h4 id="heading-push-notifications-fail-on-specific-android-phones-heres-why">Push Notifications fail on specific Android phones. Here’s why.</h4>
<p>I recently added support for <a target="_blank" href="https://firebase.google.com/docs/cloud-messaging/">Push Notifications</a> in the <a target="_blank" href="https://play.google.com/store/apps/details?id=com.kayako.android.k5">Kayako App</a>. I tested and shipped it. And I thought I did pretty good job.</p>
<p>But then one by one, my users start commenting that the the app doesn’t show any notifications about 95% of the time. At first, I thought it was a mistake because the Push Notifications were working as intended on my emulator and devices. But as I dug deeper, it became clear how serious and valid this problem was. This was but the tip of the iceberg. Close to 50% of our Android app users were affected but only few informed us about it.</p>
<h3 id="heading-so-whats-the-problem">So, what’s the problem?</h3>
<p>Push Notifications are <strong>not</strong> working properly on specific Android phones.</p>
<p>I use the word ‘properly’ because users receive push notifications when the app is open but <a target="_blank" href="https://github.com/firebase/quickstart-android/issues/41">not when it is closed</a>, which defeats the purpose of push notifications.</p>
<p>I use the words ‘specific Android phones’ because this issue is noticed only on phones by manufacturers like Xiaomi, Oppo, One Plus, Vivo, Lenovo, Huawei, Samsung, and a few others.</p>
<h3 id="heading-why-is-this-happening-and-how-do-we-fix-it">Why is this happening and how do we fix it?</h3>
<p>To understand the problem, let’s first understand the Android UI and the expected behavior of Push Notifications.</p>
<p>On Android, we have three buttons at the bottom as part of the Navigation Bar. The square button, on click, opens the <strong>Recents</strong> screen. The <strong>Recents</strong> screen lists all the ongoing tasks or apps recently opened. We can clear these applications at any time, as shown below.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/VMda4Y0jAqWe3uv5jqChb4HzarB7g2ffPjU0" alt="Image" width="362" height="667" loading="lazy">
<em>Recents Screen</em></p>
<p>Yet on certain <a target="_blank" href="https://www.xda-developers.com/what-is-custom-rom-android/">stock ROMs</a> (Android operating system customized by device manufacturers), clearing an application kills that application and its background services. This is bad because we need background services to show Push Notifications.</p>
<p>When the server informs the Android device of a new Push Notification, it would normally re-start the application’s background services to show the notification to the user. That’s good because background services will automatically start to show push notifications.</p>
<p>The image below shows the expected behavior which is the case for vanilla ROMs. This is the original Android firmware that is not customized by manufacturers.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/vsgpo013XZS9sWzJO4yXmsRyZ7O8TsP8QinG" alt="Image" width="358" height="661" loading="lazy">
<em>Expected Push Notification Behavior</em></p>
<p>Yet despite this, some Android phones using the Kayako app are <strong>not</strong> receiving Push Notifications when the app is cleared from <strong>Recents</strong> screen. The reason is that phone manufacturers like Oppo, Xiaomi, and One Plus use a stock ROM that disables the re-starting of background services for most apps. This is bad because we’re back to where we started with no way to show Push Notifications.</p>
<p>Thankfully, these stock ROMs have a Settings page to enable the re-starting of background services. Although the auto-starting of background services are disabled by default, users can manually enable this feature by following some instructions. This is good because now background services can be automatically started to show Push Notifications. But, it’s an ugly solution because it involves some manual work that the user has to do.</p>
<p>The intentions of the manufacturers are to conserve battery and improve performance. The app users now have to open their settings app, navigate to the correct page, scroll through a list of apps, and then enable the feature for the Kayako app.</p>
<h4 id="heading-but-wait-why-dont-apps-like-gmail-and-slack-have-these-problems">But wait, why don’t apps like Gmail and Slack have these problems?</h4>
<p>Top-popular apps like Gmail, Slack and Whatsapp are whitelisted by these stock ROMs. That means these apps have auto-launch enabled for them by default.</p>
<p>However our app, along with many many others, have auto-launch disabled by default.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/m-OlwUJt4m7rnaN84273MxOWR5viXIcDORZr" alt="Image" width="751" height="787" loading="lazy">
<em>One Plus ‘Apps auto-launch’ Settings page</em></p>
<h4 id="heading-i-cant-find-the-settings-to-enable-auto-launch-where-are-they-located">I can’t find the settings to enable auto-launch. Where are they located?</h4>
<p>The steps to enable auto-launch for an app are different for different manufacturers. This is because this is not a native Android feature and is very specific to stock ROMs.</p>
<p>It should also be noted that the terminology used by each manufacturer is different. The auto-launch feature can be referred to as app auto-start, start-up manager, auto-start manager, app optimisation, protected apps, or background app management.</p>
<p>To make matters worse, the auto-launch settings page is not easy to find. For One Plus devices (using <a target="_blank" href="https://www.android.com/versions/nougat-7-0/">Nougat</a> or below), you need to open up Settings, click Apps, then the gear icon located on the toolbar, and then Apps Auto-launch under the Advanced sub-category at the very bottom.</p>
<h3 id="heading-alright-whats-the-solution">Alright, what’s the solution?</h3>
<p>In the end, the user will have to perform the steps manually. This can not be programmatically enabled for all devices. The best we can do is to make it as easy as possible for app users to do so.</p>
<h4 id="heading-create-a-support-article">Create a support article</h4>
<p><a target="_blank" href="https://www.freecodecamp.org/news/why-your-push-notifications-never-see-the-light-of-day-3fa297520793/undefined">Kelly O’Brien</a> and I wrote an article which makes an attempt to identify all the device manufacturers with this problem and explain the steps to enable Push Notifications on those devices. You can read about it <a target="_blank" href="https://support.kayako.com/article/1461-why-aren-t-push-notifications-working-on-my-android-app">here</a>.</p>
<h4 id="heading-inform-users-in-app">Inform users in-app</h4>
<p>As I mentioned before, not everyone takes the time out to complain. I can not expect users to contact the support team or search for the support article online. At the same time, there’s no easy way to automatically identify if Push Notifications aren’t working when the app is closed.</p>
<p>I decided to show a small footer on the Push Notifications Settings page where the article is available to the user at all times.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/t1U0ZBIa3qJG1hvdU1lQT9GO4tJg3N0q5JUY" alt="Image" width="437" height="771" loading="lazy">
<em>Push Notification Settings Page</em></p>
<h4 id="heading-open-the-concerned-settings-page-in-app">Open the concerned settings page in-app</h4>
<p>I’ve found many Stack Overflow answers like <a target="_blank" href="https://stackoverflow.com/questions/34149198/how-to-enable-auto-start-for-my-app-in-xiaomi-programmatically">this one</a> which recommend programmatically opening the concerned settings page by detecting your device manufacturer. While I like the idea, I have not implemented this. I haven’t had the chance to test if the device-specific code actually works which puts me at unease.</p>
<p>If you have other suggestions or ideas, I welcome them.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How modularization can speed up your Android app’s built time ]]>
                </title>
                <description>
                    <![CDATA[ By Nikita Kozlov Developers will continue to add new features throughout an application’s lifetime. More code means not only longer build times — it means longer incremental build time. For teams with big projects, waiting for new builds could eventu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-modularisation-affects-build-time-of-an-android-application-43a984ce9968/</link>
                <guid isPermaLink="false">66c34e7c4f7405e6476b0204</guid>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ androiddev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ gradle ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 20 Jan 2017 16:48:47 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*J-1MC3QGbIuwq4tb-yr-iA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nikita Kozlov</p>
<p>Developers will continue to add new features throughout an application’s lifetime. More code means not only longer build times — it means longer <em>incremental</em> build time.</p>
<p>For teams with big projects, waiting for new builds could eventually take up 10-15% of their workday. This not only wastes precious developer time — it also makes test-driven development extremely tedious, which hurts overall code quality.</p>
<p>Splitting an application into modules could be a solution to this problem. I was tempted to just split our codebase by feature, by layer, or in some other quick and obvious way. But first, I decided to create an experiment and collect some data, so I could make a better-informed decision. This article will explore the results I collected and my findings.</p>
<p>Before we dive into my experiment, I’d like to talk about the theory behind all this, and explain how we can decrease incremental build time.</p>
<h3 id="heading-a-bit-of-theory">A bit of theory</h3>
<p>When you create an Android application you have to have at least one <em>application</em> module, it is a module that applied the Gradle application plugin in his <em>build.gradle</em> file:</p>
<pre><code>apply plugin: <span class="hljs-string">'com.android.application'</span>
</code></pre><p>As a result of building this module you will get an .APK file.</p>
<p>One <em>application</em> module cannot depend on another. It can only depend on a <em>library.</em> It is the module that applied the Gradle library plugin:</p>
<pre><code>apply plugin: <span class="hljs-string">'com.android.library'</span>
</code></pre><p>As a result of publishing such a module you will get an .AAR file (Android Archive Library). Comparing to .JAR file .AAR has some Android-related things, for example, resources and Manifest.</p>
<p>Building process for any library or application module can be <em>roughly</em> split into five phases, that could be represented with a certain Gradle tasks:</p>
<ol>
<li><strong>Preparation of dependencies.</strong> During this phase Gradle check that all libraries this module depends on are ready. If this module depends on another one, that module would be built as well.</li>
<li><strong>Merging resources and processing Manifest.</strong> After this phase resources and Manifest are ready to be packaged in the result file.</li>
<li><strong>Compiling.</strong> This phase started with Annotation Processors, in case you use them. Then source code is compiled into byte code. If you are using AspectJ, weaving also happens here.</li>
<li><strong>Postprocessing.</strong> All Gradle tasks with a “transform” prefix are part of this phase. Most important ones are: <code>transformClassesWithMultidexlist</code> and <code>transformClassesWithDex</code><em>.</em> They produce .DEX files.</li>
<li><strong>Packaging and publishing.</strong> For libraries this stage means creating an .AAR file in the end, for applications — .APK.</li>
</ol>
<p>As I mentioned, our goal is to minimize incremental build time. It’s difficult to speed up all the phases in one experiment, so I decided to focus on the longest ones. For a project with a single module, those were the compiling and postprocessing phases. The merging resources and processing manifest phase can also sometimes be time-consuming, but if the Java code is untouched, than incremental build is quite fast.</p>
<p>We all know, that Gradle runs task in consequent builds only if input isn’t the same. It also doesn’t rebuild a module if it wasn’t changed. That leads to the following hypothesis:</p>
<blockquote>
<p>“The Incremental build time for a project with multiple modules is faster than for a single-module project, because only modified modules are recompiled.”</p>
</blockquote>
<p>All right, lets find out whether this is true!</p>
<h3 id="heading-experiment-setup">Experiment Setup</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/m8SaIngTlbZkpYa4eqzV1F8hdi26pco4kVfE" alt="Image" width="720" height="585" loading="lazy"></p>
<p>Project uses Gradle plugins v2.2.2. Minimal Android SDK is 15, that covers most of the devices according to <a target="_blank" href="https://developer.android.com/about/dashboards/index.html">API level dashboard</a>. All modules have a dependency on <em>Butterknife</em>, to make project a bit more “alive”, since all projects has external dependencies.</p>
<p>In all variants application module is called <em>“app”</em>, while library modules are called <em>“app2”</em>, <em>“app3”</em> and so on.</p>
<p>Each variant has in total around 100 packages 15,000 classes 90,000 methods. Assembled that is two DEX files, almost three. Generated code is dummy, to keep all the methods in the .APK file, minifying and shrinking were disabled.</p>
<p>All measurements was done with Gradle build-in profiler. To use it you just need to add “--profile” in the end of the command, like this:</p>
<pre><code>./gradlew assembleDebug --profile
</code></pre><p>As a result you will get a .HTML file with measurements.</p>
<p>For each setup I repeated each measurement 4 to 15 times, to make sure that my results were reproducible.</p>
<h4 id="heading-java-code-generator">Java Code Generator</h4>
<p>Writing all 15,000 classes by hand is time consuming, so I wrote a simple code generator in Python. It is available in <a target="_blank" href="https://gist.github.com/NikitaKozlov/ff9d8e65d9d880a2f35e1cac58a84990">Gist</a>. Below you can find a schema of the code it generates.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/OMOMY0Ji9nNhHYvfyKBdTcPmeC8fVujWWVYv" alt="Image" width="800" height="494" loading="lazy"></p>
<p>As you can see, every next generated method called the previous one, and every first method of the next class called the last method of the previous class. That makes code more coupled, and increased compilation time.</p>
<h4 id="heading-pure-java-modules">Pure Java modules</h4>
<p>I didn’t make a special experiments for pure Java modules. But I played with them a bit, and I can say that usually they are faster then Android ones. That happens because during build less tasks are executed, for example, there is no resources to merge.</p>
<p>If you’re interested in results for pure Java modules, please write a comment. Or you can clone the project from <a target="_blank" href="https://github.com/NikitaKozlov/GradleBuildExperiment">GitHub</a> and modify it according to your needs. But don’t forget that actual results depend on hardware. To be able to compare your results, please repeat some experiments in your environment as well.</p>
<h4 id="heading-small-losses-here-and-there">Small losses here and there</h4>
<p>It’s no surprise that doing something in parallel does slow down the build. Even having a second project open in Android Studio can make build 5–10% slower. Listening to music, watching YouTube, or browsing the internet increases the build time a lot! I personally saw a speeding up of a build process by up to 30% after just closing everything except Android Studio.</p>
<p>All experiments were done with only necessary browser tabs and a single Android Studio project open.</p>
<h3 id="heading-lets-do-the-experiment">Let’s do the experiment</h3>
<h4 id="heading-initial-state">Initial State</h4>
<p>As a starting point I took a project with a single module that contains all 15 000 classes. For this setup incremental build time is <em>1m 10s</em>.</p>
<h4 id="heading-3-modules">3 Modules</h4>
<p>First step is splitting one module into three: one application module and two library ones. Application module depends on libraries, but library modules are independent from one another. Each module has about 5 000 classes and 30 000 methods.</p>
<p>If changes are made only in application module, then build time is about 35 seconds. Almost 30 seconds win compare to initial state. But when one of library module is changed, even if application module is untouched, incremental build time grows to <em>1m 50s</em>. 40 seconds longer!</p>
<p>Let’s take a look into profile report and see what took so long:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/haPhcC7iI9R6lMmNaSTWm-sEQ3LzTZg8hI41" alt="Image" width="800" height="327" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/4RI8AzAfrQCPVsDjVRt009zHjGdaUPo30Rbk" alt="Image" width="800" height="112" loading="lazy">
<em>Profile report of an incremental build with changes in library module (“:app2”). Since application module (“:app”) depends on the library one, it is also recompiled.</em></p>
<p>In the screenshots above, you can see that most of the time was spent on building the library module. You might also notice that for library modules, both debug and release tasks were executed. Gradle wasted time executing two sets of tasks instead of one! This is why it took an extra 40 seconds longer than the single-module project.</p>
<p>We can avoid this and make this build even faster than our initial <em>1m 10s</em> by splitting our code into modules.</p>
<p>But that’s not the only problem. Let’s look into <em>how</em> our application module depends on library modules:</p>
<pre><code>dependencies {    compile project(path: <span class="hljs-string">':app2'</span>)    compile project(path: <span class="hljs-string">':app3'</span>)}
</code></pre><p>There’s an important problem in the code above: if a library is added like this, then the application always depends on the <em>release</em> variant, independent of it’s own build type. It also doesn’t matter which variant is chosen in Android Studio. Here’s what the <a target="_blank" href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication">Gradle Plugin User Guide</a> says about all this:</p>
<blockquote>
<p>By default a library only publishes its <em>release</em> variant. This variant will be used by all projects referencing the library, no matter which variant they build themselves. This is a temporary limitation due to Gradle limitations that we are working towards removing.</p>
</blockquote>
<p>Luckily, it’s possible to change the variant our application depends on.</p>
<p>First, add the following code to libraries’ <em>build.gradle</em> file. It will allow library to publish <em>debug</em> variant as well:</p>
<pre><code>android {    defaultConfig {        defaultPublishConfig <span class="hljs-string">'release'</span>        publishNonDefault <span class="hljs-literal">true</span>    }}
</code></pre><p>Second, application module should depend on library ones like this:</p>
<pre><code>dependencies {    debugCompile project(path: <span class="hljs-string">':app2'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"debug"</span>)    releaseCompile project(path: <span class="hljs-string">':app2'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"release"</span>)    debugCompile project(path: <span class="hljs-string">':app3'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"debug"</span>)    releaseCompile project(path: <span class="hljs-string">':app3'</span>, <span class="hljs-attr">configuration</span>: <span class="hljs-string">"release"</span>)}
</code></pre><p>Now the debug variant of our application depends on the debug variant of the libraries, and its release depends on their release. So lets make some changes to the module <em>app2</em> and rebuild it. After these changes, we can check our profile report again:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/khyDy7gT4Hd8SiCz7rfoDlarUfRyGRCINpXs" alt="Image" width="800" height="285" loading="lazy"></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/D-udP9Ns1gkbTFHdcLh0AE7MDlkYoNb3jJ66" alt="Image" width="800" height="110" loading="lazy"></p>
<p>The most significant difference is the absence of <em>:app2:packageReleaseJarArtifact,</em> which saves us about 15 seconds. In addition, the time is reshuffled a bit between rest of the tasks, and we end up with <em>1m 32s</em>. That is 18 seconds faster then before, but still 22 seconds slower then our initial configuration. For changes only in the application module, build time stays almost the same — <em>36 seconds</em> vs <em>35 seconds</em> in our previous configuration.</p>
<p>Unfortunately I didn’t found a proper explanation for why it builds both flavors. I hope that once this Gradle limitation is resolved, then this problem will just go away as well. The same issue is discussed in <a target="_blank" href="https://code.google.com/p/android/issues/detail?id=52962">AOSP Issue Tracker</a>.</p>
<p>I’m also planning to spend some time experimenting with Gradle tasks to find a workaround for this problem. One possible way is to exclude all release tasks for debug builds.</p>
<h4 id="heading-5-modules">5 Modules</h4>
<p>Obviously, build time depends on the amount of code. If you reduce amount of code by half then the build should also be roughly two times faster. If instead of 3 modules project is split in 5, then build time should be approximately 40% faster.</p>
<p>It is almost true.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/JsR7H3b6U9J49HLLY6rV5BCsNnuCQIT0O4rx" alt="Image" width="800" height="277" loading="lazy"></p>
<p>If changes are made only in application module then incremental build time is approximately 24<em>s.</em> For changes in a library module incremental build takes <em>50s</em>. Compare to initial <em>1m 10s</em> that is already a win. But I have a few more tricks at my disposal.</p>
<h4 id="heading-reduce-size-of-the-application-module">Reduce Size of The Application Module</h4>
<p>Independently of what module is changed, application module will be recompiled every time. So reducing it’s size makes total sense. Ideally, it should just assemble whole application from a separate modules and might also provide a splash screen, because splash screen often depends on lots of features.</p>
<p>That is how idea about <em>3+1</em> and <em>5+1</em> configurations was born. In both cases project has a small application module that depends on 3 and 5 library modules accordingly. All library modules are independent from one another and has equal sizes. Let’s see what that gives us:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/e5AZF2lz4WsblcBuK1WA94CRadMgF7lPrjr-" alt="Image" width="800" height="405" loading="lazy"></p>
<p>We can observe further drop in incremental build time. Even with changes in library module <em>5+1</em> configuration is build almost twice as fast as an initial single-module project. This is a decent progress.</p>
<h4 id="heading-why-does-project-actually-depends-on-butterknife">Why does project actually depends on Butterknife?</h4>
<p>This is a point where I have to make a confession. There was one very strong reason to add a dependency on <em>Butterknife</em>.</p>
<p>In the initial configuration incremental compilation takes <em>45s</em> out of <em>1m 10s</em>, but if <em>Butterknife</em> is removed then project is compiled in <em>15s</em> only! Three times faster! Whole incremental build without Butterknife is <em>40s</em>.</p>
<p>Is it a problem in the library?</p>
<p>As it appeared — no. Without <em>Butterknife</em> project compiles so fast because of actual Java incremental compilation, which is disabled for projects that use Annotation processors. You can find related issues in <a target="_blank" href="https://issues.gradle.org/browse/GRADLE-3259">Gradle Jira</a>, in <a target="_blank" href="https://code.google.com/p/android/issues/detail?id=200043">AOSP Issue Tracker</a>, it is also tracked in Gradle <a target="_blank" href="https://github.com/gradle/gradle/blob/master/design-docs/incremental-java-compilation.md">design docs</a>. If you will take a closer look into the issue from ASOP Issue Tracker, one of the comment says:</p>
<blockquote>
<p><em>“Annotation processors is not yet supported with incremental java compilation. It will depend on changes in Gradle.</em></p>
<p><em>We disabled it for project that apply com.neenbedankt.android-apt, so it's no longer a significant issue.”</em></p>
</blockquote>
<p>That is why build just becomes slower without a notification.</p>
<p>Personally I won’t remove Annotation processors from the whole project. I find libraries like <em>Dagger</em> and <em>Butterknife</em> useful. But having a couple of modules without them could be a good idea, that would make their builds so much faster!</p>
<h4 id="heading-one-more-trick-rump-up-api-level">One More Trick — Rump Up API Level</h4>
<p>Compilation is not the only thing that slows down build process. Producing .DEX files could also be time consuming. Especially if an application is above DEX Limit. Using multidex configuration increases build time, build system need to decided which classes go to which .DEX file. With introduction of Android Runtime the way how Android OS works with application that has multiple DEX files has changed. This is what <a target="_blank" href="https://developer.android.com/studio/build/multidex.html#mdex-on-l">Android Studio documentation</a> says about it:</p>
<blockquote>
<p><em>“Android 5.0 (API level 21) and higher uses a runtime called ART which natively supports loading multiple DEX files from APK files. ART performs pre-compilation at app install time which scans for <code>classesN.dex</code> files and compiles them into a single <code>.oat</code> file for execution by the Android device.”</em></p>
</blockquote>
<p>That leads to decrease in build time. The reason is that each module produces its own DEX files, that are included into APK without modification. If you take a look into the tasks that run during build, you will notice that <code>transformClassesWithMultidexlist</code> is no longer executed. Also compilation itself became faster. You can find more information and instructions how to make a flavor that uses API 21 <a target="_blank" href="https://developer.android.com/studio/build/multidex.html#dev-build">here</a>.</p>
<h4 id="heading-fastest-build-configuration-achieved">Fastest Build Configuration Achieved.</h4>
<p>Using API 21 for debug is an easy gain for every project. I tried it for <em>5+1</em> configuration and results were amazing:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/odoCUKJg-NQm9vl4yJKfZfh7jLCsxqEPqRAS" alt="Image" width="800" height="279" loading="lazy"></p>
<p>Even for changes in library module incremental build time was only <em>17 seconds</em>! But take into account that all modules are independent from one another. Once dependency between modules is introduced, build time increases from <em>17s</em> to <em>42s</em> (last row in the table above)!</p>
<h4 id="heading-developing-library-module-in-a-test-driven-way">Developing Library Module in a Test Driven Way</h4>
<p>One of the main reasons why test-driven development (TDD) is difficult for single-module project is build time. TDD encourage to run test often. Running tests multiple times in a minute is a normal practice. But when build takes a minute or two, working in Test Driven way couldn’t be very productive.</p>
<p>With introduction of modules that problem is automagically resolved. Building a single module in the last configuration took only <em>9s</em>! It make possible to run tests as often as needed.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/8hhEYND4vfQGxgZ-NOcL8YVohRxBHLHqjm3G" alt="Image" width="720" height="675" loading="lazy"></p>
<p>First and most important, the hypothesis was correct, modularizing project can significantly speed up build process, but not for all configurations.</p>
<p>Second, if splitting is done in a wrong way, then build time will be drastically increased, because Gradle build both, release and debug version of library modules.</p>
<p>Third, working in test-driven way is much easier for a project with multiple modules, because building a small library module is way faster then the whole project.</p>
<p>Forth, doing many things in parallel slows down the build. So having more powerful hardware is a good idea.</p>
<p>Below you can find results of all experiments described in this article:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hxYQoAIaUGfb-dIVjjBmZVtiDyiPmpGyOOkw" alt="Image" width="800" height="601" loading="lazy"></p>
<p>Please vote for mentioned issues. Resolving any of those would be a huge step towards faster builds. Below you can find all links:</p>
<ul>
<li><a target="_blank" href="https://code.google.com/p/android/issues/detail?id=52962">https://code.google.com/p/android/issues/detail?id=52962</a></li>
<li><a target="_blank" href="https://issues.gradle.org/browse/GRADLE-3259"><em>https://issues.gradle.org/browse/GRADLE-3259</em></a></li>
<li><a target="_blank" href="https://code.google.com/p/android/issues/detail?id=200043">https://code.google.com/p/android/issues/detail?id=200043</a></li>
</ul>
<p>All code is published on <a target="_blank" href="https://github.com/NikitaKozlov/GradleBuildExperiment">GitHub</a>.</p>
<p><a target="_blank" href="https://twitter.com/Nikita_E_Kozlov"><strong>Nikita Kozlov (@Nikita_E_Kozlov) | Twitter</strong></a><br><a target="_blank" href="https://twitter.com/Nikita_E_Kozlov">_The latest Tweets from Nikita Kozlov (@Nikita_E_Kozlov): “https://t.co/wmGSJ7snW1"_twitter.com</a></p>
<p><em>Thank you for you time reading this article. If you like it, don’t forget to click the</em> ? <em>below.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Hard-Earned Android Programming Experiences ]]>
                </title>
                <description>
                    <![CDATA[ By Arun (now voidmain.dev) This post, like Kent Beck says in his book Implementation Patterns, “…is based on a rather fragile premise that good code matters…”. But we all know that clean code matters as we’ve had to deal for so long with its lack. An... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/hard-earned-android-programming-experiences-361fbaaecd07/</link>
                <guid isPermaLink="false">66c34c1e93db2451bd44146e</guid>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ androiddev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Startups ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 07 Jul 2016 15:42:18 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*5v2uWjgpnjKka7rhTyxzmA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Arun (now voidmain.dev)</p>
<p>This post, like Kent Beck says in his book <strong>Implementation Patterns</strong><em>, “…is based on a rather fragile premise that good code matters…”.</em> But we all know that clean code matters as we’ve had to deal for so long with its lack. And so does Kent.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/D1y48LxFVLN-7DJq2e-GSt4r868LL7H45DCS" alt="Image" width="100" height="146" loading="lazy">
<em>Kent Beck</em></p>
<h4 id="heading-the-total-cost-of-owning-a-mess">The Total Cost of Owning a Mess</h4>
<p>A few years ago, like every naive Android developer working in an early-stage startup in India, I tried to “<em>hack”</em> real world problems, to “<em>disrupt the industry”</em> and to <em>put a “dent in the universe”</em>. Without a care in the world about good software design or architecture, I started writing code to build an Android app that would one day become one of the biggest consumer heath-care apps in India.</p>
<p>Sprint after sprint, hack after hack, features were built in a mad rush. <em>Build. Measure. Learn</em>. <em>Time-to-market</em> was important and every day mattered. Time flew by, we were growing at the rate of 1 team member every 6 months and the app had hit the million downloads mark.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hLHerHSI0WHhoNSBZ8iTKX7KjbmvHDmEv90H" alt="Image" width="646" height="209" loading="lazy">
<em>Our app’s Google Play store downloads and rating.</em></p>
<p>By this time, the app had stopped being trivial and it had become a <em>multi-tenant</em> client, if that’s even a thing. Features that would take hours when we started now took days, sometimes weeks. Every Activity was 1000+ lines of spaghetti code as Android inherently doesn’t worry too much about the separation of concerns. <strong>The total cost of owning a mess had significantly slowed us down.</strong></p>
<h4 id="heading-the-android-conundrum">The Android Conundrum</h4>
<p>The code looked ugly, <em>Activities</em> managed everything:</p>
<ul>
<li><em>Threading</em></li>
<li><em>I/O</em></li>
<li><em>Computation</em></li>
<li><em>Layouts</em></li>
<li><em>Config changes</em></li>
<li><em>What not</em></li>
</ul>
<p>After all, <em>Activities</em> are <em>Controllers</em>, right? Or are they <em>Views</em>? I didn’t know anymore.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/DmDdWfbf3wRAQaclKUYmFWXXcgEOZsrDOh2L" alt="Image" width="576" height="256" loading="lazy">
<em>MVC</em></p>
<h4 id="heading-the-grand-redesign-in-the-sky">The Grand Redesign In The Sky</h4>
<p>We needed to design the app in a way that changing a line of code somewhere did not break something somewhere else. The app had to be, as Uncle Bob says, <em>“robust but not rigid, flexible but not fragile”</em>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/IfUwvie1Hd9-7z1AqmI7VATBu3Mct0kjXXvE" alt="Image" width="100" height="116" loading="lazy">
<em>Robert “Uncle Bob” Martin</em></p>
<p>This was when my mentor and friend <a target="_blank" href="https://www.freecodecamp.org/news/hard-earned-android-programming-experiences-361fbaaecd07/undefined">Kashif Razzaqui</a> joined the team to help us alleviate the mess. The grand redesign never happened, but we refactored the hell out of our code:</p>
<ul>
<li>We added a “<em>service”</em> layer and moved all the non-UI code into them, one service at a time.</li>
<li>We chucked <em>AsyncTasks</em> and moved to <em>ListenableFutures</em> using <em>Guava</em>.</li>
<li>We dumped <em>AsyncHttpClient</em> for <em>OkHttp.</em></li>
<li>But more importantly, we started reading a lot: Clean Code, Clean Architecture, SOLID, DRY, The Pragmatic Programmer, Java Concurrency In Practice, Domain Driven Design, etc.</li>
</ul>
<p>Soon we started seeing the benefits of our efforts. Productivity increased, we were writing things faster, everyone was happy.</p>
<p>This was until we unified our apps and all hell broke lose. Just having an additional <em>service</em> layer didn’t cut it.</p>
<h4 id="heading-the-art-of-clean-code">The Art of Clean Code</h4>
<p>After watching Uncle Bob’s videos on <a target="_blank" href="https://www.youtube.com/results?search_query=clean+architecture&amp;page=&amp;utm_source=opensearch">Clean Architecture</a> multiple times and reading a lot on Android app architecture, I decided to experiment with the <a target="_blank" href="https://github.com/esoxjem/MovieGuide">MVP design pattern and RxJava</a>.</p>
<p>A few days into the experimentation, we decided to switch to <em>RxJava</em> and implement <em>MVP using Clean Architecture</em>. We made sure we encapsulated all layers behind interfaces and separated concerns well.</p>
<ul>
<li><em>The View,</em> usually implemented by a Fragment, contains a reference to the presenter. The only thing that the view will do is to call a method from the Presenter every time there is an interface action.</li>
<li><em>The Presenter</em> is responsible to act as the middle man between <em>View</em> and <em>Model</em>. It retrieves data from the Model and returns it formatted to the View. But unlike the typical MVC, it also decides what happens when you interact with the View.</li>
<li><em>The Model</em> is only the gateway to the <em>domain</em> <em>layer</em> or <em>business logic.</em></li>
<li><em>The Interactor</em> deals with I/O and is the provider of data to be displayed in the <em>View</em>.</li>
</ul>
<p>Now it’s much easier to switch out one layer with a completely new implementation. Redesigning the UI, a part and parcel of Android app development, has become much easier. Things can finally move fast without breaking.</p>
<h4 id="heading-the-boy-scout-rule">The Boy Scout Rule</h4>
<p>It’s not enough to write code well, the code has to be <strong>kept clean</strong> over time. The fact of life is that software has a tendency for <em>entropy</em>. We’ve all seen code rot and degrade over time so we borrowed the simple boy scouts rule: “<em>Leave the campground cleaner than you found it.”</em></p>
<p>If we all checked-in our code a little cleaner than when we checked it out, the code simply could not rot. The cleanup doesn’t have to be something big. Change one variable name for the better, break up one function that’s a little too large, eliminate one small bit of duplication, clean up one composite if statement.</p>
<h4 id="heading-conclusion">Conclusion</h4>
<p>Our way of building a scalable app might not be “<em>correct</em>” and you might not agree with this post. After all, not all martial artists agree about the best martial art, or the best technique within one ;)</p>
<p>There are many different approaches towards MVP and a lot of interesting solutions to adapt it to Android. The one fact that we can’t deny is that <em>Clean Code</em> matters and you just can’t sweep it under a rug.</p>
<p>This post borrows heavily from Uncle Bob’s <strong>Clean Code</strong> and steals the title from <a target="_blank" href="https://www.youtube.com/watch?v=dauMw_Bns0w"><em>Kashif’s Droidcon talk</em></a> from 2011.</p>
<p>If <em>Clean Code</em> matters to you, let’s chat :)<br>_Twitter: <a target="_blank" href="http://twitter.com/_arunsasi">@_arunsasi</a>_<br><em>LinkedIn:</em> <a target="_blank" href="https://www.linkedin.com/in/arunsasidharan">https://www.linkedin.com/in/arunsasidharan</a></p>
<h3 id="heading-if-you-liked-this-post-please-hit-the-little-heart">If you liked this post, please hit the little heart! ❤</h3>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
