<?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:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Since Last Commit]]></title><description><![CDATA[A collection of personal learning]]></description><link>https://blog.asadmansoor.com/</link><image><url>https://blog.asadmansoor.com/favicon.png</url><title>Since Last Commit</title><link>https://blog.asadmansoor.com/</link></image><generator>Ghost 4.1</generator><lastBuildDate>Tue, 31 Mar 2026 20:56:02 GMT</lastBuildDate><atom:link href="https://blog.asadmansoor.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Git Hooks for Android Development]]></title><description><![CDATA[<h3 id="what-are-git-hooks">What are Git Hooks?</h3><p>Git hooks are scripts that automatically run on a particular git event. These git events could be committing a change, checking out a branch or performing a rebase. Hence, making them an important mechanism to enhancing automation and removing tedious manual work that are prone to</p>]]></description><link>https://blog.asadmansoor.com/git-hooks-for-android-development/</link><guid isPermaLink="false">62a625dc79b9a519c85ece14</guid><category><![CDATA[Android]]></category><dc:creator><![CDATA[Asad Mansoor]]></dc:creator><pubDate>Mon, 13 Jun 2022 00:54:29 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1518432031352-d6fc5c10da5a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fGF1dG9tYXRpb258ZW58MHx8fHwxNjU1MDgxNjIx&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<h3 id="what-are-git-hooks">What are Git Hooks?</h3><img src="https://images.unsplash.com/photo-1518432031352-d6fc5c10da5a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fGF1dG9tYXRpb258ZW58MHx8fHwxNjU1MDgxNjIx&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Git Hooks for Android Development"><p>Git hooks are scripts that automatically run on a particular git event. These git events could be committing a change, checking out a branch or performing a rebase. Hence, making them an important mechanism to enhancing automation and removing tedious manual work that are prone to human error. In this blog post, we will explore three custom git hook implementations that can be added to an Android project that will not only enhance developer productivity but also increase automation throughout the development workflow. I highly encourage you to explore and customize these git hooks to match your needs.</p><p>Git hooks are files that are named in a certain way for git to start using them in the git workflow. To get started, create a .githooks folder in the root of the project. Then create the separate files for the desired git hook you wish to use. For example, if you want to run a command prior to a commit, you can create a file named pre-commit in the .githooks folder, which will contain the implementation on what needs to be executed. Then whenever a commit is being made, the pre-commit hook will run the script and create the commit only if the script has passed. In this blog post, we will create three files named pre-commit, commit-msg and post-commit respectively. Since we are adding them to the .githooks folder, we can push these to the remote source control repository to share them with the team.</p><p>Once the .githooks folder is created with all three git hook files, ensure that they have the permission to be executed. The next step is to configure the hooksPath to allow git to target this folder when running the git hooks for the repository. Open the terminal and navigate to the root of the project, then execute the following command shown in step 2.</p><!--kg-card-begin: markdown--><h3 id="step-1create-the-folder-and-files">Step 1 - Create the folder and files</h3>
<pre><code>.githooks/
  - pre-commit
  - commit-msg
  - post-commit
</code></pre>
<h3 id="step-2configure-git-to-use-this-folder">Step 2 - Configure git to use this folder</h3>
<pre><code>git config core.hooksPath .githooks
</code></pre>
<!--kg-card-end: markdown--><h3 id="pre-commit">Pre-commit</h3><p>The pre-commit is a git hook that gets executed prior to a commit. Once the changes have been added and a git message is provided, git will execute the pre-commit script. If the script has finished successfully, then it would proceed to making the commit. However, if the script has failed, the commit would not be created. This is extremely useful if you wish to perform additional verification on the changes prior to creating a commit on your local machine.</p><p>From prior experience, the lint task is usually the step that often fails a pipeline. Whether it is a code formatting issue or an unused import that has been added, it can be quite annoying to wait for the CI pipeline to finish to indicate whether the pull request has any lint issues. Rather than relying on the lint check on the CI pipeline, which can take a lot of resources and long time to process, the lint check can be executed on the local machine using the pre-commit hook. If no lint issues are present in the new changes, it will proceed with the commit. Or else, it will alert the developer that lint issues are present and the fix is required before a commit can be created. This will significantly<strong> reduce the feedback loop from minutes to just seconds</strong>. To run the link check in your pre-commit hook, check out the code below in step 3. </p><p>Note: pre-commit hooks can be used for anything, so feel free to use a different linter, such as ktlint or detekt, or perform a different task such as building the app or running unit tests. However, the pre-commit checks should be a quick and small task since they are expected to be executed every time a commit has been made.</p><!--kg-card-begin: markdown--><h3 id="step-3create-a-pre-commit-file-and-add-the-lint-check">Step 3 - Create a pre-commit file and add the lint check</h3>
<pre><code>#!/bin/sh
#
# An example hook script to verify that the changes do not contain
# any lint issues. The hook will prevent a commit to be made if the
# status of the lint task is a non-zero result.
# To enable this hook, the file has to be named &quot;pre-commit&quot;.

# Run Android Lint
./gradlew lintDebug
status=$?

# Display messaging based on the result
if [ $status -eq 0 ]; then
  echo &quot;=======================================================&quot;
  echo &quot;Pre-commit check passed. Changes will now be committed.&quot;
  echo &quot;=======================================================&quot;
else
  echo &quot;=======================================================&quot;
  echo &quot;Pre-commit check failed. Changes include lint issues.&quot;
  echo &quot;=======================================================&quot;
fi
exit $status
</code></pre>
<!--kg-card-end: markdown--><h3 id="commit-msg">Commit-msg</h3><p>The commit-msg hook is a git hook that executes a script whenever a commit message has been entered. The script is provided the path of a temporary file that contains the proposed git message. This is the perfect place to validate the commit message. If the git commit does not the meet the standard set by the team, the commit-msg could fail the script and prevent the commit to be made. This is a great and easy way to align the team to use a specific git commit structure.</p><p>An example of a commit-msg hook could be to examine the commit message that is going to be added and determine if it includes vital information, such as the corresponding ticket number. Since most teams use some sort of project management tool, such as Jira, all tasks need to be associated with a ticket number. This can be a useful technique for debugging which commits belong to which tasks when parsing the develop or main branch. Ideally, not much work should be included in this git hook apart from checking the git commit (consider using post-commit instead). The code in step 4 shows an example of a commit-msg hook that parses the commit message and validate if it starts with a ticket number.</p><!--kg-card-begin: markdown--><h3 id="step-4create-a-commit-msg-file-and-add-the-check">Step 4- Create a commit-msg file and add the check</h3>
<pre><code>#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by &quot;git commit&quot; with one argument, the name of the file
# that has the commit message.  The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit.
# To enable this hook, rename this file to &quot;commit-msg&quot;.

commit_msg=$(cat $1)

# Check if commit message starts with DROID. Replace with your ticket name.
if [[ $commit_msg == DROID-* ]]; then
  echo &quot;=======================================================&quot;
  echo &quot;Commit-msg check passed. Changes will now be committed.&quot;
  echo &quot;=======================================================&quot;
  exit 0
else
  echo &quot;=======================================================&quot;
  echo &quot;Commit-msg check failed. Commits must start with DROID-&quot;
  echo &quot;=======================================================&quot;
  exit 1
fi
</code></pre>
<!--kg-card-end: markdown--><h3 id="post-commit">Post-commit</h3><p>The post-commit hook is a git hook that executes a script after the commit has been created. The status of the hook, unlike the previous hooks, have no impact on the commit itself. It is ideally used in scenarios to notify or perform additional tasks after the commit has successfully been created. Example of this could be capturing the commit log statement from the previously created commit, building an app for distribution or notifying various stakeholders through some communication channel.</p><p>The example of the post-commit hook in this blog post is to build a release APK once a commit has been made on the release branch. These commits are usually updating the build version and name. Once the developer has updated the version and starts to make the release, they would often push the update to their CI/CD pipeline. In parallel, the post-commit hook could generate a release APK that can be distributed internally or stored in a specific directory on the local machine. However, automatic distribution to Firebase App Distribution or Google Play Console should be done on the CI/CD pipeline as it is more efficient and secure. The code in step 5 shows an example of a post-commit hook creating a release APK when a commit is made on a release branch. </p><!--kg-card-begin: markdown--><h3 id="step-5create-a-post-commit-file-and-add-the-check">Step 5 - Create a post-commit file and add the check</h3>
<pre><code>#!/bin/sh
#
# An example hook script to perform additional tasks during the
# post-commit flow. In this case, it creates a release APK if
# the commit has been made on the release branch.
# Status of this script does not impact the commit.
# To enable this hook, rename this file to &quot;post-commit&quot;.

branch_name=$(git symbolic-ref --short -q HEAD)

if [[ $branch_name == release* ]]; then
  echo &quot;=======================================================&quot;
  echo &quot;Performing post-commit hook. Building release APK...&quot;
  ./gradlew assembleRelease
  echo &quot;=======================================================&quot;
else
  echo &quot;===========================================================&quot;
  echo &quot;Committing on a non-release branch, skipping post-commit...&quot;
  echo &quot;===========================================================&quot;
fi

</code></pre>
<!--kg-card-end: markdown--><h3 id="conclusion">Conclusion</h3><p>Git hooks are a powerful tool to enhance automation within the codebase. Developers spend a lot of time performing manual tedious tasks that take them away from problem solving or adding any value to the business. With git hooks, some of the tasks can be done more quickly and efficiently on the local machine to boost developer productivity. Best of all, these hooks can be shared with the team which can help create a standard of practice when developing and maintaining an Android project. </p><p>Till next time, keep automating!</p>]]></content:encoded></item><item><title><![CDATA[Handling detekt lint issues on Android]]></title><description><![CDATA[<p>Detekt is a configurable lint tool for Kotlin that can be used to find code smells within your Android project. In the <a href="https://blog.asadmansoor.com/adding-detekt-to-your-android-project/">previous blog post</a>, we discussed how to integrate detekt in your project. Now we will explore what to do when we discover lint issues.</p><p><strong>Tip</strong> - detekt generates</p>]]></description><link>https://blog.asadmansoor.com/handling-lint-issues/</link><guid isPermaLink="false">614fc92279b9a519c85ecca2</guid><dc:creator><![CDATA[Asad Mansoor]]></dc:creator><pubDate>Thu, 30 Sep 2021 13:00:02 GMT</pubDate><content:encoded><![CDATA[<p>Detekt is a configurable lint tool for Kotlin that can be used to find code smells within your Android project. In the <a href="https://blog.asadmansoor.com/adding-detekt-to-your-android-project/">previous blog post</a>, we discussed how to integrate detekt in your project. Now we will explore what to do when we discover lint issues.</p><p><strong>Tip</strong> - detekt generates a report after the lint scan that includes the issue with code snippets as well as a suggestion to resolve it.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.asadmansoor.com/content/images/2021/09/Capture-1.PNG" class="kg-image" alt loading="lazy" width="738" height="814" srcset="https://blog.asadmansoor.com/content/images/size/w600/2021/09/Capture-1.PNG 600w, https://blog.asadmansoor.com/content/images/2021/09/Capture-1.PNG 738w" sizes="(min-width: 720px) 720px"><figcaption>Detekt lint report containing 117 issues.</figcaption></figure><p>When running detekt for the first time, you may encounter hundreds of lint issues like in the report shown above. This is fine! Normally, a software project accumulates technical debt over time. Instead of jumping to solve all of the issues in one go, let&apos;s break down different strategies you can use to deal with this situation.</p><p>When encountering any type of lint issue, you can</p><ol><li>Fix the issues that are critical or can be resolved easily</li><li>Disable or modify the rule to meet your specifications</li><li>Suppress the issue until it can be fixed at a later date</li></ol><p></p><h2 id="dealing-with-lint-issues">Dealing with lint issues</h2><h3 id="fix-the-issue">Fix the issue</h3><p>It may not be a good idea to try to solve all of the issues in the lint report. Instead, analyze which issues are critical or can be resolved easily. The goal of using a linter is to keep the project in a good state which includes resolving all of the current issues and preventing any issues being merged into the codebase. </p><p>For issues that are critical or can be resolved easily, simply implement the solution to satisfy the rule and re-run detekt to verify that the issue has been fixed.</p><p></p><h3 id="disable-or-modify-the-rule">Disable or modify the rule</h3><p>Not all issues will be important to your project. If you feel there is a rule that does not make sense to enforce, you can disable it through the configuration. This will prevent the lint scan from alerting you of this issue in the future, so use it with caution. You also have the ability to modify the threshold of a specific rule. Some rules can be customized to take on a lower or higher threshold value, so they will only alert if that particular threshold has been crossed.</p><p>Detekt uses the default ruleset upon integration. To disable or modify a rule, simply add the <a href="https://github.com/detekt/detekt/blob/main/detekt-core/src/main/resources/default-detekt-config.yml">default configuration file</a> into the project and make a reference of it in build.gradle file. Then make any changes to the configuration yml file and push it to the code repository. </p><p></p><!--kg-card-begin: markdown--><p>/** build.gradle (app) */</p>
<pre><code>detekt {
    // Define the detekt configuration(s) you want to use.
    // Defaults to the default detekt configuration.
    config = files(&quot;path/to/config.yml&quot;)
    ...
}
</code></pre>
<!--kg-card-end: markdown--><p><strong>Reference</strong>: <a href="https://detekt.github.io/detekt/configurations.html">https://detekt.github.io/detekt/configurations.html</a></p><p></p><h3 id="suppress-the-issue">Suppress the issue</h3><p>In the case where fixing or modifying the rule might not possible, you can suppress the issue until it can be fixed at a later date. This is the preferred alternative to disabling a rule, since it allows you keep scanning for that particular in future scans as well as keep track of the technical debt that has been accepted as of now. You can suppress an issue by adding the<a href="https://detekt.github.io/detekt/suppressing-rules.html"> suppress annotation</a> with the rule name in the class that contain the issue. All subsequent lint scans will not alert on that particular issue.</p><p>Another way to suppress issues is by adding it to the baseline. A baseline file is a file that tracks all of the current lint issues and ignores it for subsequent lint scans. This accepts the current technical debt and only alerts when new issues are being added to the codebase. Detekt can generate a baseline file for you by running the ./gradlew detektBaseline task in terminal. Once completed, make a reference of the file in the build.gradle file and push it to the code repository.</p><!--kg-card-begin: markdown--><p>/** build.gradle (app) */</p>
<pre><code>detekt {
    // Specifying a baseline file. All findings stored in this file in subsequent runs of detekt.
    baseline = file(&quot;path/to/baseline.xml&quot;)
    ...
}
</code></pre>
<!--kg-card-end: markdown--><p></p><h2 id="conclusion">Conclusion</h2><p>Setting up a lint tool can be a scary and overwhelming task, especially dealing with hundreds of lint issues. Once everything is set up, we can ensure that software quality will be maintained on the codebase. During the time of this blog post, I was able to fix 112 out of the 117 issues which were quite easy to fix. As for the remaining 5 issues, I added them to my baseline. With detekt in place, I can continue writing more code knowing that I am following the best practices and not introducing any code smells in the codebase. </p><p>That&apos;s a wrap! Stay tuned for more blog posts.</p>]]></content:encoded></item><item><title><![CDATA[Adding Detekt to your Android project]]></title><description><![CDATA[<figure class="kg-card kg-image-card"><img src="https://blog.asadmansoor.com/content/images/2021/09/carbon--3-.png" class="kg-image" alt loading="lazy" width="1296" height="732" srcset="https://blog.asadmansoor.com/content/images/size/w600/2021/09/carbon--3-.png 600w, https://blog.asadmansoor.com/content/images/size/w1000/2021/09/carbon--3-.png 1000w, https://blog.asadmansoor.com/content/images/2021/09/carbon--3-.png 1296w" sizes="(min-width: 720px) 720px"></figure><h2 id="overview">Overview</h2><p>There are a number of things that could slow down an Android dev team. It could be the time wasted troubleshooting a buggy codebase, navigating through an ill-structured set of classes and having to do a lot of refactoring to add new features. All of these correlate to how</p>]]></description><link>https://blog.asadmansoor.com/adding-detekt-to-your-android-project/</link><guid isPermaLink="false">613e3a0a79b9a519c85ecab3</guid><dc:creator><![CDATA[Asad Mansoor]]></dc:creator><pubDate>Fri, 17 Sep 2021 00:34:47 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card"><img src="https://blog.asadmansoor.com/content/images/2021/09/carbon--3-.png" class="kg-image" alt loading="lazy" width="1296" height="732" srcset="https://blog.asadmansoor.com/content/images/size/w600/2021/09/carbon--3-.png 600w, https://blog.asadmansoor.com/content/images/size/w1000/2021/09/carbon--3-.png 1000w, https://blog.asadmansoor.com/content/images/2021/09/carbon--3-.png 1296w" sizes="(min-width: 720px) 720px"></figure><h2 id="overview">Overview</h2><p>There are a number of things that could slow down an Android dev team. It could be the time wasted troubleshooting a buggy codebase, navigating through an ill-structured set of classes and having to do a lot of refactoring to add new features. All of these correlate to how well the product is implemented and the amount of technical debt it has accumulated throughout its time. Hence making software quality of the essential attributes to the success of a product.</p><p>When developing software products, teams often require feedback prior to merging code. This ensures the changes adhere to the best standards and follow specifications that encourage maintainability and flexibility of new requirements. The manual review process is an important act of collaboration which is an entry point to catching a lot of the technical issues that could impact users. Teams often use static code analysis tools that scan the codebase and highlight issues and warnings of bad implementation practices within the codebase. These automated checks are fast and reliable, hence reducing the feedback cycle and allowing better code to be merged into the code repository.</p><p>Linting on Android is no different than any other development framework. It can help you and your team with:</p><ul><li>Standardizing a coding design structure</li><li>Highlighting coding errors and bad practices</li><li>Calculating cyclomatic complexity</li><li>Prompting warnings of deprecated dependencies and unused resources</li><li>Pinpointing accessibility and localization issues (<em>and much more...</em>)</li></ul><p></p><blockquote>Linting - It&apos;s a second pair of eyes that provides additional insights on what can be improved in the codebase adhering to a high quality of software development.</blockquote><p></p><h2 id="detekt">Detekt</h2><p>Detekt is a configurable lint tool for Kotlin that can be used within your Android project. It comes with a predefined set of rules that analyzes potential code smells. Upon integrating detekt, a Gradle task is created that can run the analysis and output a report containing the list of current issues. This task can be executed locally and on a continuous integration (CI) pipeline. </p><p><strong>To integrate detekt in your project, make the following changes:</strong></p><!--kg-card-begin: markdown--><pre><code>/** build.gradle (project) */
plugins {
    id &quot;io.gitlab.arturbosch.detekt&quot; version &quot;1.18.1&quot;
}



/** build.gradle (app) */
apply plugin: &apos;io.gitlab.arturbosch.detekt&apos;

dependencies {
    // optional: additional formatting rules from ktlint
    detektPlugins(&quot;io.gitlab.arturbosch.detekt:detekt-formatting:1.18.1&quot;)
}

// detekt configuration block.
detekt {
    toolVersion = &quot;1.18.1&quot;
    basePath = projectDir
    reports {
        html { enabled = true }
        txt { enabled = false }
        xml { enabled = false }
    }
}

</code></pre>
<!--kg-card-end: markdown--><p>To run the detekt lint analysis, open the terminal and navigate to the project directory. Then execute <strong>./gradlew detekt</strong> </p><p></p><h2 id="lint-issues">Lint Issues</h2><p>After running detekt, you will see a lot of lint issues in the report. This is normal! By design, detekt is using the default ruleset which can be customized as well as allowing some rules to be disabled. Ideally, you should not try to fix all of the lint errors at once. Instead, analyze the lint report and determine which issues are important that need to be fixed and which can be turned off and ignored. With detekt, you can configure the threshold, disable a rule, suppress the issue within the codebase or add that issue to the baseline. More on this later.</p><p>Here is an example of what you can expect from your lint report.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.asadmansoor.com/content/images/2021/09/Capture.PNG" class="kg-image" alt loading="lazy" width="738" height="814" srcset="https://blog.asadmansoor.com/content/images/size/w600/2021/09/Capture.PNG 600w, https://blog.asadmansoor.com/content/images/2021/09/Capture.PNG 738w" sizes="(min-width: 720px) 720px"><figcaption>detekt html report</figcaption></figure><p>These reports are generated in the<strong> app/build/reports</strong> folder.</p><p></p><h2 id="advantages">Advantages</h2><p>A tool like detekt can recommend a lot of great suggestions in improving the quality of the codebase. Here are a few advantages of using detekt in your development workflow:</p><ul><li>Automatically find issues that could turn into potential bugs</li><li>Generates an useful report that provides additional insights </li><li>Allow team members to follow a standard when contributing to the codebase</li><li>Highly configurable ruleset that can be adjusted and turned off</li><li>Ability to fail the CI pipeline if an issue is found</li></ul><p></p><p>That&apos;s a wrap! Stay tuned for more blog posts around detekt. </p>]]></content:encoded></item><item><title><![CDATA[Android Dev Challenge: Jetpack Compose]]></title><description><![CDATA[<p>A few months ago, Jetpack Compose was promoted to beta allowing everyone to get a glimpse of what the future state of Android development could look like. Following this announcement, a new Android Developer Challenge was launched to promote the new framework through a series of four challenges with a</p>]]></description><link>https://blog.asadmansoor.com/android-dev-challenge/</link><guid isPermaLink="false">60a92e6c79b9a519c85ec96a</guid><category><![CDATA[Android]]></category><dc:creator><![CDATA[Asad Mansoor]]></dc:creator><pubDate>Sat, 22 May 2021 17:33:33 GMT</pubDate><media:content url="https://blog.asadmansoor.com/content/images/2021/05/IMG_8443.JPG" medium="image"/><content:encoded><![CDATA[<img src="https://blog.asadmansoor.com/content/images/2021/05/IMG_8443.JPG" alt="Android Dev Challenge: Jetpack Compose"><p>A few months ago, Jetpack Compose was promoted to beta allowing everyone to get a glimpse of what the future state of Android development could look like. Following this announcement, a new Android Developer Challenge was launched to promote the new framework through a series of four challenges with a chance to win exciting prizes. Since the announcement was a great interest to me, I took part in the challenge to learn more about the upcoming framework. In this blog post, I&apos;ll share my initial experience with Jetpack Compose.</p><p></p><h2 id="jetpack-compose">Jetpack Compose</h2><p>Jetpack Compose is a new declarative user-interface (UI) framework within the Android ecosystem to help create beautiful UI with less code. As opposed to the traditional imperative UI development where the user-facing views are created in a tree-like structure of widgets through the inflation of an XML layout file, Jetpack Compose provides Kotlin APIs to create composable functions that emit the UI in a declarative manner. In a sense, the views are initially created in the composition stage and only then the necessary changes are applied whenever the state has changed. Similar to SwiftUI, the core programming language is responsible for creating the UI which favours both the ease of use as well as the notion of reusability when it comes to development.</p><p></p><h2 id="what-surprised-me">What Surprised Me</h2><p>There were a few things that surprised me when I started working on the Android Developer Challenge. The first one was working with the preview mode where I could visually see the changes as soon as I applied them. This could drastically reduce the development time as I would no longer have to re-run my application on a device. In addition to that, working with Jetpack Compose felt very similar to Flutter. Both frameworks share the same look-and-feel when it comes to how the UI is so easily presented in the source code. Finally, Jetpack Compose is supported by a wide range of Jetpack libraries that have the corresponding Compose dependency, such as Jetpack Navigation for Compose. This will make it easier for Android projects to integrate the new framework without much effort. If a project is following an architecture pattern that separates the UI from the business logic layer, then Jetpack Compose can replace the Activity or Fragment source code with Composable functions that will handle the UI and state, without impacting the business logic.</p><p></p><h2 id="challenge-1thinking-in-compose">Challenge 1 - Thinking in Compose</h2><p>In the first challenge, the task was to create a puppy adoption application with two screens. The first screen will showcase a list of all the puppies followed by the puppy&apos;s detail on the second screen. The challenge focused on the basics of Jetpack Compose and the building blocks of creating UI from the Kotlin APIs. Views, such as Text, are added in the Composable function annotated by the Composable tag. This tells the framework that this function takes data as input and emits UI elements.</p><p>Jetpack Compose takes a series of Composable functions and draws them during the composition stage with some initial data. If the state has changed at some point, the changed composable function is executed again with new data which is then redrawn. Jetpack Compose automatically handles this process of recomposition very efficiently and only updates the view that have changed since last redraw.</p><p><a href="https://github.com/asadmansr/jetpup-jetpack-compose">Source code of the first challenge.</a></p><p></p><h2 id="challenge-2managing-state">Challenge 2 - Managing State </h2><p>In the second challenge, the task was to create a countdown timer application using state in Jetpack Compose. A <em>state</em> is any piece of information that can change at any time. Since the view can be recomposed multiple times at any given time, the <em>remember</em> keyword binds the state to the local storage allowing it to survive the recomposition. In addition, the <em>observeAsState</em> keyword adds a <em>LiveData</em> on an object and observes when the object has changed.</p><p>The timer application made use of <em>state</em>, <em>remember</em> and <em>observeAsState</em> in its implementation. The state kept track of whether the app was in a countdown mode or whether the user has yet to start the timer. Based on this, the specific UI was shown to the user. When the timer had started, the viewmodel was responsible for launching the thread that would count down and update the object that the <em>LiveData</em> was bound to. Whenever the time value changed, the UI would redraw the Text view that held the timer value.</p><p><a href="https://github.com/asadmansr/timer-jetpack-compose">Source code of the second challenge.</a></p><p></p><h2 id="closing-remarks">Closing Remarks</h2><p>Working with Jetpack Compose is quite different from traditional UI development for Android. There are a lot of new keywords and principles added when working with the new declarative framework. It could be a learning curve, but I am excited to see what the future holds for modern Android development. In the meantime, I got to enjoy a cool prize from the Android Developer Challenge. </p><figure class="kg-card kg-image-card"><img src="https://blog.asadmansoor.com/content/images/2021/05/IMG_8574.JPG" class="kg-image" alt="Android Dev Challenge: Jetpack Compose" loading="lazy" width="2000" height="2667" srcset="https://blog.asadmansoor.com/content/images/size/w600/2021/05/IMG_8574.JPG 600w, https://blog.asadmansoor.com/content/images/size/w1000/2021/05/IMG_8574.JPG 1000w, https://blog.asadmansoor.com/content/images/size/w1600/2021/05/IMG_8574.JPG 1600w, https://blog.asadmansoor.com/content/images/size/w2400/2021/05/IMG_8574.JPG 2400w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[Demystifying the Android CI pipeline]]></title><description><![CDATA[<p>Building software at scale requires a team of developers that are continuously modifying the codebase in parallel. These modifications can range from feature development, bug fixes or optimizations. When building at scale, it is essential to have a continuous integration (CI) pipeline that automates the flow of <strong>validating</strong> new changes</p>]]></description><link>https://blog.asadmansoor.com/demystifying-the-android-ci-pipeline/</link><guid isPermaLink="false">606f26b079b9a519c85ec85c</guid><dc:creator><![CDATA[Asad Mansoor]]></dc:creator><pubDate>Fri, 09 Apr 2021 17:15:19 GMT</pubDate><media:content url="https://blog.asadmansoor.com/content/images/2021/04/android.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.asadmansoor.com/content/images/2021/04/android.jpg" alt="Demystifying the Android CI pipeline"><p>Building software at scale requires a team of developers that are continuously modifying the codebase in parallel. These modifications can range from feature development, bug fixes or optimizations. When building at scale, it is essential to have a continuous integration (CI) pipeline that automates the flow of <strong>validating</strong> new changes to ensure that no errors or undesired side-effects are introduced. With the combination of automated CI pipeline and code review, we get a workflow that allows teams to be agile and flexible in the development of a software product.</p><p><strong>Setting the stage</strong>: Most development teams follow a Gitflow workflow, a process that standardizes the branching model around the release process. All new development changes are branched off as features branches from the develop branch and gets merged only once if it has passed the CI pipeline and code review. This is also the main entry-point where new changes are being introduced so it is essential to catch issues with the codebase earlier in the process. Branches such as main, hotfix and release are used when dealing with releases.</p><p><strong>Building for Android</strong>: The development cycle for Android is not any different. If teams are following the Gitflow workflow, they will require a CI pipeline that will automatically validate the changes through the Gradle build system. These validation can range from analyzing the correctness of the source code written in Java or Kotlin as well as the resource and dependency management within the Android framework. In the following sections, we will explore how we can build a CI pipeline that can help us validate new changes specifically for Android.</p><p></p><h2 id="ci-pipeline">CI Pipeline</h2><p>At minimum, the CI pipeline for Android requires a 3-step validation that will help validate the stability and correction of the application. The pipeline is split into stages to provide early feedback whenever an issue is discovered.</p><h3 id="compile-and-build">Compile and Build</h3><p>The first step of validation is to ensure that the project can compile and build on the CI pipeline when new code is introduced. Without a CI pipeline, it would be pretty annoying to track down a change that broke the project for the entire team. While the project is compiling and building, Gradle is also being synced to ensure the build configurations are correct and able to download the required project dependencies. The build system will also package and generate the build artifact (APK or AAB). All of these operations are signs of validation that no errors are being introduced into the codebase.</p><p><strong>What issues are we trying to catch?</strong></p><ul><li>Syntax errors or invalid build configurations</li><li>Incorrect management of project dependencies</li><li>Errors that prevent the creation of the build artifact</li></ul><p></p><h3 id="lint">Lint</h3><p>After validating that the project can be compiled and built, the second step of validation is to ensure that the codebase does not have any structural issues. Issues within the Kotlin codebase can lead to performance or reliability issues. A static code analysis tool can catch issues with formatting, complexity, exception handling, multithreading and much more. With the introduction of this tool, projects will adhere to a code quality standard throughout the development flow. Some static code analysis tools for Android projects are:</p><ul><li><a href="https://github.com/detekt/detekt">Detekt</a> (Kotlin)</li><li><a href="https://github.com/pinterest/ktlint">Ktlint</a> (Kotlin)</li><li><a href="https://developer.android.com/studio/write/lint">Android Lint</a> (Android framework)</li></ul><p><strong>What issues are we trying to catch?</strong></p><ul><li>Catching any static code analysis issues in our Kotlin codebase</li><li>Catching any issues in our implementation within the Android framework regarding accessibility, usability and performance</li></ul><p></p><h3 id="tests">Tests</h3><p>Despite validating that the project can be built and does not contain any static code analysis issues, it is not enough to ensure that the actual implementation is correct. The third step of validation is ensuring that implementation behaves as it should when the application is being used by the user. In this stage, we will require tests that validate the correctness of our business logic as well as the UI layout. The testing for Android projects can be broken down to unit tests that validate pure Kotlin code and instrumented tests running on an Android device that validate the UI or any logic that requires the Android SDK. The validation requires the execution of the entire test suite.</p><p><strong>What issues are we trying to catch?</strong></p><ul><li>New logic behaves as it should</li><li>New changes did not introduce any errors or undesired side-effect in other parts of the codebase</li></ul><p></p><h2 id="conclusion">Conclusion</h2><p>The CI process helps us validate new changes through an automated and repetitive process granting us the confidence that nothing will break. If errors are found in this process, developers can quickly resolve without impacting the customer experience. Validating an Android project requires the analysis and testing of various areas of focus independently. Only when we merge all of these validation stages into a single pipeline, the decision regarding the stability of the application can be made. In the efforts to remain agile and flexible, the CI pipeline needs to be growing side-by-side with development such that it can perform fast and reliable analysis and validation for future development work.</p>]]></content:encoded></item></channel></rss>