<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Truiton</title>
	<atom:link href="https://www.truiton.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.truiton.com/</link>
	<description>Technology Reaching Us In Time - Online</description>
	<lastBuildDate>Sat, 24 Jan 2026 05:48:05 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/11/cropped-truiton_new_logo_half_white.png?fit=32%2C32&#038;ssl=1</url>
	<title>Truiton</title>
	<link>https://www.truiton.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">54534495</site>	<item>
		<title>Android JaCoCo Code Coverage Plugin for Unit Testing</title>
		<link>https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/</link>
					<comments>https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/#respond</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Sat, 24 Jan 2026 04:15:45 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Jacoco]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://www.truiton.com/?p=18052</guid>

					<description><![CDATA[<p>Here we discuss the significance of unit testing in Android app development, emphasizing the use of the Android JaCoCo plugin for code coverage. It outlines steps to integrate JaCoCo for generating detailed coverage reports, troubleshoot issues related to Firebase Performance Monitoring, and implement CI/CD workflows using GitHub Actions for testing compliance.</p>
<p>The post <a href="https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/">Android JaCoCo Code Coverage Plugin for Unit Testing</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?ssl=1"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="1024" height="535" data-attachment-id="18110" data-permalink="https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/android-jacoco/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?fit=1536%2C803&amp;ssl=1" data-orig-size="1536,803" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android Jacoco" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?fit=300%2C157&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?fit=1024%2C535&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?resize=1024%2C535&#038;ssl=1" alt="Android JaCoCo implementation " class="wp-image-18110" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?resize=1024%2C535&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?resize=300%2C157&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?resize=768%2C402&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?resize=640%2C335&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?resize=600%2C314&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco.jpg?w=1536&amp;ssl=1 1536w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>If you have an Android app and you wish to build and deploy with confidence you might think end to end test automation is the way to go. But if one goes a little deeper and understand unit testing with its application their opinion might change. As with proper use of unit test cases one can test most of their code by just writing them properly. Therefore in today&#8217;s age most of the product and tech organizations emphasize on writing Android JUnit test cases for their Android apps. But writing unit test cases are only one part of the process, as a an engineer we also need to identify the areas to write unit test cases so that we can cover most of the code. To identify the areas of code that are covered and not covered by unit test cases we use Java code coverage (<a href="https://www.eclemma.org/jacoco/" target="_blank" rel="noreferrer noopener">JaCoCo</a>) plugin for Android. This tutorial is aimed to share a clean approach for integrating Android Jacoco plugin and explain its use cases in CI/CD world.</p>



<h2 class="wp-block-heading">Android JaCoCo Implementation</h2>



<p>When writing JUnit test cases for an Android app, our goal is to cover as much of the codebase as possible so that we can release with confidence. However, to identify the parts of the code that are not covered by JUnit tests, we need a tool that can generate a detailed coverage report and provide a clear view of which areas still require JUnit tests.</p>



<p>To generate an Android JUnit test coverage report, we can use the JaCoCo plugin. JaCoCo is not limited to Android projects; it can be used with any Java project to generate JUnit coverage reports. But, keeping the scope limited to the Android implementation of JaCoCo, let us take a look at a cleaner and more streamlined way to implement the JaCoCo plugin in an Android app project.</p>



<p>In your app level folder parallel to <code>build.gradle.kts</code>(app) file create a new file <code>jacoco.gradle.kts</code> and add following code in it: </p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import org.gradle.api.tasks.testing.Test
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
import org.gradle.testing.jacoco.tasks.JacocoReport

apply(plugin = "jacoco")

configure&lt;JacocoPluginExtension> {
    toolVersion = "0.8.12"
}

tasks.withType&lt;Test> {
    configure&lt;JacocoTaskExtension> {
        isIncludeNoLocationClasses = true
        excludes = listOf("jdk.internal.*")
    }
}

tasks.register&lt;JacocoReport>("jacocoTestReport") {
    dependsOn("testDebugUnitTest")

    reports {
        xml.required.set(true)
        html.required.set(true)
    }

    val exclusions = listOf(
        "**/R.class",
        "**/R\$*.class",
        "**/BuildConfig.*",
        "**/Manifest*.*",
        "**/*Test*.*",
        "android/**/*.*",
        "**/Lambda\$*.class",
        "**/Lambda.class",
        "**/*Lambda.class",
        "**/*Lambda*.class",
        "**/*_MembersInjector.class",
        "**/Dagger*.*",
        "**/*Dagger*.*",
        "**/*_Factory.class",
        "**/*_Provide*Factory.class",
        "**/*_ViewBinding*.*",
        "**/BR.class",
        "**/DataBinderMapperImpl.class",
        "**/DataBinderMapperImpl\$*.class",
        "**/DataBindingInfo.class",
        "**/*\$Creator.class",
        "**/*\$DefaultImpls.class",
        "**/*\$Companion.class"
    )

    sourceDirectories.setFrom(files("${project.projectDir}/src/main/java"))
    
    // Using specific paths for Java and Kotlin classes to avoid "different class with same name" error
    val javaClasses = fileTree("${layout.buildDirectory.get().asFile}/intermediates/javac/debug/classes") {
        exclude(exclusions)
    }
    val kotlinClasses = fileTree("${layout.buildDirectory.get().asFile}/tmp/kotlin-classes/debug") {
        exclude(exclusions)
    }
    
    classDirectories.setFrom(files(javaClasses, kotlinClasses))

    executionData.setFrom(fileTree(layout.buildDirectory.get().asFile) {
        include(listOf("jacoco/testDebugUnitTest.exec", "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec"))
    })
}</pre>
</div></div>



<p>Now that we have a separate file for Android Java Code Coverage (JaCoCo) plugin implementation, its makes our original build.gradle.kts file cleaner. To make this work we just need to add the following in the <code>build.gradle.kts</code> (app) file at the end:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">apply(from = "jacoco.gradle.kts")</pre>
</div></div>



<p>In this Android JaCoCo implementation, we just defined that we want XML as well as and HTML coverage report for the available unit test cases. Now to actually get the Android JUnit coverage report we just need to run the below mentioned gradle task:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">./gradlew clean :app:jacocoTestReport</pre>
</div></div>



<p></p>



<h3 class="wp-block-heading">Issues faced with Android JaCoCo implementation</h3>



<p>In a modern Android project to make Android JaCoCo implementation work properly and generate reports we need to define both compiled Java and Kotlin class directories for full coverage. Otherwise we may miss out on classes to be covered, but in a one off scenario &#8211; even when it was defined correctly, I encountered this issue:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">> Task :app:jacocoTestReport
[ant:jacocoReport] Classes in bundle 'app' do not match with execution data. For report generation the same class files must be used as at runtime.</pre>
</div></div>



<p>This issue states that &#8216;same class files must be used at runtime&#8217; &#8211; I was wondering, does that mean that the classes were being instrumented at runtime? This made me think about the working of Firebase Performance Monitoring plugin (which was also included in my build.gradle)- it instruments the classes at runtime. Then I tried <a href="https://firebase.google.com/docs/perf-mon/disable-sdk?platform=android#disable-gradle-plugin" target="_blank" rel="noreferrer noopener">disabling Firebase Performance Monitoring SDK</a> for debug builds using the code below and JaCoCo started working just fine. If you are also facing a similar issue, try using the same work around:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        debug {
            ...
            // Added this line for jacoco plugin
            configure&lt;FirebasePerfExtension> {
                setInstrumentationEnabled(false)
            }
        }</pre>
</div></div>



<p>When I further investigated,  I found out that similar issues were reported on the <a href="https://github.com/firebase/firebase-android-sdk/issues?q=is%3Aissue%20state%3Aclosed%20jacoco">firebase&#8217;s GitHub repo</a>, hope they&#8217;ll solve this in future.</p>



<p></p>



<h2 class="wp-block-heading">Android JaCoCo Coverage Report</h2>



<p>As a practice when developing large scale Android apps, we tend include a lot of SDKs to solve various things for us, JaCoCo is also one of them. In Android Studio we can get coverage reports by simply using Android Studio&#8217;s run with coverage option as well. But when comparing Android Studio&#8217;s coverage option with JaCoCo coverage report you&#8217;ll see a significant difference in the details that JaCoCo coverage report shares. Also its not just about the details Android Studio&#8217;s &#8220;Run with Coverage&#8221; option does not has, the main difference is that -its more of an IDE tool, vs JaCoCo report shared a detailed code analysis with coverage numbers which can be used in various CI pipelines.</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?ssl=1"><img data-recalc-dims="1" decoding="async" width="1024" height="202" data-attachment-id="18071" data-permalink="https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/android-jacoco-1/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?fit=1767%2C348&amp;ssl=1" data-orig-size="1767,348" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android Jacoco &amp;#8211; 1" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?fit=300%2C59&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?fit=1024%2C202&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?resize=1024%2C202&#038;ssl=1" alt="" class="wp-image-18071" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?resize=1024%2C202&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?resize=300%2C59&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?resize=768%2C151&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?resize=1536%2C303&amp;ssl=1 1536w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?resize=640%2C126&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?resize=600%2C118&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-1.jpg?w=1767&amp;ssl=1 1767w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>The JaCoCo plugin provides an option to generate HTML reports, as shown in the image above. The Java code coverage report allows us to click through and navigate inside the classes to see exactly which lines are covered. It also highlights missed lines, methods, and classes, helping us identify areas that still need to be covered by our JUnit tests. Once you integrate and run JaCoCo plugin for Android, typically you will find the report at this path: <code>build/reports/jacoco/jacocoTestReport/html/index.html</code>.</p>



<p></p>



<h2 class="wp-block-heading">JaCoCo plugin usages in CI/CD</h2>



<p>As Android applications scale and more engineers contribute to the codebase, application stability becomes critical. If every code merge or push to a Git branch introduces compilation or logical errors, it can result in significant productivity loss. To ensure releases remain resilient and predictable, large-scale organizations typically enforce a unit test coverage target of 80% or higher.</p>



<p>Achieving this level of unit test coverage requires two key mechanisms: first, the ability to measure the current unit test coverage, and second, the ability to pass or fail Git pull request checks based on that coverage. For Android applications, the JaCoCo plugin helps implement both of these mechanisms effectively. </p>



<p>In previous sections of this Android code coverage tutorial, I have shown how JaCoCo plugin can help in measuring the code coverage. In the next sections lets have a look at how JaCoCo plugin&#8217;s coverage report can be consumed in leading tools used for tracking Android code coverage which will eventually help in building CI and PR checks.</p>



<p></p>



<h3 class="wp-block-heading">Print in your CI Pipeline</h3>



<p>There are many use cases where we just need Android JUnit code coverage number when our Gradle task for running the unit test cases completes. We can print the coverage by just parsing XML report generated by the JaCoCo plugin. To implement the same please add the below code at the end of your <code>jacocoTestReport</code> task, which was created in previous section:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">doLast {
    val reportFile = file("${layout.buildDirectory.get().asFile}/reports/jacoco/jacocoTestReport/jacocoTestReport.xml")
    if (reportFile.exists()) {
        val factory = javax.xml.parsers.DocumentBuilderFactory.newInstance()
        factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
        val parser = factory.newDocumentBuilder()
        val doc = parser.parse(reportFile)
        val root = doc.documentElement
        val nodeList = root.childNodes
        
        println("-------------------------------------------------------")
        println("Code Coverage Summary (Project Level):")
        
        for (i in 0 until nodeList.length) {
            val node = nodeList.item(i)
            if (node is org.w3c.dom.Element &amp;&amp; node.tagName == "counter") {
                val type = node.getAttribute("type")
                val missed = node.getAttribute("missed").toDouble()
                val covered = node.getAttribute("covered").toDouble()
                val total = missed + covered
                val percentage = if (total > 0) (covered / total) * 100 else 0.0
                
                if (type == "INSTRUCTION") {
                    println("Instructions : ${String.format("%.2f", percentage)}% (${covered.toInt()}/${total.toInt()})")
                } else if (type == "BRANCH") {
                    println("Branches     : ${String.format("%.2f", percentage)}% (${covered.toInt()}/${total.toInt()})")
                } else if (type == "LINE") {
                    println("Lines        : ${String.format("%.2f", percentage)}% (${covered.toInt()}/${total.toInt()})")
                }
            }
        }
        println("-------------------------------------------------------")
    } else {
        println("Jacoco report XML not found at ${reportFile.absolutePath}")
    }
}</pre>
</div></div>



<p>I will add the link to complete source code at the end of this tutorial for better understanding. This script will print below text as output when the execution of <code>jacocoTestReport</code> task completes.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">> Task :app:jacocoTestReport
-------------------------------------------------------
Code Coverage Summary (Project Level):
Instructions : 3.39% (976/28763)
Branches     : 0.56% (9/1614)
Lines        : 2.61% (140/5367)
-------------------------------------------------------</pre>
</div></div>



<p>For example if Jenkins CI is being used, simply use&nbsp;shell commands&nbsp;with piping, a&nbsp;Groovy script&nbsp;in a pipeline, or the&nbsp;Log Parser Plugin to parse the above coverage output. </p>



<p></p>



<h3 class="wp-block-heading">Integrate with BrowserStack</h3>



<p>If you want to integrate a third-party tool such as BrowserStack with your CI pipeline, you can do so using BrowserStack App Automate feature, which allows you to offload your UI Espresso test executions to BrowserStack. However, in this tutorial we are focusing specifically on JUnit test coverage. Therefore, we will limit the discussion to that topic and explore BrowserStack’s support for JUnit coverage.</p>



<p>To track JUnit test executions using BrowserStack’s Test Reporting &amp; Analytics feature, you need to add the following task to your <code>jacoco.gradle.kts</code> file:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="7" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Task to upload coverage and test reports to BrowserStack.
tasks.register("uploadReportsToBrowserStack") {
    dependsOn("jacocoTestReport")
    doLast {
        val bsUser = if (project.hasProperty("bsUser")) project.property("bsUser") else "YOUR_USER_ID"
        val bsKey = if (project.hasProperty("bsKey")) project.property("bsKey") else "YOUR_USER_KEY"
        val buildId = java.text.SimpleDateFormat("yyyy-MM-dd_HH-mm").format(java.util.Date())

        // Upload JUnit XML Reports (to Automation Upload endpoint)
        val junitReportDir = file("${layout.buildDirectory.get().asFile}/test-results/testDebugUnitTest")
        if (junitReportDir.exists()) {
            println("Uploading JUnit reports to BrowserStack...")
            junitReportDir.listFiles { f -> f.extension == "xml" }?.forEach { xmlFile ->
                exec {
                    commandLine(
                        "curl", "-u", "$bsUser:$bsKey", "-vvv",
                        "-X", "POST",
                        "-F", "data=@${xmlFile.absolutePath}",
                        "-F", "projectName=TambolaCaller",
                        "-F", "buildName=Unit Test Coverage",
                        "-F", "buildIdentifier=$buildId",
                        "-F", "tags=unit_test, android",
                        "-F", "frameworkVersion=junit, 4.13.2",
                        "https://upload-automation.browserstack.com/upload"
                    )
                }
            }
        }
    }
}</pre>
</div></div>



<p>If you wish to specify a build Id you can put that custom logic in line 7 above. Once this task executes, it would upload your JUnit test report to BrowserStack&#8217;s APIs. As of now, I did not find a way to upload JaCoCo reports to browserStack, hopefully in future they may introduce this feature.</p>



<p></p>



<h3 class="wp-block-heading">Integration with GitHub Actions and workflows</h3>



<p>To enforce a minimum JUnit test coverage threshold, the <code>jacocoTestReport</code> Gradle task is executed on the CI platform, and its result is reported back to the Git repository as a pull request (PR) check using webhooks. If GitHub is used as the source code repository, it can also serve directly as the CI/CD platform. In modern technology stacks, <a href="https://github.com/features/actions" target="_blank" rel="noreferrer noopener">GitHub Actions</a> is commonly used as the CI/CD tool, as it has the capability to trigger builds and perform automated PR checks. For this Android JaCoCo tutorial I had created a github action which acts as a gating check based on Android JaCoCo coverage report. To implement the same please create a file <code>.github/workflows/android.yml</code> with following code:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">name: Android CI

on:
  push:
    #branches: [ "master" ]
  pull_request:
    #branches: [ "master" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - name: set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: gradle

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
      - name: Generate JaCoCo report
        run: ./gradlew clean jacocoTestReport

      - name: Upload Report
        uses: actions/upload-artifact@v4
        with:
          name: report.xml
          path: ${{ github.workspace }}/**/build/reports/jacoco/**/jacocoTestReport.xml

      - name: JaCoCo Report
        id: jacoco
        uses: Madrapps/jacoco-report@v1.7.2
        with:
          paths: |
            ${{ github.workspace }}/**/build/reports/jacoco/**/jacocoTestReport.xml,
            ${{ github.workspace }}/**/build/reports/jacoco/**/debugCoverage.xml
          token: ${{ secrets.GITHUB_TOKEN }}
          min-coverage-overall: 80
          min-coverage-changed-files: 80
          title: Code Coverage

      - name: Get the Coverage info
        run: |
          echo "Total coverage ${{ steps.jacoco.outputs.coverage-overall }}"
          echo "Changed Files coverage ${{ steps.jacoco.outputs.coverage-changed-files }}"

      - name: Fail PR if overall coverage is less than 80%
        if: ${{ steps.jacoco.outputs.coverage-overall &lt; 80.0 }}
        uses: actions/github-script@v6
        with:
          script: |
            core.setFailed('Overall coverage is less than 80%!')</pre>
</div></div>



<p>Once the above file is pushed in code repository, whenever a code push or pull request is created GitHub Actions will trigger a CI build. This CI build will run the <code>jacocoTestReport</code> gradle task, whose report would be used to post a comment on the pull request(PR) and a check would be added for PR merge.</p>



<figure data-carousel-extra='{&quot;blog_id&quot;:1,&quot;permalink&quot;:&quot;https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/&quot;}'  class="wp-block-gallery has-nested-images columns-1 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?ssl=1"><img data-recalc-dims="1" decoding="async" width="710" height="374" data-attachment-id="18085" data-permalink="https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/android-jacoco-github-comment/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?fit=710%2C374&amp;ssl=1" data-orig-size="710,374" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android Jacoco &amp;#8211; github comment" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?fit=300%2C158&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?fit=710%2C374&amp;ssl=1" data-id="18085" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?resize=710%2C374&#038;ssl=1" alt="" class="wp-image-18085" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?w=710&amp;ssl=1 710w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?resize=300%2C158&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?resize=640%2C337&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-comment.png?resize=600%2C316&amp;ssl=1 600w" sizes="(max-width: 710px) 100vw, 710px" /></a></figure>



<figure class="wp-block-image size-large is-style-default"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="327" data-attachment-id="18084" data-permalink="https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/android-jacoco-github-pr-check/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?fit=1601%2C512&amp;ssl=1" data-orig-size="1601,512" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android Jacoco &amp;#8211; github PR check" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?fit=300%2C96&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?fit=1024%2C327&amp;ssl=1" data-id="18084" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?resize=1024%2C327&#038;ssl=1" alt="" class="wp-image-18084" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?resize=1024%2C327&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?resize=300%2C96&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?resize=768%2C246&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?resize=1536%2C491&amp;ssl=1 1536w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?resize=640%2C205&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?resize=600%2C192&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2026/01/Android-Jacoco-github-PR-check.png?w=1601&amp;ssl=1 1601w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<p>GitHub actions is a very powerful workflow which can help automate not just this use case but many other as well. For example it can be used to perform code quality checks, integrations with third party apps and much more. For better understanding  please find the link to full source code used in this tutorial here:</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link has-text-align-center wp-element-button" href="https://gist.github.com/mohitgupt/d1694f259816271e9a9cc18b1f197439" target="_blank" rel="noreferrer noopener">GitHub Code</a></div>
</div>



<p></p>



<p>The above mentioned code link gives you full access to the <code>jacoco.gradle.kts</code> and <code>android.yml</code> files used in this JaCoCo integration tutorial for Android. As the codebase of an app evolves and team grows it becomes necessary to work on JUnit code coverage so that we can release with confidence. In this article we learned how to integrate JaCoCo plugin in an Android app in a clean way. Also I showcased how JaCoCo is used to enforce gating mechanisms via GitHub PR checks. There are many other use cases JUnit test cases and JaCoCo can solve. Please let me know what innovative use cases you are solving via JaCoCo in Android in the comments section, hope this article helped.</p>
<p>The post <a href="https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/">Android JaCoCo Code Coverage Plugin for Unit Testing</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2026/01/android-jacoco-code-coverage-plugin-for-unit-testing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">18052</post-id>	</item>
		<item>
		<title>Spring Boot Hibernate &#8211; JPA GenerationType Table vs Sequence strategy with MySQL</title>
		<link>https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/</link>
					<comments>https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/#respond</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Tue, 20 Feb 2024 13:49:03 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[JPA]]></category>
		<guid isPermaLink="false">https://www.truiton.com/?p=17152</guid>

					<description><![CDATA[<p>Explaining how GenerationType TABLE and SEQUENCE works with MySQL DB in Spring boot hibernate. We will build a custom TableGenerator with prefix and compare its performance with a SequenceStyleGenerator</p>
<p>The post <a href="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/">Spring Boot Hibernate &#8211; JPA GenerationType Table vs Sequence strategy with MySQL</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-style-default"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="571" data-attachment-id="17201" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?fit=1900%2C1060&amp;ssl=1" data-orig-size="1900,1060" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?fit=1024%2C571&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?resize=1024%2C571&#038;ssl=1" alt="Spring JPA GenerationType Table vs Sequence comparison" class="wp-image-17201" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?resize=1024%2C571&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?resize=768%2C428&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?resize=1536%2C857&amp;ssl=1 1536w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?resize=640%2C357&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?resize=600%2C335&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Featured.webp?w=1900&amp;ssl=1 1900w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="has-text-align-justify">When you are building backend REST APIs and if you plan to generate identifiers or primary keys for your table records, you have to pick a primary key generation strategy which could be either one of the following AUTO, IDENTITY, SEQUENCE, TABLE or UUID. When designing a system from scratch, you always would want to pick the strategy that works best for you. I was working on a set of backend REST APIs which are built using Kotlin Spring Hibernate framework with MySQL database. For persistence and ORM I decided to use <a href="https://spring.io/projects/spring-data-jpa">Spring data JPA</a> for this project, as it is suited the best. Here in this article I wish to share my learnings on use of GenerationType.TABLE vs. GenerationType.SEQUENCE, and determine which id generation strategy is  faster when we have to dynamically generate identifiers for table records.</p>



<div class="wp-block-group has-nv-light-bg-background-color has-background" style="border-radius:20px;padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)"><div class="wp-block-group__inner-container is-layout-constrained wp-container-core-group-is-layout-af10a197 wp-block-group-is-layout-constrained">
<p><em>I understand some people have reservations on use of MySQL database for production projects, but there are multiple factors considered when choosing a database, and it suited best for my use case. If you plan to use some other database, its your choice</em>.</p>
</div></div>



<div style="height:50px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading">Problem Statement: How to generate String identifiers with a prefix with Spring boot using JPA</h2>



<p>As mentioned, I am using MySQL database with Hibernate and Spring data JPA. For few of my tables I had a requirement to have simple numerical identifiers like 1,2,3,4 and so on. But for some of the tables in the database I wished to have an id with prefix like:</p>



<figure class="wp-block-table is-style-stripes"><table><tbody><tr><td class="has-text-align-center" data-align="center">ID (Primary key)</td><td class="has-text-align-center" data-align="center">Other Column</td></tr><tr><td class="has-text-align-center" data-align="center">TPA00001</td><td class="has-text-align-center" data-align="center">&#8230;</td></tr><tr><td class="has-text-align-center" data-align="center">TPA00002</td><td class="has-text-align-center" data-align="center">&#8230;</td></tr><tr><td class="has-text-align-center" data-align="center">TPA00003</td><td class="has-text-align-center" data-align="center">&#8230;</td></tr><tr><td class="has-text-align-center" data-align="center">TPA00004</td><td class="has-text-align-center" data-align="center">&#8230;</td></tr></tbody></table></figure>



<p class="has-text-align-justify">I read through a lot of posts available on the internet about how to generate an identifier with prefix and which GenerationType strategy is best for it. In most of the posts it was suggested that <code>GenereationType.IDENTITY</code> or <code>GenerationType.SEQUENCE</code> are fast and scalable enough to give a good performance. But since I wished to generate an ID which is supposed to have string characters as well as integers, IDENTITY type generation strategy was ruled out. As to utilize the true power of <code>GenereationType.IDENTITY</code>, I would need to have an <code>AUTO_INCREMENT</code> column in MySQL DB, which would have defeated the whole purpose of having a string prefix, and columns with VARCHAR cannot have <code>AUTO_INCREMENT</code> property.</p>



<div class="wp-block-group has-nv-light-bg-background-color has-background" style="border-style:none;border-width:0px;border-radius:20px;padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)"><div class="wp-block-group__inner-container is-layout-constrained wp-container-core-group-is-layout-af10a197 wp-block-group-is-layout-constrained">
<p>My Configuration</p>



<ul class="wp-block-list">
<li>Spring Boot : 3.2.1</li>



<li>mysql-connecter-j : 8.1.0</li>



<li>HikariCP : 5.0.1</li>
</ul>
</div></div>



<p></p>



<h3 class="wp-block-heading" id="Custom-SequenceGenerator">Implementing Custom SequenceGenerator with Spring boot JPA using MySQL DB</h3>



<p class="has-text-align-justify">In some of the posts on the internet it is suggested that identifier generation strategy <code>GenerationType.SEQUENCE</code> is one of the best strategies available. But given our use case we are using MySQL DB in this implementation, and as we know MySQL DB does not support sequences. Therefore if we wish to use SequenceGenerator strategy in Spring boot JPA using MySQL DB, then we need go with some workarounds. Since MySQL does not support the sequences, but still if we want to use this strategy, we have to create a sequence table which would maintain the <code>next_val</code> counter for the records in our table. JPA in Hibernate is built in such a way that SequenceGenerator strategy can work with a table as well in the case of MySQL. So to implement the same one can create a <code>TABLE_NAME_seq</code> table and use it with Spring data JPA in Hibernate. I created following table via SQL:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">CREATE TABLE IF NOT EXISTS `cosmos`.`my_table_seq` (
  `name` VARCHAR(45) NOT NULL,
  `next_val` BIGINT(20) NULL DEFAULT NULL,
  PRIMARY KEY (`name`))</pre>
</div></div>



<div class="wp-block-group has-nv-light-bg-background-color has-background" style="border-radius:20px;padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)"><div class="wp-block-group__inner-container is-layout-constrained wp-container-core-group-is-layout-af10a197 wp-block-group-is-layout-constrained">
<p class="has-text-align-justify"><em>Also if you are using <code>spring.jpa.hibernate.ddl-auto=update</code> then it might automatically create a sequence table for each of the tables where you implement the SequenceGenerator (not tried).</em> </p>
</div></div>



<p>Next we need to add a record to this table, to get things started:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="243" height="103" data-attachment-id="17161" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-sequence/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence.png?fit=243%2C103&amp;ssl=1" data-orig-size="243,103" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Sequence" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence.png?fit=243%2C103&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence.png?fit=243%2C103&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence.png?resize=243%2C103&#038;ssl=1" alt="" class="wp-image-17161"/></a></figure>
</div>


<p>Now we need to build a custom Sequence Generator using the <code>SequenceStyleGenerator</code> class:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.cosmos.sequences

import org.hibernate.HibernateException
import org.hibernate.MappingException
import org.hibernate.engine.spi.SharedSessionContractImplementor
import org.hibernate.id.enhanced.SequenceStyleGenerator
import org.hibernate.internal.util.config.ConfigurationHelper
import org.hibernate.service.ServiceRegistry
import org.hibernate.type.Type
import org.hibernate.type.spi.TypeConfiguration
import java.io.Serializable
import java.util.*


class StringPrefixedSequenceIdGenerator : SequenceStyleGenerator() {
    val VALUE_PREFIX_PARAMETER: String = "valuePrefix"
    val VALUE_PREFIX_DEFAULT: String = ""
    private var valuePrefix: String? = null

    val NUMBER_FORMAT_PARAMETER: String = "numberFormat"
    val NUMBER_FORMAT_DEFAULT: String = "%d"
    private var numberFormat: String? = null

    @Throws(HibernateException::class)
    override fun generate(
        session: SharedSessionContractImplementor?,
        `object`: Any?
    ): Serializable {
        return valuePrefix + String.format(numberFormat!!, super.generate(session, `object`))
    }

    @Throws(MappingException::class)
    override fun configure(type: Type?, params: Properties?, serviceRegistry: ServiceRegistry?) {
        super.configure(
            TypeConfiguration().basicTypeRegistry.getRegisteredType(Long::class.java),
            params,
            serviceRegistry
        )
        valuePrefix = ConfigurationHelper.getString(
            VALUE_PREFIX_PARAMETER,
            params, VALUE_PREFIX_DEFAULT
        )
        numberFormat = ConfigurationHelper.getString(
            NUMBER_FORMAT_PARAMETER,
            params, NUMBER_FORMAT_DEFAULT
        )
    }
}</pre>
</div></div>



<p>To use this <code>StringPrefixedSequenceIdGenerator</code>, we need reference it in our entity class by using the following:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cosmos_sequence1")
@GenericGenerator(
    name = "cosmos_sequence1",
    type = StringPrefixedSequenceIdGenerator::class,
    parameters = [
        org.hibernate.annotations.Parameter(name = "sequence_name", value = "my_table_seq"),
        org.hibernate.annotations.Parameter(name = "increment_size", value = "50"),
        org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled-lo"),
        org.hibernate.annotations.Parameter(name = "valuePrefix", value = "TPA"),
        org.hibernate.annotations.Parameter(name = "numberFormat", value = "%05d")])
@Column(name = "id", nullable = false, length = 10)
open var id: String? = null</pre>
</div></div>



<p class="has-text-align-justify">Now when we run this, and insert any record in the database for this entity, it will generate the desired identifier format i.e. <code>TPA00001</code>. Also it will maintain the counter for increment in <code>my_table_seq</code> table, while having the pre allocated numbers in the memory. Like for this example it would hit the <code>my_table_seq</code> table once to increment after 50 inserts have happened.</p>



<p class="has-text-align-justify">This identifier generation strategy for Spring JPA works well with MySQL. But with this approach the only downside I feel is that, we have to create a sequence table corresponding to every table in our database where we need to maintain sequence strategy based IDs. If only, we could optimize this further, our database would be much cleaner. The answer to this problem is <code>GenerationType.TABLE</code>, which we&#8217;ll explore in next section. </p>



<p></p>



<h3 class="wp-block-heading" id="Custom-TableGenerator">Implementing Custom TableGenerator with Spring boot JPA using MySQL DB</h3>



<p class="has-text-align-justify">Here I will show how to implement a custom <code>TableGenerator</code> which adds a prefix to the generated incremental numeric value in Spring boot JPA using MySQL database. Also I will explain how efficiently this identifier generation strategy can be used for multiple tables when generating primary keys for records. </p>



<p class="has-text-align-justify">Internally this <code>GenerationType.TABLE</code> strategy is very similar to sequence generator. Here a single table can have multiple <code>next_val</code> counters for multiple entity tables. There are many threads available over the internet about its performance, but lets reserve this point for next section where we compare GenerationType Table vs Sequence. For now lets create a table where we can maintain primary keys for our entities:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">CREATE TABLE IF NOT EXISTS `cosmos`.`cosmos_sequence` (
  `sequence_name` VARCHAR(255) NOT NULL,
  `next_val` BIGINT(20) NULL DEFAULT NULL,
  PRIMARY KEY (`sequence_name`))</pre>
</div></div>



<p class="has-text-align-justify">Next lets create a class for implementing a custom TableGenerator which can generate primary keys with a prefix in Spring boot JPA with MySQL. </p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.cosmos.sequences

import org.hibernate.HibernateException
import org.hibernate.MappingException
import org.hibernate.engine.spi.SharedSessionContractImplementor
import org.hibernate.id.enhanced.TableGenerator
import org.hibernate.internal.util.config.ConfigurationHelper
import org.hibernate.service.ServiceRegistry
import org.hibernate.type.Type
import org.hibernate.type.spi.TypeConfiguration
import java.io.Serializable
import java.util.*


class StringPrefixedTableGenerator : TableGenerator() {
    val VALUE_PREFIX_PARAMETER: String = "valuePrefix"
    val VALUE_PREFIX_DEFAULT: String = ""
    private var valuePrefix: String? = null

    val NUMBER_FORMAT_PARAMETER: String = "numberFormat"
    val NUMBER_FORMAT_DEFAULT: String = "%d"
    private var numberFormat: String? = null

    @Throws(HibernateException::class)
    override fun generate(
        session: SharedSessionContractImplementor?,
        `object`: Any?
    ): Serializable {
        return valuePrefix + String.format(numberFormat!!, super.generate(session, `object`))
    }

    @Throws(MappingException::class)
    override fun configure(type: Type?, params: Properties?, serviceRegistry: ServiceRegistry?) {
        super.configure(
            TypeConfiguration().basicTypeRegistry.getRegisteredType(Long::class.java),
            params,
            serviceRegistry
        )
        valuePrefix = ConfigurationHelper.getString(
            VALUE_PREFIX_PARAMETER,
            params, VALUE_PREFIX_DEFAULT
        )
        numberFormat = ConfigurationHelper.getString(
            NUMBER_FORMAT_PARAMETER,
            params, NUMBER_FORMAT_DEFAULT
        )
    }
}</pre>
</div></div>



<p>Now to actually use this StringPrefixedTableGenerator we need to reference it in our entity class with all the parameters</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Id
@GenericGenerator(
    name = "my_table_sequence",
    type = StringPrefixedTableGenerator::class,
    parameters = [
        org.hibernate.annotations.Parameter(name = TableGenerator.TABLE_PARAM, value = "cosmos_sequence"),
        org.hibernate.annotations.Parameter(name = TableGenerator.SEGMENT_COLUMN_PARAM, value = "sequence_name"),
        org.hibernate.annotations.Parameter(name = TableGenerator.VALUE_COLUMN_PARAM, value = "next_val"),
        org.hibernate.annotations.Parameter(name = TableGenerator.SEGMENT_VALUE_PARAM, value = "my_table_sequence"),
        org.hibernate.annotations.Parameter(name = "initial_value", value = "1"),
        org.hibernate.annotations.Parameter(name = "increment_size", value = "50"),
        org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled-lo"),
        org.hibernate.annotations.Parameter(name = "valuePrefix", value = "TPA"),
        org.hibernate.annotations.Parameter(name = "numberFormat", value = "%05d")]
)
@GeneratedValue(strategy = GenerationType.TABLE, generator = "my_table_sequence")
@Column(name = "id", nullable = false, length = 10)
open var id: String? = null</pre>
</div></div>



<p class="has-text-align-justify">When an insert happens through the above code, a record is created in the underlying table which we have specified for the TableGenerator(in this case <code>cosmos_sequence</code>). Once a record is created in <code>cosmos_sequence</code> Spring JPA can perform 50 inserts without referencing this underlying table. This is done by using the pooled-lo optimizer, you can read more about it in its official documentation. The above code would give us the desired identifier format <code>TPA00001</code>.</p>



<p class="has-text-align-justify">Just to share this is how your underlying sequence table would look when you would have multiple sequences for multiple entities in the same TableGenerator table:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-2.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="385" height="134" data-attachment-id="17170" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-sequence-2/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-2.png?fit=385%2C134&amp;ssl=1" data-orig-size="385,134" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Sequence-2" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-2.png?fit=300%2C104&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-2.png?fit=385%2C134&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-2.png?resize=385%2C134&#038;ssl=1" alt="" class="wp-image-17170" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-2.png?w=385&amp;ssl=1 385w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-2.png?resize=300%2C104&amp;ssl=1 300w" sizes="auto, (max-width: 385px) 100vw, 385px" /></a></figure>
</div>


<p class="has-text-align-justify">Therefore, as you can see, this approach would help us in optimizing the number of tables in our database. As we have used only one table for having primary key counters for multiple entities. Also, if you do not wish to have a single table due to fault tolerance or any other factors on specific entities, you can opt for an architecture where groups of specific entities have separate sequence tables while others are combined in to groups of 8, 16 or as per your need and performance.</p>



<p class="has-text-align-justify">In many online posts I have read people mentioning about the performance for <code>TableGenerator</code> in comparison to <code>SequenceGenerator</code>, I believe things are a little different when we are building with MySQL database. In the next section I would discuss about the performance of <code>GenerationType.TABLE</code> and <code>GenerationType.SEQUENCE</code> in Hibernate using MySQL database. </p>



<h2 class="wp-block-heading" id="Comparison-TableGenerator-SequenceGenerator">Comparing Custom TableGenerator vs. SequenceGenerator performance in Spring boot JPA using MySQL DB</h2>



<p class="has-text-align-justify">When we compare <code>GenerationType.TABLE</code> vs. <code>GenerationType.SEQUENCE</code> using MySQL DB, there is not much of a difference in the implementation. Firstly, be it SEQUENCE generation strategy or the TABLE generation, both strategies when used with pooled-lo optimization, the primary key is generated in the memory itself after the insert of first record. To be clear, in both the implementations <code>next_val</code> column&#8217;s values from the underlying table(s) are fetched only once, either on first insert or after the in-memory values are completely exhausted.</p>



<p class="has-text-align-justify">Secondly, both the approaches being discussed here use row level read locking techniques to safeguard the transaction and neither of them apply a table level lock when using MySQL DB with InnoDB. To query the <code>next_val</code> from sequence tables, Spring data JPA uses the primary key in the where clause of the query in case of GenerationType.TABLE, therefore a lock is applied only on that row. While in generation type SEQUENCE strategy only a single record is supposed to be present in the sequence table, therefore only that is locked and it should not make a difference. To actually validate this hypothesis, while the first insert was happening, I logged the queries for both of these primary key generation strategies :</p>



<p>Query for generation type SEQUENCE strategy using MySQL database:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">select next_val as id_val from my_table_seq for update
update my_table_seq set next_val= ? where next_val=?
insert into exp_pav_loc (created_on,exp_pav_id,is_deleted,loc_type,name,number,updated_on,id) values (?,?,?,?,?,?,?,?)</pre>
</div></div>



<p>Query for GenerationType.TABLE strategy using MySQL database:</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<pre class="EnlighterJSRAW" data-enlighter-language="sql" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">select tbl.next_val from cosmos_sequence tbl where tbl.sequence_name=? for update
update cosmos_sequence set next_val=?  where next_val=? and sequence_name=?
insert into exp_pav_loc (created_on,exp_pav_id,is_deleted,loc_type,name,number,updated_on,id) values (?,?,?,?,?,?,?,?,?,?)</pre>
</div></div>



<p class="has-text-align-justify">As you can see in the above SQL statements both of the primary key generation strategies use <a href="https://dev.mysql.com/doc/refman/8.3/en/innodb-locking-reads.html" target="_blank" rel="noreferrer noopener">SELECT FOR UPDATE</a> statements which locks rows only under normal circumstances. This is the reason, I feel that there is not much of a difference between <code>TableGenerator</code> and <code>SequenceGenerator</code> strategy when using MySQL DB with Spring data JPA. As both of them rely on the same working strategy for maintaining the counters for <code>next_val</code>. </p>



<h3 class="wp-block-heading" id="performance-tablegenerator-sequencegenerator">Performance of TableGenerator and SequenceGenerator in Spring boot hibernate using MySQL</h3>



<p class="has-text-align-justify">To further share data on the claim that there is not much of a difference in performance of <code>GenerationType.TABLE</code> vs. <code>GenerationType.SEQUENCE</code> when using MySQL DB, I created APIs and used JMeter for performance testing. For the first test I created one REST POST API, which performs an insert on a table when called. Further I used JMeter with following load to test its performance</p>



<div class="wp-block-group has-nv-light-bg-background-color has-background" style="border-radius:20px;padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)"><div class="wp-block-group__inner-container is-layout-constrained wp-container-core-group-is-layout-af10a197 wp-block-group-is-layout-constrained">
<p class="has-text-align-center"><strong>JMeter load config</strong></p>



<ul class="wp-block-list">
<li>Number of threads/users : 1000</li>



<li>Ramp up period (seconds) : 10</li>



<li>Loop count : 5</li>
</ul>



<p class="has-text-align-right"><em>This is equivalent to load:<br>Requests/Minute: 6000<br>Daily Active Users: 8.64 million</em></p>
</div></div>



<p class="has-text-align-justify">For the first three runs I had configured the API to use GenerationType.SEQUENCE as the primary key generation strategy using the code shared in above sections. I will log the time taken in milliseconds for an API to return response by using JMeter. Please have a look at the 15k sample results for this performance tests:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="150" data-attachment-id="17188" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-sequence-1-results/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?fit=1401%2C205&amp;ssl=1" data-orig-size="1401,205" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Sequence-1-Results" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?fit=300%2C44&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?fit=1024%2C150&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?resize=1024%2C150&#038;ssl=1" alt="Spring GenerationType SEQUENCE performance results" class="wp-image-17188" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?resize=1024%2C150&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?resize=300%2C44&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?resize=768%2C112&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?resize=640%2C94&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?resize=600%2C88&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-1-Results.png?w=1401&amp;ssl=1 1401w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>For next three runs I configured the same API to use GenerationType.TABLE, have a look at the results:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="152" data-attachment-id="17189" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-table-1-results/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?fit=1400%2C208&amp;ssl=1" data-orig-size="1400,208" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Table-1-Results" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?fit=300%2C45&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?fit=1024%2C152&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?resize=1024%2C152&#038;ssl=1" alt="Spring GenerationType TABLE performance results" class="wp-image-17189" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?resize=1024%2C152&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?resize=300%2C45&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?resize=768%2C114&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?resize=640%2C95&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?resize=600%2C89&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-1-Results.png?w=1400&amp;ssl=1 1400w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="has-text-align-justify">As you can see that results are very similar but for better representation, lets have a look at the average of key figures to compare the performance between SequenceGenerator and TableGenerator</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" data-attachment-id="17193" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-comparison-sequence-table-1-call/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?fit=1800%2C1350&amp;ssl=1" data-orig-size="1800,1350" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?fit=300%2C225&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?fit=1024%2C768&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?resize=1024%2C768&#038;ssl=1" alt="SequenceGenerator vs. TableGenerator results comparison" class="wp-image-17193" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?resize=300%2C225&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?resize=768%2C576&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?resize=1536%2C1152&amp;ssl=1 1536w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?resize=640%2C480&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?resize=600%2C450&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-1-call.jpg?w=1800&amp;ssl=1 1800w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="has-text-align-justify">As we can see these results show a very minor difference in milliseconds even at the 99th percentile. But to be completely sure, next I decided to execute a performance test between the GenerationType.SEQUENCE vs. GenerationType.TABLE with three APIs using MySQL DB on Spring data JPA. This will help us understand the behavior of TableGenerator when multiple reads/inserts/updates happen in the same sequence table. </p>



<p class="has-text-align-justify">To do this I created three different REST POST APIs, which run an insert statement on the desired table based on the code shared in above sections. Then I configured JMeter to call these APIs sequentially in a thread group, but since I am planning to have multiple threads, eventually all of these would be called in parallel.  </p>



<div class="wp-block-group has-nv-light-bg-background-color has-background" style="border-radius:20px;padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)"><div class="wp-block-group__inner-container is-layout-constrained wp-container-core-group-is-layout-af10a197 wp-block-group-is-layout-constrained">
<p class="has-text-align-center"><strong>JMeter load config</strong></p>



<ul class="wp-block-list">
<li>Number of threads/users : 1000</li>



<li>Ramp up period (seconds) : 10</li>



<li>Loop count : 5</li>
</ul>



<p class="has-text-align-right"><em>This is equivalent to load:<br>Requests/Minute: 18000<br>Daily Active Users: 8.64 million</em></p>
</div></div>



<p>For the first three runs I configured the APIs to use <code>GenerationType.SEQUENCE</code> as the primary key generation strategy. Through this performance test I will log their response time in milliseconds. Please have a look at the data gathered, in total I captured roughly 45K samples in 3 runs of 15K each, where internally 3 APIs were being called:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="150" data-attachment-id="17196" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-sequence-3-results/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?fit=1400%2C205&amp;ssl=1" data-orig-size="1400,205" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Sequence-3-Results" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?fit=300%2C44&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?fit=1024%2C150&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?resize=1024%2C150&#038;ssl=1" alt="" class="wp-image-17196" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?resize=1024%2C150&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?resize=300%2C44&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?resize=768%2C112&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?resize=640%2C94&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?resize=600%2C88&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Sequence-3-Results.png?w=1400&amp;ssl=1 1400w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="has-text-align-justify">Next, I configured the same set of 3 APIs to use the <code>GenerationType.TABLE</code> strategy to generate primary keys using Spring data JPA in MySQL DB. Like all the tests performed earlier, here as well I will log response time in milliseconds. For this test I captured around 45K samples, please have a look:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="149" data-attachment-id="17197" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-table-3-results/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?fit=1401%2C204&amp;ssl=1" data-orig-size="1401,204" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Table-3-Results" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?fit=300%2C44&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?fit=1024%2C149&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?resize=1024%2C149&#038;ssl=1" alt="" class="wp-image-17197" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?resize=1024%2C149&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?resize=300%2C44&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?resize=768%2C112&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?resize=640%2C93&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?resize=600%2C87&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Table-3-Results.png?w=1401&amp;ssl=1 1401w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="has-text-align-justify">As you can see the results are very similar when we compare both the tests for 3 APIs between the SEQUENCE generation strategy and TABLE generation strategy. For better representation, lets have a look at the comparison graph:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="768" data-attachment-id="17198" data-permalink="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/spring-jpa-generationtype-comparison-sequence-table-3-call/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?fit=1799%2C1350&amp;ssl=1" data-orig-size="1799,1350" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?fit=300%2C225&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?fit=1024%2C768&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?resize=1024%2C768&#038;ssl=1" alt="TableGenerator and Sequence Generator performance results" class="wp-image-17198" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?resize=300%2C225&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?resize=768%2C576&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?resize=1536%2C1153&amp;ssl=1 1536w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?resize=640%2C480&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?resize=600%2C450&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2024/02/Spring-JPA-GenerationType-Comparison-Sequence-Table-3-call.jpg?w=1799&amp;ssl=1 1799w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>Interestingly, even when we have this large range of samples the difference between performance of <code>SequenceGenerator</code> and <code>TableGenerator</code> is very minimal.  This test not just only highlights the difference but also certifies that internally the working of <code>SequenceGenerator</code> and <code>TableGenerator</code> is very similar when used for MySQL DB in Spring data JPA.  </p>



<h3 class="wp-block-heading">Difference between GenerationType.SEQUENCE and GenerationType.TABLE</h3>



<p class="has-text-align-justify">Looking at the data captured in performance tests above, I feel the only major functional difference between <code>GenerationType.SEQUENCE</code> and <code>GenerationType.TABLE</code> when used for MySQL DB via Spring data JPA is that the first one maintains the primary key <code>next_val</code> counter in separate tables vs. the later one stores the same for multiple entities in a single table. Data from the above performance tests also imply that there is no significant difference in performance when either of them is used on MySQL DB with Spring data JPA. </p>



<p class="has-text-align-justify">Another advantage of <code>GenerationType.TABLE</code> strategy is that it helps in keeping the database clean, as a single sequence counter table can be used to store the primary key counters for multiple entities. On the contrary, if one plans to use <code>GenerationType.SEQUENCE</code>, they would have to maintain equal number of sequence tables. Like, for example if you have 100 tables where primary keys need to be generated, then you need to have 100 sequence tables as well when using Spring data JPA with <code>GenerationType.SEQUENCE</code>, in MySQL DB. </p>



<p class="has-text-align-justify">On the other hand when using <code>TableGenerator</code>, you can chose to optimize according to your need, where you can plan to have one or more than one table for maintaining primary key counters, you can always have groups of entities using same sequence table based on some custom logic. Or if you have a small project you can have single sequence table as well under <code>TableGenerator</code> strategy for all your entities. When using <code>TableGenerator</code>, based on your requirement you can take a decision and build your system. I understand that there are many factors which are considered when a database is chosen for a system, but if you plan to choose MySQL database hope this article helps you decide your ID generation strategy. If this article helped you, please feel free to share it with your friends. </p>
<p>The post <a href="https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/">Spring Boot Hibernate &#8211; JPA GenerationType Table vs Sequence strategy with MySQL</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2024/02/spring-boot-hibernate-jpa-generationtype-table-vs-sequence-strategy-with-mysql/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">17152</post-id>	</item>
		<item>
		<title>Implementing the Splash Activity in Android &#8211; The Right Way</title>
		<link>https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/</link>
					<comments>https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/#respond</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Fri, 28 Oct 2022 17:19:52 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Splash Screen]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://www.truiton.com/?p=16643</guid>

					<description><![CDATA[<p>If you are working on a large scale Android app, you might realize that to give a premium experience to your users you need to implement a splash activity in Android. In most cases behind the scenes a splash screen is used to load data in background and on the foreground it is utilized to&#8230;&#160;<a href="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/" rel="bookmark">Read More &#187;<span class="screen-reader-text">Implementing the Splash Activity in Android &#8211; The Right Way</span></a></p>
<p>The post <a href="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/">Implementing the Splash Activity in Android &#8211; The Right Way</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="538" data-attachment-id="16645" data-permalink="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/android-splash-screen-api-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?fit=1200%2C630&amp;ssl=1" data-orig-size="1200,630" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android-Splash-Screen-API-Featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?fit=300%2C158&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?fit=1024%2C538&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?resize=1024%2C538&#038;ssl=1" alt="Android Splash Screen API" class="wp-image-16645" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?resize=1024%2C538&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?resize=300%2C158&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?resize=768%2C403&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?resize=640%2C336&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?resize=600%2C315&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-API-Featured.jpg?w=1200&amp;ssl=1 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p></p>



<p class="has-drop-cap has-text-align-justify has-medium-font-size">If you are working on a large scale Android app, you might realize that to give a premium experience to your users you need to implement a splash activity in Android. In most cases behind the scenes a splash screen is used to load data in background and on the foreground it is utilized to educate users about the app. In terms of implementation, when an app is starting, specially in a cold start case a lot of activity is done by the Android OS to start your app. To optimize this and give a great experience to the users, android has introduced a <a href="https://developer.android.com/develop/ui/views/launch/splash-screen" target="_blank" rel="noreferrer noopener">Splash Screen API</a>. In this tutorial lets see how the new android splash screen API is used and its benefits.</p>



<h2 class="wp-block-heading">What&#8217;s the use of new Android Splash Screen API ?</h2>



<p class="has-text-align-justify has-medium-font-size">You might start to think what&#8217;s the use of this new Android SplashScreen API? We can always build a custom splash screen and use it as per requirement. To understand the actual use of this API we must first understand what&#8217;s a <a href="https://developer.android.com/topic/performance/vitals/launch-time#cold" target="_blank" rel="noreferrer noopener">cold start</a> for an Android app. To understand this lets go little deeper. A cold start means launching an app for the first time. It refers to a state of OS starting an app when its process is not running. When launching an android app for the first time, OS does a lot of work in the background and creating its process from the scratch is called a cold start. Lets have a look at the states an app goes through before actually starting.</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter size-full is-resized"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" data-attachment-id="16656" data-permalink="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/android-splash-screen-cold-start/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?fit=615%2C137&amp;ssl=1" data-orig-size="615,137" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android-Splash-Screen-cold-start" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?fit=300%2C67&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?fit=615%2C137&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?resize=615%2C137&#038;ssl=1" alt="Android Splash Screen Cold Start" class="wp-image-16656" width="615" height="137" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?w=615&amp;ssl=1 615w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?resize=300%2C67&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.jpg?resize=600%2C134&amp;ssl=1 600w" sizes="auto, (max-width: 615px) 100vw, 615px" /></a></figure>
</div>


<p class="has-text-align-justify has-medium-font-size">As per the official documentation first OS starts loading and launching the app then displays a blank screen momentarily, then finally the handoff happens to the apps process where our code can actually be executed. Now from an experience standpoint even if you have a custom splash screen for launch, it would be displayed only after a blank screen is displayed momentarily. You might not get to see this experience on very fast devices, but it exists. Starting Android 12 we have this new Splash Screen API which shows a standardized splash screen, avoiding the original blank screen before the handoff to app&#8217;s process. This gives a much better experience to the user in comparison to the blank container. </p>



<p class="has-text-align-justify has-medium-font-size">Interestingly this new Android Splash Screen API is applied by default on all the apps from Android 12. Therefore whenever you launch an app on Android 12 and above you will always see a standardized animation and then your original splash screen would be displayed. This could be a little abrupt if you have used <code>android:windowBackground</code>, in your theme. As the standardized Android splash activity uses your app&#8217;s launcher icon and theme&#8217;s <code>android:windowBackground</code>, attribute to show a splash screen. To make this standardized experience blend into your app&#8217;s experience, android team has exposed some basic level of functionalities in this API, which can be used to customize your app&#8217;s launch experience. In the next section I will show an Android SplashScreen API example for the same.</p>



<p class="has-text-align-justify has-medium-font-size">This new Android SplashScreen API has been introduced from Android 12, but a <a href="https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen" target="_blank" rel="noreferrer noopener">compat version</a> of the same has also been released, which allows us to use this from API 21 onwards. In our Splash Activity in android tutorial we will be using the same. To use the compat version please include this in your gradle file :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="groovy" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">implementation "androidx.core:core-splashscreen:1.0.0"
</pre>



<h2 class="wp-block-heading">Implementation of Splash Activity in Android</h2>



<p class="has-text-align-justify has-medium-font-size">In a large scale production app, there&#8217;s a good chance that you might need to implement an Android Splash Screen. In this section we will implement the same using the latest <a href="https://developer.android.com/develop/ui/views/launch/splash-screen" target="_blank" rel="noreferrer noopener nofollow">Android SplashScreen API</a>. As mentioned in the previous section, default Android&#8217;s splash screen gives us a very standardized implementation of the splash screen. Where your app&#8217;s launcher icon and  <code>android:windowBackground</code>, is used to show a splash screen. If we are building a large scale app we might need to customize it according to our needs. If we have to build a splash activity in Android using the latest API, it gives us all the powers to customize it. Have a look at the animation below, this is what we will try to achieve in our app. </p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.gif?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="320" height="668" data-attachment-id="16672" data-permalink="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/android-splash-screen-cold-start-2/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.gif?fit=320%2C668&amp;ssl=1" data-orig-size="320,668" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android-Splash-Screen-cold-start" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.gif?fit=144%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.gif?fit=320%2C668&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start.gif?resize=320%2C668&#038;ssl=1" alt="" class="wp-image-16672"/></a><figcaption class="wp-element-caption">Android Splash Screen &#8211; Cold Start</figcaption></figure>
</div>


<p class="has-text-align-justify has-medium-font-size">Although as per official documentation it is advised that our apps launcher screen should be the actual main screen where the user has intended to go. But when building large scale apps a splash screen is needed to do various things like, initializing SDKs (if not in the Application class), fetching location before the main screen or maybe just to build a deep link router, there are many more such use cases (If you know a few, please add them in the comments section). Therefore in this section we will build a splash screen which would have the default enter animation with the screen customization according to our theme, and a custom exit animation which would transform the initial splash in to our custom android splash screen. In this custom splash activity we can do whatever we want, once we execute our code we will eventually load app&#8217;s main screen. </p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="613" height="177" data-attachment-id="16718" data-permalink="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/custom-splash-screen-in-android-flow-1/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?fit=613%2C177&amp;ssl=1" data-orig-size="613,177" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Custom-splash-screen-in-Android-flow-1" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?fit=300%2C87&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?fit=613%2C177&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?resize=613%2C177&#038;ssl=1" alt="" class="wp-image-16718" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?w=613&amp;ssl=1 613w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?resize=300%2C87&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Custom-splash-screen-in-Android-flow-1.jpg?resize=600%2C173&amp;ssl=1 600w" sizes="auto, (max-width: 613px) 100vw, 613px" /></a></figure>
</div>


<p class="has-text-align-justify has-small-font-size"><em>Please note &#8211; If this is not your use case and you wish to open the main screen directly, things are simpler for you. Splash screen just needs to be initialized as per the <a href="https://developer.android.com/develop/ui/views/launch/splash-screen" target="_blank" rel="noreferrer noopener nofollow">official documentation</a>. </em></p>



<p class="has-text-align-justify has-medium-font-size">Firstly to start with building a splash screen in Android Studio we need to include a Gradle dependency defined in the section above, this way we will have the support from android API 21 onwards. Next we need to create a theme which inherits the <code>"Theme.SplashScreen"</code>. Have look at the example code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;style name="Theme.MyCustomSplash" parent="Theme.SplashScreen">
    &lt;item name="windowSplashScreenBackground">@color/purple_500&lt;/item>
    &lt;item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher&lt;/item>
    &lt;item name="postSplashScreenTheme">@style/Theme.MyCustomSplashTheme&lt;/item>
&lt;/style>

&lt;style name="Theme.MyCustomSplashTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    &lt;item name="colorPrimary">@color/purple_500&lt;/item>
    &lt;item name="colorPrimaryVariant">@color/purple_700&lt;/item>
    &lt;item name="colorOnPrimary">@color/white&lt;/item>
    &lt;item name="colorSecondary">@color/teal_200&lt;/item>
    &lt;item name="colorSecondaryVariant">@color/teal_700&lt;/item>
    &lt;item name="colorOnSecondary">@color/black&lt;/item>
    &lt;item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant&lt;/item>
    &lt;item name="android:windowActionBar">false&lt;/item>
    &lt;item name="android:windowNoTitle">true&lt;/item>
    &lt;item name="android:fitsSystemWindows">false&lt;/item>
    &lt;item name="android:windowFullscreen">true&lt;/item>
    &lt;item name="android:windowContentOverlay">@null&lt;/item>
    &lt;!-- Customize your theme here. -->

&lt;/style></pre>



<p class="has-text-align-justify has-medium-font-size">In the above section another point to note is that we also have to define a <code>postSplashScreenTheme</code> attribute, where we mention the theme which is to be applied after the standardized splash animation is dismissed. In our case since we are landing the user on to a custom android splash screen, we have mentioned a theme which is inheriting <code>"Theme.MaterialComponents.DayNight.NoActionBar"</code>. Otherwise we could have used the app&#8217;s theme. Next lets have a look at the manifest where this theme needs to be specified, although in the end of this article, I will share the link to its full source code.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android">

    &lt;application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyCustomAppTheme">
        &lt;activity
            android:name=".MyLaunchActivity"
            android:exported="true"
            android:theme="@style/Theme.MyCustomSplash">
            &lt;intent-filter>
                &lt;action android:name="android.intent.action.MAIN" />

                &lt;category android:name="android.intent.category.LAUNCHER" />
            &lt;/intent-filter>
        &lt;/activity>

        &lt;activity android:name=".MainActivity" />
    &lt;/application>

&lt;/manifest></pre>



<p class="has-text-align-justify has-medium-font-size">As you can see in our launch activity we have defined the our custom Android Splash Screen theme. Next we have to do an initialization of the SplashScreen API in the <code>onCreate</code> of launch activity. Please note that this needs to be done before <code>super.onCreate</code> and <code>setContentView</code>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.splashscreenapi

import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.animation.AccelerateInterpolator
import android.view.animation.OvershootInterpolator
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.doOnEnd
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext


class MyLaunchActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val screen = installSplashScreen()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_launch)
        val mySplashMainIcon: ImageView = findViewById(R.id.splash_main_icon)
        screen.setOnExitAnimationListener { splashScreenView ->
            val lineStartY: Int = getRelativeTop2(mySplashMainIcon)
            val animY = ObjectAnimator.ofFloat(
                splashScreenView.iconView,
                View.Y,
                lineStartY.toFloat()
            )
            //Just in case you wish to run multiple animations
            /*val animX = ObjectAnimator.ofFloat(
                splashScreenView.iconView,
                View.X,
                mySplashIcon2.x
            )*/

            val alpha = ObjectAnimator.ofFloat(
                splashScreenView.view,
                View.ALPHA,
                1f,
                0f
            )
            alpha.interpolator = AccelerateInterpolator()
            alpha.duration = 200L

            val traverseSet = AnimatorSet().apply {
                interpolator = OvershootInterpolator()
                duration = 500L
                playTogether(/*animX,*/ animY)
            }

            AnimatorSet().apply {
                play(traverseSet).before(alpha)
                doOnEnd {
                    splashScreenView.remove()
                }
                start()
            }
        }

        lifecycleScope.launch(Dispatchers.Main) {
            doSomeWork() // can do initializations on IO/Worker Thread
            launchNextScreen() // back on UI/Main thread
        }
    }

    private suspend fun doSomeWork() = withContext(Dispatchers.IO) {
        delay(5000L) // pretend we are doing some IO operation
    }

    private fun launchNextScreen() {
        startActivity(Intent(this, MainActivity::class.java))
        finish()
    }

    private fun getRelativeTop2(view: View): Int {
        val parent = view.parent as View
        val parentLocation = IntArray(2)
        val viewLocation = IntArray(2)
        view.getLocationOnScreen(viewLocation)
        parent.getLocationOnScreen(parentLocation)
        return viewLocation[1] - (parentLocation[1]*2)
    }
}</pre>



<p class="has-text-align-justify has-medium-font-size">To make a splash screen exit animation on Android we have overridden <code>setOnExitAnimationListener</code>. This callback gives us a reference to the splash screen view through which we can get the logo view which can be used for animation. So to animate we have used an ObjectAnimator, the code for the same is self explanatory and beyond the scope of this article. You can view full source code here:</p>



<div class="wp-block-buttons has-text-align-center is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill is-style-primary"><a class="wp-block-button__link wp-element-button" href="https://github.com/Truiton/SplashScreenAPI" target="_blank" rel="noreferrer noopener">Full Source Code</a></div>
</div>



<p class="has-text-align-justify has-medium-font-size">Now once this <code>setOnExitAnimationListener</code> has completed its execution we land into the regular app flow, where we have started a coroutine which is pretending to to some work, in the actual implementation you can write all the initializations or API calls that you want to make in this <code>doSomeWork()</code> method. Once the execution for <code>doSomeWork()</code> method completes this coroutine launches the next activity of the app giving us the desired Android custom splash screen experience.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure data-carousel-extra='{&quot;blog_id&quot;:1,&quot;permalink&quot;:&quot;https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/&quot;}'  class="wp-block-gallery aligncenter has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start-profiling.gif?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="320" height="668" data-attachment-id="16684" data-permalink="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/android-splash-screen-cold-start-profiling/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start-profiling.gif?fit=320%2C668&amp;ssl=1" data-orig-size="320,668" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android-Splash-Screen-cold-start-profiling" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start-profiling.gif?fit=144%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start-profiling.gif?fit=320%2C668&amp;ssl=1" data-id="16684" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-cold-start-profiling.gif?resize=320%2C668&#038;ssl=1" alt="" class="wp-image-16684"/></a><figcaption class="wp-element-caption">Android Splash Activity Cold Start with Profiling</figcaption></figure>
</figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure data-carousel-extra='{&quot;blog_id&quot;:1,&quot;permalink&quot;:&quot;https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/&quot;}'  class="wp-block-gallery aligncenter has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-warm-start.gif?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="320" height="668" data-attachment-id="16683" data-permalink="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/android-splash-screen-warm-start/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-warm-start.gif?fit=320%2C668&amp;ssl=1" data-orig-size="320,668" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android-Splash-Screen-warm-start" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-warm-start.gif?fit=144%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-warm-start.gif?fit=320%2C668&amp;ssl=1" data-id="16683" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2022/10/Android-Splash-Screen-warm-start.gif?resize=320%2C668&#038;ssl=1" alt="" class="wp-image-16683"/></a><figcaption class="wp-element-caption">Android Splash Activity Warm Start</figcaption></figure>
</figure>
</div>
</div>



<p></p>



<p class="has-text-align-justify has-medium-font-size">When building this sample I also did CPU and memory profiling of the custom splash activity in the sample. Interestingly when we launch the app for the first time, basically when we do a cold start it does give a spike, since OS is loading and launching the app but there is no visual lag, neither there is any blank screen momentarily. This is the real advantage of using the <a href="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/">Android SplashScreen API</a>. Also when we do a warm start of the app, you can see that the handoff from splash to custom animation happens almost instantaneously, and since we have a <code>setOnExitAnimationListener</code> set to handle this situation it works flawlessly giving a very smooth experience. This brings us to the conclusion of this article, hope it helped in understanding the concept. </p>



<hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"/>
<p>The post <a href="https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/">Implementing the Splash Activity in Android &#8211; The Right Way</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2022/10/implementing-the-splash-activity-in-android-the-right-way/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">16643</post-id>	</item>
		<item>
		<title>Merging Android LiveData</title>
		<link>https://www.truiton.com/2019/11/merging-android-livedata/</link>
					<comments>https://www.truiton.com/2019/11/merging-android-livedata/#respond</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Sun, 17 Nov 2019 12:35:14 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[LiveData]]></category>
		<guid isPermaLink="false">https://www.truiton.com/?p=3772</guid>

					<description><![CDATA[<p>Learn how to combine two LiveData objects into a single stream of merged Android LiveData using MediatorLiveData. </p>
<p>The post <a href="https://www.truiton.com/2019/11/merging-android-livedata/">Merging Android LiveData</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="950" height="530" data-attachment-id="3782" data-permalink="https://www.truiton.com/2019/11/merging-android-livedata/merging-android-livedata-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?fit=950%2C530&amp;ssl=1" data-orig-size="950,530" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Merging-Android-LiveData-Featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?fit=950%2C530&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?resize=950%2C530&#038;ssl=1" alt="Merging Android LiveData" class="wp-image-3782" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?w=950&amp;ssl=1 950w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?resize=768%2C428&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?resize=640%2C357&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/08/Merging-Android-LiveData-Featured.jpg?resize=600%2C335&amp;ssl=1 600w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure></div>



<p></p>



<p style="text-align:justify" class="has-drop-cap">Since the adoption of reactive programming in Android by Google, a new category of life cycle aware classes were released to make the concept more usable. This paradigm shift induced a lot of changes in the android stack, and lead to the conceptualization of LiveData. This <a href="https://developer.android.com/topic/libraries/architecture/livedata" target="_blank" rel="noreferrer noopener" aria-label="Android LiveData (opens in a new tab)">Android LiveData</a> as we know is a data holder class on which we can put an observable to observe the changes in data it holds. This works very well with SQLite databases and API calls, but what if we have to combine both of these LiveData objects and return one single Android merged LiveData. You must be thinking, its not very straight forward. But still it is very easy to implement, in this tutorial we would have a look at how to merge two android LiveData objects and maintain a single stream of merged Android LiveData at the Activity level.</p>



<p style="text-align:justify">For this Android LiveData merging tutorial, it expected from you as a reader to have basic understanding of following concepts:</p>



<ul class="wp-block-list"><li>Androidx</li><li>MVVM Architecture</li><li>Android Architecture Components</li><li>Lifecycle Aware Programming</li><li>Room Database</li></ul>



<p style="text-align:justify">When you need to combine LiveData objects from multiple data sources into one LiveData object, you also need to take care of a case where data is changed in one of the original LiveData objects. In such a case then the corresponding data should also be refreshed in the other LiveData which is merged with current one. In the next sections you will see how to refresh data dynamically from SQLite database when one of the API call based LiveData values are changed. </p>



<p></p>



<h2 class="wp-block-heading">How to merge and combine multiple LiveData sources? </h2>



<p style="text-align:justify">Once you start using LiveData in your apps you will realize that, it can solve almost every data flow problem, weather you are trying to communicate with a fragment from an activity, or you are trying to connect with a database. Even if you are trying to make an API call and return data to your activity, now-days the best practice is to use a LiveData object. But one issue that you may face by using LiveData is that, if you need data from multiple sources, for example from a web API call and a local database, then how will you combine two LiveData objects? This example revolves around this problem only, where we show how to merge multiple LiveData objects in Android. </p>



<h4 class="wp-block-heading">By using MediatorLiveData and Transformations</h4>



<p style="text-align:justify">In this example, we will combine two sources of data and both of them would be served by a LiveData object at the Android activity.  To achieve this merging of Android LiveData we would be using <a rel="noreferrer noopener" aria-label="MediatorLiveData (opens in a new tab)" href="https://developer.android.com/reference/androidx/lifecycle/MediatorLiveData.html" target="_blank">MediatorLiveData</a> and <a rel="noreferrer noopener" aria-label="MutableLiveData (opens in a new tab)" href="https://developer.android.com/reference/androidx/lifecycle/MediatorLiveData.html" target="_blank">MutableLiveData</a> classes extensively. In brief MediatorLiveData allows us to observe on multiple LiveData objects and react to their changes. For this android merged LiveData example one should have a clear understanding of <a href="https://developer.android.com/topic/libraries/architecture/livedata">LiveData</a> and its types, therefore please refer to the official documentation for that. </p>



<p style="text-align:justify">At times the use case is such that a LiveData object needs to be changed into  a different type of object. Such cases can be gracefully handled by the LiveData <a rel="noreferrer noopener" aria-label="Transformations (opens in a new tab)" href="https://developer.android.com/reference/androidx/lifecycle/Transformations.html" target="_blank">Transformations</a>. In this LiveData merging sample, we will be using Transformations class, this will help us in transforming and merging the LiveData from <a rel="noreferrer noopener" aria-label="Room database (opens in a new tab)" href="https://developer.android.com/training/data-storage/room/index.html" target="_blank">Room database</a> with LiveData from the API call. To be specific in this sample we will be using <a rel="noreferrer noopener" aria-label="Transformations.switchMap (opens in a new tab)" href="https://developer.android.com/reference/androidx/lifecycle/Transformations.html#switchMap(androidx.lifecycle.LiveData%3CX%3E,%20androidx.arch.core.util.Function%3CX,%20androidx.lifecycle.LiveData%3CY%3E%3E)" target="_blank">Transformations.switchMap</a> type of transformations method which allows us to call a function and transform the data as per our needs. For full details on transformations and room database please read about them in the official documentation, as discussing them in this post would go in a different direction.</p>



<h4 class="wp-block-heading">How is a merged Android LiveData object created?</h4>



<p style="text-align:justify">Now that we have a clear understanding of how all the components would work, lets have an understanding how they will work together. We want to achieve a functionality where we can get a merged Android LiveData from two or more sources of LiveData. Here one source can be of an API LiveData and the other one can be of a room database. To do so in this example we would use retrofit as a networking client and get a LiveData response. We will also create a stream of LiveData from room database and finally merge the two android LiveData objects with respect to each other by using <a rel="noreferrer noopener" href="https://developer.android.com/reference/androidx/lifecycle/MediatorLiveData.html" target="_blank">MediatorLiveData</a> and <a rel="noreferrer noopener" href="https://developer.android.com/reference/androidx/lifecycle/Transformations.html#switchMap(androidx.lifecycle.LiveData%3CX%3E,%20androidx.arch.core.util.Function%3CX,%20androidx.lifecycle.LiveData%3CY%3E%3E)" target="_blank">Transformations.switchMap</a> functions. Once this is done we can put an observer on the final output of the MediatorLiveData object and fulfill our motives. Lets explore some code part in the next sections to have full understanding.</p>



<p></p>



<h2 class="wp-block-heading">Merging Android LiveData</h2>



<ul data-carousel-extra='{&quot;blog_id&quot;:1,&quot;permalink&quot;:&quot;https://www.truiton.com/2019/11/merging-android-livedata/&quot;}'  class="wp-block-gallery columns-1 is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex"><li class="blocks-gallery-item"><figure><img data-recalc-dims="1" loading="lazy" decoding="async" width="1191" height="869" data-attachment-id="4196" data-permalink="https://www.truiton.com/2019/11/merging-android-livedata/foursquare-mvvm/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?fit=1191%2C869&amp;ssl=1" data-orig-size="1191,869" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android MVVM" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?fit=300%2C219&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?fit=1024%2C747&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?resize=1191%2C869&#038;ssl=1" alt="Android MVVM - LiveData merge" data-id="4196" class="wp-image-4196" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?w=1191&amp;ssl=1 1191w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?resize=300%2C219&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?resize=768%2C560&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?resize=1024%2C747&amp;ssl=1 1024w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?resize=640%2C467&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/09/Foursquare-MVVM.png?resize=600%2C438&amp;ssl=1 600w" sizes="auto, (max-width: 1191px) 100vw, 1191px" /></figure></li></ul>



<p style="text-align:justify">To showcase how to combine multiple android LiveData objects we will build a sample where we would enter a location in an EditText and show places data for that location. To fetch the surrounding places we would use the <a rel="noreferrer noopener" aria-label="Foursqaure venues API (opens in a new tab)" href="https://developer.foursquare.com/docs/api/venues/search" target="_blank">Foursqaure venues API</a> in this case. The surrounding places that we fetched would be displayed in a RecyclerView on the same screen. To make this problem a little more interesting, we would also allow the user to mark a place favorite by tapping on a button on the details screen. To do so we will keep the &#8216;favorite marked place&#8217; in our local Room Database. </p>



<ul data-carousel-extra='{&quot;blog_id&quot;:1,&quot;permalink&quot;:&quot;https://www.truiton.com/2019/11/merging-android-livedata/&quot;}'  class="wp-block-gallery columns-2 is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex"><li class="blocks-gallery-item"><figure><img data-recalc-dims="1" loading="lazy" decoding="async" width="1080" height="1920" data-attachment-id="6198" data-permalink="https://www.truiton.com/android-merging-livedata-1/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-1.png?fit=1080%2C1920&amp;ssl=1" data-orig-size="1080,1920" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android-Merging-LiveData-1" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-1.png?fit=169%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-1.png?fit=576%2C1024&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-1.png?resize=1080%2C1920&#038;ssl=1" alt="Android-Merging-LiveData-1" data-id="6198" data-link="https://www.truiton.com/android-merging-livedata-1/" class="wp-image-6198"/></figure></li><li class="blocks-gallery-item"><figure><img data-recalc-dims="1" loading="lazy" decoding="async" width="1080" height="1920" data-attachment-id="6199" data-permalink="https://www.truiton.com/android-merging-livedata-2/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-2.png?fit=1080%2C1920&amp;ssl=1" data-orig-size="1080,1920" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android-Merging-LiveData-Details" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-2.png?fit=169%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-2.png?fit=576%2C1024&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2019/11/Android-Merging-LiveData-2.png?resize=1080%2C1920&#038;ssl=1" alt="Android-Merging-LiveData-Details" data-id="6199" data-link="https://www.truiton.com/android-merging-livedata-2/" class="wp-image-6199"/></figure></li></ul>



<p style="text-align:justify">Now that the final data on the listing screen would be displayed from two sources i.e. from the local Room database and from a web API call we would need to merge the data from two LiveData sources. To do so we will use <a rel="noreferrer noopener" href="https://developer.android.com/reference/androidx/lifecycle/MediatorLiveData.html" target="_blank">MediatorLiveData</a> and <a href="https://developer.android.com/reference/androidx/lifecycle/Transformations.html#switchMap(androidx.lifecycle.LiveData%3CX%3E,%20androidx.arch.core.util.Function%3CX,%20androidx.lifecycle.LiveData%3CY%3E%3E)" target="_blank" rel="noreferrer noopener" aria-label=" (opens in a new tab)">Transformations.switchMap</a>, by following full MVVM architecture. </p>



<p style="text-align:justify">We will use retrofit as an API client in this Android LiveData merging sample. We have defined an interface by the name of <code>FSInterface</code> to make the API call, you can find the full source code at the end of the tutorial. Also we have defined a room database to store the favorite flag, with respect to the data from API. We intend to store this flag in the room database when user marks a place as favorite. Both these data sets would be eventually merged in the repository and passed on to a view model so that it can be displayed on a view i.e. our activity shown above. So lets start by defining the <em>favorite </em>entity:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.mergedlivedata.entity

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "favourite_table")
class Favourite(@PrimaryKey @ColumnInfo(name = "foursquareId") var foursquareId: String,
    @ColumnInfo(name = "fav") var favourite: Boolean)</pre>



<p>Next lets define the DAO functions for fetching and modifying the data from database:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.mergedlivedata.dao

import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.truiton.mergedlivedata.entity.Favourite

@Dao
interface FavouriteDao {

    @Query("SELECT * from favourite_table")
    fun getAllFavourites(): LiveData&lt;List&lt;Favourite>>

    @Query("SELECT * from favourite_table WHERE foursquareId LIKE :id")
    fun getFavouritesById(id: String): List&lt;Favourite>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(favourite: Favourite)

    @Query("DELETE FROM favourite_table")
    fun deleteAll()
}</pre>



<p style="text-align:justify">You can find the full implementation for room database, retrofit client and interfaces in the GitHub link shared at the end of the tutorial. Next we can define the repository where we will generate a merged Android LiveData by combining mentioned two LiveData sources:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.mergedlivedata

import androidx.annotation.WorkerThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import com.truiton.mergedlivedata.dao.FavouriteDao
import com.truiton.mergedlivedata.entity.Favourite
import com.truiton.mergedlivedata.model.Venues
import com.truiton.mergedlivedata.rest.FSInterface
import com.truiton.mergedlivedata.rest.RetrofitService


class FourSquareRepo(private val favouriteDao: FavouriteDao) {

    val allVenues: MutableLiveData&lt;List&lt;Venues>> = MutableLiveData()
    var foursquareApi = RetrofitService.createService(FSInterface::class.java)
    val mediatorLiveData = MediatorLiveData&lt;List&lt;Venues>>()
    var roomLiveData: LiveData&lt;List&lt;Venues>> = MutableLiveData()

    init {
        allVenues.value = emptyList()

        mediatorLiveData.addSource(allVenues) {
            mediatorLiveData.value = it
        }

        roomLiveData = Transformations.switchMap(favouriteDao.getAllFavourites()) { favs -> getVenues(favs) }
        mediatorLiveData.addSource(roomLiveData) {
            mediatorLiveData.value = it
        }
    }

    private fun getVenues(favourites: List&lt;Favourite>?): LiveData&lt;List&lt;Venues>>? {
        val venues: MutableLiveData&lt;List&lt;Venues>> = MutableLiveData()
        var list = ArrayList&lt;Venues>(allVenues.value!!)
        for (fav in favourites!!) {
            for (venue in list) {
                if (fav.foursquareId == venue.id) {
                    venue.favourite = fav
                }
            }
        }
        venues.value = list
        return venues
    }


    @WorkerThread
    suspend fun insert(favourite: Favourite) {
        favouriteDao.insert(favourite)
    }

    @WorkerThread
    suspend fun getNearbyPlaces(query: String) {
        val foursquareResponse =
            foursquareApi.getPlacesList(
                "your client_id",
                "your client_secret",
                "Seattle,+WA",
                query,
                "20180401",
                "20"
            )
        if (foursquareResponse.isSuccessful) {
            var list = foursquareResponse.body()!!.response.venues.toMutableList()
            for (venue in list) {
                if (favouriteDao.getFavouritesById(venue.id).isNotEmpty()) {
                    venue.favourite = favouriteDao.getFavouritesById(venue.id)[0]
                }
            }
            allVenues.postValue(list)
        } else {
            allVenues.postValue(emptyList())
        }

    }
}
</pre>



<p style="text-align:justify">As you can see in the above piece of code we have generated a merged LiveData object <code>mediatorLiveData</code> by merging <code>allVenues</code> data and <code>roomLiveData</code> which are responses from the API call and room database respectively. To do so we have used <a rel="noreferrer noopener" href="https://developer.android.com/reference/androidx/lifecycle/Transformations.html#switchMap(androidx.lifecycle.LiveData%3CX%3E,%20androidx.arch.core.util.Function%3CX,%20androidx.lifecycle.LiveData%3CY%3E%3E)" target="_blank"><code>Transformations.switchMap</code></a>, which helped us in calling a function in the repository itself through which we modified the structure of every object which being returned in LiveData, without putting an observer. The advantage of using a switchMap here for merging android LiveData objects is that it returns a LiveData object. To actually use this piece of code and display data on the screen please have a look at the full source code at the GitHub link below.</p>



<div class="wp-block-button aligncenter is-style-default"><a class="wp-block-button__link has-text-color has-very-light-gray-color has-background has-vivid-cyan-blue-background-color" href="https://github.com/Truiton/MergedLiveData">Full Source Code</a></div>



<p style="text-align:justify">You can see in the full source code that we have used MutableLiveData objects, transformations and MediatorLiveData to merge and pass on the data. To see the merged LiveData in action you need to implement the ViewModel class along with an Activity with all the components for a RecyclerView. In this Android LiveData merging example we have tried to build a sample with all the latest architecture principles, if you wish to implement similar functionality in a different architecture, feel free to do so. </p>



<p></p>



<p style="text-align:justify">In this <a href="https://www.truiton.com/2019/11/merging-android-livedata/">Android merged LiveData example</a> we merged two LiveData sources, one from a web API and the other one from a local database, but in real world scenarios there could be situation where you would want to merge more than two LiveData objects. Let me assure you and say all those scenarios can be achieved by using transformations and the approach mentioned in this tutorial. Also it is not possible to cover all the capabilities of LiveData in a single article as there are infinite use-cases where it can be used. For example merging error and success LiveData responses in a single stream or combining different object types in a single stream of LiveData. For more such use-cases stay connected with us on twitter, and Facebook, also if you like this tutorial please share it with your friends and subscribe to our newsletter.</p>
<p>The post <a href="https://www.truiton.com/2019/11/merging-android-livedata/">Merging Android LiveData</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2019/11/merging-android-livedata/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3772</post-id>	</item>
		<item>
		<title>Android Chips Example: Material Design</title>
		<link>https://www.truiton.com/2018/10/android-chips-example-material-design/</link>
					<comments>https://www.truiton.com/2018/10/android-chips-example-material-design/#respond</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Sun, 21 Oct 2018 06:27:20 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Material Design]]></category>
		<category><![CDATA[Material Design Backward Compatibility]]></category>
		<guid isPermaLink="false">https://www.truiton.com/?p=2119</guid>

					<description><![CDATA[<p>Google&#8217;s material design has been evolving year by year. At first when Material Design was introduced a lot of new components were listed in its documentation. But their implementation or official widgets were not released at that time. But&#160;with every support library release, few new significant components are released. With this year&#8217;s Google I/O, Androidx&#8230;&#160;<a href="https://www.truiton.com/2018/10/android-chips-example-material-design/" rel="bookmark">Read More &#187;<span class="screen-reader-text">Android Chips Example: Material Design</span></a></p>
<p>The post <a href="https://www.truiton.com/2018/10/android-chips-example-material-design/">Android Chips Example: Material Design</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter is-resized"><img data-recalc-dims="1" loading="lazy" decoding="async" data-attachment-id="2182" data-permalink="https://www.truiton.com/2018/10/android-chips-example-material-design/featured-android_chips/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?fit=950%2C530&amp;ssl=1" data-orig-size="950,530" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="Android Chips Example Featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?fit=950%2C530&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?resize=580%2C323&#038;ssl=1" alt="Android Chips Example Featured" class="wp-image-2182" width="580" height="323" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?w=950&amp;ssl=1 950w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?resize=768%2C428&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?resize=640%2C357&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Featured-Android_Chips.jpg?resize=600%2C335&amp;ssl=1 600w" sizes="auto, (max-width: 580px) 100vw, 580px" /></figure></div>



<p></p>



<p>Google&#8217;s material design has been evolving year by year. At first when Material Design was introduced a lot of new components were listed in its documentation. But their implementation or official widgets were not released at that time. But&nbsp;with every support library release, few new significant components are released. With this year&#8217;s Google I/O, Androidx was released as a new implementation for Android&#8217;s support library framework, along with this a new material design component library was also released. As I mentioned above a few new components were released this year too, one of them is Android Chip. This new Android chips widget is now a part of design support library v28 and has also been introduced in this new material design component library 1.0.0. This library has many components but in this article we will be discussing on Android chips only and how to make an Android chips example, via the new <a href="https://material.io/develop/android/docs/getting-started/" target="_blank" rel="noopener noreferrer">Material Component library</a>.</p>



<p>Android Pill button or chips have always been a part of our apps. One way or the other building a button like a pill has never been a difficult task for us. But now that Google has&nbsp;officially released a widget by the name of <a href="https://developer.android.com/reference/com/google/android/material/chip/Chip" target="_blank" rel="noopener noreferrer">Chips</a>, it will definitely make our lives easier to some level. In this Android chips example we would learn how to make an android chip button which looks like a pill shaped interact-able element. Please note: To make use of this example, you might have to switch over to&nbsp;<code>AndroidX</code>&nbsp;and&nbsp;<code>com.google.android.material</code>&nbsp;packages by refactoring from the Refactor menu of the Android Studio, as the new material library does not work with old support packages. If you wish to use old support libraries for the time being, please use the v28 of it. It has the Chip widget.</p>



<h2 class="wp-block-heading">Exploring Material Design : Android Chips Example</h2>



<p>Generally Android chips are used to capture user input, filter content, trigger actions and simply to make a selection from a choice of options. It should not be used in a situation where a single call to action has to be performed. One of the most obvious example of Android Chips, that you must have seen, should be the Gmail app. In Gmail app when an email address is entered, it is shown in an Android Chip like view. If you wish to make a UI element which looks like the gmail email address pill button type view, you should use the Android Chip widget. To start with the implementation part, first you would have to include the following dependency in your gradle file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">dependencies { 
implementation 'com.google.android.material:material:1.0.0' 
}</pre>



<p><span style="color: #23282d; font-family: Roboto; font-size: 1.4em; font-weight: inherit;">Using Android Chips with Styles</span></p>



<p>In simple terms Android Chip is just a combined object of text, icon and optional close icon. With this, the new material design component also gives us a few new attributes to change its appearance and behavior. It allows us to make it&nbsp;represent an attribute, text, entity, or perform an action. This eventually allows the user to trigger an action, filter content, select a choice, or enter information. Also if you have to represent a contact with image, this Android chip can be of good use. To have a more detailed look at the chips, lets have a look at its styles.</p>



<h4 class="wp-block-heading">Action Chip (Default)</h4>



<p>The most basic chip of all the available ones is the Action chip. Its a single actionable chip, in short its an alternative to the button widget. If you have to perform an action, based on users tap, this is the chip that you should use. Generally this type of chip is placed after the content of the page and is used as a clickable, just like a button. Have a look at the images below to understand its usage.</p>



<ul data-carousel-extra='{&quot;blog_id&quot;:1,&quot;permalink&quot;:&quot;https://www.truiton.com/2018/10/android-chips-example-material-design/&quot;}'  class="wp-block-gallery columns-2 is-cropped wp-block-gallery-6 is-layout-flex wp-block-gallery-is-layout-flex"><li class="blocks-gallery-item"><figure><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-1.jpg?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="426" height="213" data-attachment-id="2184" data-permalink="https://www.truiton.com/2018/10/android-chips-example-material-design/android-chips-example-1/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-1.jpg?fit=426%2C213&amp;ssl=1" data-orig-size="426,213" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="Android chips example -1" data-image-description="" data-image-caption="&lt;p&gt;Android Action Chip Example 1&lt;/p&gt;
" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-1.jpg?fit=300%2C150&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-1.jpg?fit=426%2C213&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-1.jpg?resize=426%2C213&#038;ssl=1" alt="Android chips example -1" data-id="2184" class="wp-image-2184" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-1.jpg?w=426&amp;ssl=1 426w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-1.jpg?resize=300%2C150&amp;ssl=1 300w" sizes="auto, (max-width: 426px) 100vw, 426px" /></a></figure></li><li class="blocks-gallery-item"><figure><a href="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-2.jpg?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="426" height="213" data-attachment-id="2185" data-permalink="https://www.truiton.com/2018/10/android-chips-example-material-design/android-chips-example-2/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-2.jpg?fit=426%2C213&amp;ssl=1" data-orig-size="426,213" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="Android chips example -2" data-image-description="" data-image-caption="&lt;p&gt;Android Action Chip Example 2&lt;/p&gt;
" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-2.jpg?fit=300%2C150&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-2.jpg?fit=426%2C213&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-2.jpg?resize=426%2C213&#038;ssl=1" alt="Android chips example -2" data-id="2185" class="wp-image-2185" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-2.jpg?w=426&amp;ssl=1 426w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-2.jpg?resize=300%2C150&amp;ssl=1 300w" sizes="auto, (max-width: 426px) 100vw, 426px" /></a></figure></li></ul>



<p>To make a working example of Android action chip, you can either define it in the XML or you can insert it dynamically by Java/Kotlin code. In this Android chips example, we will do so by XML and will use its properties in Java code. Please have a look below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    &lt;com.google.android.material.chip.Chip
        android:id="@+id/action_chip"
        style="@style/Widget.MaterialComponents.Chip.Action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/action_chip_txt"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:padding="10dp"
        android:text="Hello World"
        app:chipIcon="@drawable/ic_android_24dp"
        app:iconStartPadding="5dp"/></pre>



<p>In the above code, please see that we have defined a style tag <code>style="@style/Widget.MaterialComponents.Chip.Action"</code>. This is used to define the style for action chip, but in case if this is missing, it would still render an Android chip with &#8216;Action&#8217; style. As this is also the default style. Moving ahead, to capture this Android chip&#8217;s click event, we use this piece of code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        Chip actionChip = findViewById(R.id.action_chip);
        actionChip.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i(TAG, "Clicked action chip");
            }
        });</pre>



<h4 class="wp-block-heading">Entry Chip (Input Chip)</h4>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="666" height="207" data-attachment-id="2193" data-permalink="https://www.truiton.com/2018/10/android-chips-example-material-design/android-chips-example-3/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?fit=666%2C207&amp;ssl=1" data-orig-size="666,207" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android chips example -3" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?fit=300%2C93&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?fit=666%2C207&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?resize=666%2C207&#038;ssl=1" alt="Android Chips Example - Entry Chip" class="wp-image-2193" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?w=666&amp;ssl=1 666w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?resize=300%2C93&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?resize=640%2C199&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-3.jpg?resize=600%2C186&amp;ssl=1 600w" sizes="auto, (max-width: 666px) 100vw, 666px" /></figure></div>



<p>Another type of chip is the input one, this chip used display captured user input in a non editable format. Its a very nice way to showcase the user input. One of the most obvious usages of Android Entry chip is shown in the gmail app. Particularly the email input experience- when an email is entered by the user, it is showcased as an entry chip, sort of a pill shaped layout. Now according to the material design this element should be an Android Chip with style as &#8216;Entry&#8217;. This chip can also have a close icon along with a chip icon. Generally this type of chip is contained in a <code><code></code></code><a href="https://developer.android.com/reference/com/google/android/material/chip/ChipGroup" target="_blank" rel="noopener noreferrer">ChipGroup</a>. ChipGoup class is similar to <code><code></code></code><a href="https://developer.android.com/reference/android/widget/RadioGroup" target="_blank" rel="noopener noreferrer">RadioGroup</a> class, as it is used to hold multiple chips. It has the properties to display all the chips in a single line. Have a look at the images below to have a better understanding on how the entry chips would look:</p>



<p>In case of Android entry chips, in the XML we will create an empty <code>ChipGroup</code> and add chips programmatically. Lets have a look at the layout.xml of the activity:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    &lt;com.google.android.material.chip.ChipGroup
        android:id="@+id/entry_chip_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/entry_chip_txt">

    &lt;/com.google.android.material.chip.ChipGroup></pre>



<p>Now since we will be adding chips dynamically through code, a big challenge would be to maintain style along the chips. As per my understanding to maintain consistent styles there are two ways, either by code we style it and use in a loop. Or we create a standard chip style in XML and use it across. Interestingly Android Chips widget also supports a <code><code></code></code><a href="https://developer.android.com/reference/com/google/android/material/chip/ChipDrawable" target="_blank" rel="noopener noreferrer">ChipDrawable</a> class through which we can create a chip dynamically, and this <code>ChipDrawable</code> object can be created by using an XML resource. Therefore as per the principle I like this way better, have a look at my chip style which I used to inject a chip in <code>ChipGroup</code> :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;chip
    style="@style/Widget.MaterialComponents.Chip.Entry"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:checkable="false"
    app:chipIcon="@drawable/ic_android_24dp"
    app:iconStartPadding="5dp"/></pre>



<p>Next to create an Input Chip dynamically we need to define a method :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    private Chip getChip(final ChipGroup entryChipGroup, String text) {
        final Chip chip = new Chip(this);
        chip.setChipDrawable(ChipDrawable.createFromResource(this, R.xml.my_chip));
        int paddingDp = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 10,
                getResources().getDisplayMetrics()
        );
        chip.setPadding(paddingDp, paddingDp, paddingDp, paddingDp);
        chip.setText(text);
        chip.setOnCloseIconClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                entryChipGroup.removeView(chip);
            }
        });
        return chip;
    }</pre>



<p>And this is how an Android Entry Chip is inserted in the chip group:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">final ChipGroup entryChipGroup = findViewById(R.id.entry_chip_group);
final Chip entryChip = getChip(entryChipGroup, "Hello World");
final Chip entryChip2 = getChip(entryChipGroup, "Test");
entryChipGroup.addView(entryChip);
entryChipGroup.addView(entryChip2);</pre>



<h4 class="wp-block-heading">Filter Chip</h4>



<p>These type of chips should be used in situations exactly as its name suggests, i.e. for creating filters. Android filter chips are similar to check boxes, in a way they should be used to filter the content. For example if you have to show a UI where there&#8217;s a list and user has to filter a specific type of content from it, in this situation a filter chip would be an apt solution. Generally filter chips do not have a icon attached to them, as a check icon is displayed once a chip is selected. Please have a look at the images below:</p>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="462" height="195" data-attachment-id="2196" data-permalink="https://www.truiton.com/2018/10/android-chips-example-material-design/android-chips-example-4/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-4.jpg?fit=462%2C195&amp;ssl=1" data-orig-size="462,195" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android chips example -4" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-4.jpg?fit=300%2C127&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-4.jpg?fit=462%2C195&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-4.jpg?resize=462%2C195&#038;ssl=1" alt="Android chips example -4" class="wp-image-2196" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-4.jpg?w=462&amp;ssl=1 462w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-4.jpg?resize=300%2C127&amp;ssl=1 300w" sizes="auto, (max-width: 462px) 100vw, 462px" /></figure></div>



<p>Further lets define the XML for Android Filter Chips, they have&nbsp;<code>style="@style/Widget.MaterialComponents.Chip.Filter"</code> :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    &lt;com.google.android.material.chip.ChipGroup
        android:id="@+id/filter_chip_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/filter_chip_txt">

        &lt;com.google.android.material.chip.Chip
            android:id="@+id/filter_chip"
            style="@style/Widget.MaterialComponents.Chip.Filter"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_marginLeft="10dp"
            android:layout_marginStart="10dp"
            android:text="Dogs"/>

        &lt;com.google.android.material.chip.Chip
            android:id="@+id/filter_chip2"
            style="@style/Widget.MaterialComponents.Chip.Filter"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:text="Cats"/>
    &lt;/com.google.android.material.chip.ChipGroup></pre>



<p>Now that we have filter chips in place, we need to detect clicks on the filter chips. We can do so simply by attaching a OnCheckedChangeListener to it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        ChipGroup filterChipGroup = findViewById(R.id.filter_chip_group);
        Chip filterChip = findViewById(R.id.filter_chip);
        Chip filterChip2 = findViewById(R.id.filter_chip2);
        CompoundButton.OnCheckedChangeListener filterChipListener = new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.i(TAG, buttonView.getId() + "");
            }
        };
        filterChip.setOnCheckedChangeListener(filterChipListener);
        filterChip2.setOnCheckedChangeListener(filterChipListener);</pre>



<h4 class="wp-block-heading">Filter Chip &#8211; Single Selection Mode</h4>



<p>In this <a href="https://www.truiton.com/2018/10/android-chips-example-material-design/">Android Chips Example</a>, I will also show a filter chip with single selection mode. In this mode, filter chips would start acting as a radio button. This means in a way only one selection can be made at a time. This functionality is achieved by adding all the filter chips in a <code>ChipGroup</code> and setting the property : <code>app:singleSelection="true"</code>&nbsp;of Chip Group. To have a better understanding, lets have a look at the layout XML file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    &lt;com.google.android.material.chip.ChipGroup
        android:id="@+id/filter_chip_SS_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/filter_chip_ss_txt"
        app:singleSelection="true">

        &lt;com.google.android.material.chip.Chip
            android:id="@+id/filter_ss_chip"
            style="@style/Widget.MaterialComponents.Chip.Filter"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_marginLeft="10dp"
            android:layout_marginStart="10dp"
            android:text="Dogs"/>

        &lt;com.google.android.material.chip.Chip
            android:id="@+id/filter_ss_chip2"
            style="@style/Widget.MaterialComponents.Chip.Filter"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:text="Cats"/>
    &lt;/com.google.android.material.chip.ChipGroup></pre>



<p>Next to capture the selected chip out of all chips, we need to attach a&nbsp;<code>ChipGroup.OnCheckedChangeListener()</code> on the <code>ChipGroup</code>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        ChipGroup filterChipGroupSingleSelection = findViewById(R.id.filter_chip_SS_group);
        filterChipGroupSingleSelection.setOnCheckedChangeListener(new ChipGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(ChipGroup group, @IdRes int checkedId) {
                // Handle the checked chip change.
                Log.i(TAG, "ID: " + group.getCheckedChipId());
            }
        });</pre>



<p>Please Note: This <code>ChipGroup.OnCheckedChangeListener()</code> would return callbacks only when single selection mode is set to <code>true</code>.</p>



<h4 class="wp-block-heading">Choice Chip</h4>



<p>A perfect example of choice chip is similar to the filter chip one. Choice chip allows the user to select only one of the available options just like the filter chips. But with one difference, it does not have a check icon on it. Instead according to material design guidelines, it displays the selection with a change of color, when it is selected. If you wish you can use a chipIcon with this chip. But ideally they should be used wherever you feel the need to show RadioButton. Lets have a look at the UI for Android Choice Chip:</p>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="360" height="189" data-attachment-id="2198" data-permalink="https://www.truiton.com/2018/10/android-chips-example-material-design/android-chips-example-5/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-5.jpg?fit=360%2C189&amp;ssl=1" data-orig-size="360,189" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android chips example -5" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-5.jpg?fit=300%2C158&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-5.jpg?fit=360%2C189&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-5.jpg?resize=360%2C189&#038;ssl=1" alt="Android chips example -5" class="wp-image-2198" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-5.jpg?w=360&amp;ssl=1 360w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/10/Android-chips-example-5.jpg?resize=300%2C158&amp;ssl=1 300w" sizes="auto, (max-width: 360px) 100vw, 360px" /></figure></div>



<p>To use the choice chip, we use&nbsp;<code>style="@style/Widget.MaterialComponents.Chip.Choice"</code> parameter in the XML. Lets have a look at the XML:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    &lt;com.google.android.material.chip.ChipGroup
        android:id="@+id/choice_chip_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/choice_chip_txt"
        app:singleSelection="true">

        &lt;com.google.android.material.chip.Chip
            android:id="@+id/choice_chip"
            style="@style/Widget.MaterialComponents.Chip.Choice"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_marginLeft="10dp"
            android:layout_marginStart="10dp"
            android:text="Cars"/>

        &lt;com.google.android.material.chip.Chip
            android:id="@+id/choice_chip2"
            style="@style/Widget.MaterialComponents.Chip.Choice"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:text="Trucks"/>
    &lt;/com.google.android.material.chip.ChipGroup></pre>



<p>As shown in this Android Chips Example earlier, ChipGroup can return the selected chip only when single selection mode is set to true. Even here we will utilize the same property and capture the selection:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">        ChipGroup choiceChipGroup = findViewById(R.id.choice_chip_group);
        choiceChipGroup.setOnCheckedChangeListener(new ChipGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(ChipGroup chipGroup, @IdRes int i) {
                Log.i(TAG, i + "");
            }
        });</pre>



<p>If you wish to have a look at all the working sample of the Android Chip types mentioned above, please have a look at the full source code here:&nbsp;</p>



<p style="text-align:center"><a class="fasc-button fasc-size-large fasc-type-flat fasc-rounded-medium ico-fa fasc-ico-before fa-github" style="background-color: #0364af; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="https://github.com/Truiton/ChipsExample">Full Source Code</a>&nbsp;</p>



<p>In this Android Chips Example, as you can see we built a working sample of all the chip styles, by using the latest Google&#8217;s material library. Here in this tutorial we also showcased, that a chip has the properties of a radio button as well as a check box. In a way its a better representation of both.&nbsp;You can use it either in a single selection or in multiple selection mode. Both ways it would give a great experience.&nbsp;As the Android Chips are compact, relevant and focused. Hope this example made you understand things better, for latest news on Android connect with us on Twitter, Facebook and Google+. Also subscribe to our newsletter, for news right in your inbox.</p>
<p>The post <a href="https://www.truiton.com/2018/10/android-chips-example-material-design/">Android Chips Example: Material Design</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2018/10/android-chips-example-material-design/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2119</post-id>	</item>
		<item>
		<title>Android AutoCompleteTextView: Suggestions from Web Service Call</title>
		<link>https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/</link>
					<comments>https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/#comments</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Tue, 19 Jun 2018 08:37:26 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[AutoCompleteTextView]]></category>
		<guid isPermaLink="false">http://www.truiton.com/?p=1857</guid>

					<description><![CDATA[<p>When building a mobile app, one of the most basic things to have in an app is an auto suggest box. It is such a common widget that anyone who&#8217;s using an app expects it to be there. But recently I realized that not many Android autocomplete examples exist on the internet where a web&#8230;&#160;<a href="https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/" rel="bookmark">Read More &#187;<span class="screen-reader-text">Android AutoCompleteTextView: Suggestions from Web Service Call</span></a></p>
<p>The post <a href="https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/">Android AutoCompleteTextView: Suggestions from Web Service Call</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="950" height="530" data-attachment-id="1988" data-permalink="https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/autocompletetextview-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?fit=950%2C530&amp;ssl=1" data-orig-size="950,530" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="AutoCompleteTextView &amp;#8211; Featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?fit=950%2C530&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?resize=950%2C530" alt="Android AutoCompleteTextView - Featured" class="wp-image-1988" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?w=950&amp;ssl=1 950w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?resize=768%2C428&amp;ssl=1 768w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?resize=640%2C357&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/03/AutoCompleteTextView-Featured.jpg?resize=600%2C335&amp;ssl=1 600w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure></div>



<p></p>



<p>When building a mobile app, one of the most basic things to have in an app is an auto suggest box. It is such a common widget that anyone who&#8217;s using an app expects it to be there. But recently I realized that not many Android autocomplete examples exist on the internet where a web service or an API call is used to fetch data dynamically. Instead many tutorials are present showing the wrong practices of implementing an Android AutoCompleteTextView with web API call. Hence here I would show how I built an autosuggest feature on my Android app.</p>



<p>To start with lets, understand the new additions in the <a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView" target="_blank" rel="noopener noreferrer">AutoCompleteTextView</a> widget. Recently with the release of Android support appcompat library 25.1.0 a background tint support was added and post which the new widget class was named as <a href="https://developer.android.com/reference/android/support/v7/widget/AppCompatAutoCompleteTextView" target="_blank" rel="noopener noreferrer"><code>AppCompatAutoCompleteTextView</code></a>. This new widget class is not much different from the original one, but since its an enhanced version of AutoCompleteTextView we will using this class for this Android AutoCompleteTextView with and API call tutorial.</p>



<h2 class="wp-block-heading">Android AutoCompleteTextView with data from Web API Call example</h2>



<p>To start with, lets define the objectives of this tutorial. Here we will create and Android AutoCompleteTextView example, where data is fetched dynamically from a web API call. Once the data is fetched dynamically based on the user&#8217;s input, we would display it accordingly in a drop down scrolling list. The Android&nbsp;AutoCompleteTextView implementation is so flexible that even its dropdown can also be customised. But to keep things simple and focused, we would keep this out of the scope of this example.</p>



<h3 class="wp-block-heading">1. Prerequisites</h3>



<p>To make any API call in an android app, we must have a REST framework implemented. So that we can have some basic set of features relating to web API call. Since <a href="http://www.truiton.com/2015/02/android-volley-example/" target="_blank" rel="noopener noreferrer">Android Volley</a> is a very simple framework, we would be using volley in this example to make API calls. But just in case, if you are comfortable with any other REST framework, please feel free to use that in your app.</p>



<p>First lets add internet permission in the manifest:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;manifest ...>

    &lt;uses-permission android:name="android.permission.INTERNET" />

    &lt;application .... >
    &lt;/application>
&lt;/manifest></pre>



<p>Secondly lets define a basic class to make an API call through the app.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.autosuggesttextviewapicall;

import android.content.Context;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

/**
 * Created by MG on 04-03-2018.
 */

public class ApiCall {
    private static ApiCall mInstance;
    private RequestQueue mRequestQueue;
    private static Context mCtx;

    public ApiCall(Context ctx) {
        mCtx = ctx;
        mRequestQueue = getRequestQueue();
    }

    public static synchronized ApiCall getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new ApiCall(context);
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
        }
        return mRequestQueue;
    }

    public &lt;T> void addToRequestQueue(Request&lt;T> req) {
        getRequestQueue().add(req);
    }

    public static void make(Context ctx, String query, Response.Listener&lt;String>
            listener, Response.ErrorListener errorListener) {
        String url = "https://itunes.apple.com/search?term=" + query
                + "&amp;country=US";
        StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
                listener, errorListener);
        ApiCall.getInstance(ctx).addToRequestQueue(stringRequest);
    }
}
</pre>



<p>Method to take note of in the class above is <code>make</code>, as this is the only static method in this class. This method would be used to make an API call for the Android&nbsp;AutoCompleteTextView implementation ahead. Internally this method would create a request queue for volley and handle all the network I/O itself. Also in the above class, I just defined a basic example of Android volley request queue, through which we will be making an API call for the implementation of Android&nbsp;AutoCompleteTextView showing dynamic data from the same. To learn more in detail on Android volley please refer to my <a href="http://www.truiton.com/2015/02/android-volley-example/" target="_blank" rel="noopener noreferrer">tutorial on it here</a>.</p>



<h3 class="wp-block-heading">2. Define an Adapter for Android&nbsp;AutoCompleteTextView with dynamic data from API call</h3>



<p>As you may know, the drop down list shown on top of an&nbsp;<code>AutoCompleteTextView</code> is just a <code>ListView</code> inside of the overflow. Therefore as per principle, we have to make an adapter for the underlying <code>ListView</code>. Now since we are going to use an adapter, where only data needs to be shown in a form of list and also we don&#8217;t need any sort of processing on the list therefore we would use an <a href="https://developer.android.com/reference/android/widget/ArrayAdapter" target="_blank" rel="noopener noreferrer"><code>ArrayAdapter</code></a>. But keeping the future improvements in mind we will also implement a <code>Filterable</code> interface. This can help us in processing the list as well without making an API call.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.autosuggesttextviewapicall;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;

import java.util.ArrayList;
import java.util.List;

public class AutoSuggestAdapter extends ArrayAdapter&lt;String> implements Filterable {
    private List&lt;String> mlistData;

    public AutoSuggestAdapter(@NonNull Context context, int resource) {
        super(context, resource);
        mlistData = new ArrayList&lt;>();
    }

    public void setData(List&lt;String> list) {
        mlistData.clear();
        mlistData.addAll(list);
    }

    @Override
    public int getCount() {
        return mlistData.size();
    }

    @Nullable
    @Override
    public String getItem(int position) {
        return mlistData.get(position);
    }

    /**
     * Used to Return the full object directly from adapter.
     *
     * @param position
     * @return
     */
    public String getObject(int position) {
        return mlistData.get(position);
    }

    @NonNull
    @Override
    public Filter getFilter() {
        Filter dataFilter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint != null) {
                    filterResults.values = mlistData;
                    filterResults.count = mlistData.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results != null &amp;&amp; (results.count > 0)) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return dataFilter;
    }
}
</pre>



<p>The above piece of code would turn out to be a fully functional <code>ArrayAdapter</code>, with the capability of setting the data without instantiating the adapter object once again. Also this would have a <code>Filterable</code> implementation, therefore it would be perfect example for an Android&nbsp;<code>AutoCompleteTextView</code>&nbsp;where suggestions from an API call are shown.</p>



<h3 class="wp-block-heading">3. Using Android&nbsp;AppCompatAutoCompleteTextView with web API call</h3>



<p>As mentioned earlier for this tutorial we will be using Android&nbsp;AppCompatAutoCompleteTextView widget for building an auto suggest experience, as this widget gives an extra advantage over standard implementation. That is with this new one, we can set background tint color and modify it dynamically with <code>ViewCompat</code> methods. Lets start by defining a layout:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.truiton.autosuggesttextviewapicall.MainActivity">

    &lt;android.support.v7.widget.AppCompatAutoCompleteTextView
        android:id="@+id/auto_complete_edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_margin="10dp"
        android:inputType="text"
        android:maxLines="1"/>

    &lt;TextView
        android:id="@+id/selected_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/auto_complete_edit_text"
        android:layout_marginTop="50dp"
        android:padding="20dp"/>

&lt;/RelativeLayout>
</pre>



<p>Next to implement an Android AppCompatAutoCompleteTextView where&nbsp;suggestions come from a WebService call, we need to define an activity where all of this is done.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.autosuggesttextviewapicall;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatAutoCompleteTextView;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.TextView;

import com.android.volley.Response;
import com.android.volley.VolleyError;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private static final int TRIGGER_AUTO_COMPLETE = 100;
    private static final long AUTO_COMPLETE_DELAY = 300;
    private Handler handler;
    private AutoSuggestAdapter autoSuggestAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final AppCompatAutoCompleteTextView autoCompleteTextView =
                findViewById(R.id.auto_complete_edit_text);
        final TextView selectedText = findViewById(R.id.selected_item);

        //Setting up the adapter for AutoSuggest
        autoSuggestAdapter = new AutoSuggestAdapter(this,
                android.R.layout.simple_dropdown_item_1line);
        autoCompleteTextView.setThreshold(2);
        autoCompleteTextView.setAdapter(autoSuggestAdapter);
        autoCompleteTextView.setOnItemClickListener(
                new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView&lt;?> parent, View view,
                                            int position, long id) {
                        selectedText.setText(autoSuggestAdapter.getObject(position));
                    }
                });

        autoCompleteTextView.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int
                    count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                                      int count) {
                handler.removeMessages(TRIGGER_AUTO_COMPLETE);
                handler.sendEmptyMessageDelayed(TRIGGER_AUTO_COMPLETE,
                        AUTO_COMPLETE_DELAY);
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        handler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                if (msg.what == TRIGGER_AUTO_COMPLETE) {
                    if (!TextUtils.isEmpty(autoCompleteTextView.getText())) {
                        makeApiCall(autoCompleteTextView.getText().toString());
                    }
                }
                return false;
            }
        });
    }

    private void makeApiCall(String text) {
        ApiCall.make(this, text, new Response.Listener&lt;String>() {
            @Override
            public void onResponse(String response) {
                //parsing logic, please change it as per your requirement
                List&lt;String> stringList = new ArrayList&lt;>();
                try {
                    JSONObject responseObject = new JSONObject(response);
                    JSONArray array = responseObject.getJSONArray("results");
                    for (int i = 0; i &lt; array.length(); i++) {
                        JSONObject row = array.getJSONObject(i);
                        stringList.add(row.getString("trackName"));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //IMPORTANT: set data here and notify
                autoSuggestAdapter.setData(stringList);
                autoSuggestAdapter.notifyDataSetChanged();
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });
    }
}
</pre>



<p>The above implementation of an Android&nbsp;<code>AppCompatAutoCompleteTextView</code> is a bit different from the regular implementation. Here firstly an adapter is instantiated, which we defined in the previous section of tutorial. Secondly an instance of&nbsp;<code>AdapterView.OnItemClickListener()</code> is set, to capture the clicks on the dropdown items. Next one of the most important part, a <code>TextWatcher</code> is attached to the <code>AutoCompleteTextView</code>. This <code>TextWatcher</code> captures all the all the user inputs and sends it to a handler. Here in this Android&nbsp;AutoCompleteTextView example, we are processing the changes of <code>EditText</code> via a delayed handler. In a way, this approach saves us some unnecessary web API calls, as a delay in consecutive requests is introduced with the help of <code>Handler</code> class. Once a successful call is reached to the handler, we make an API call which returns the results in expected form and they are shown with the help of an Adapter. This way, data is shown on the AutoCompleteTextView drop down. To view the full source code, please checkout the link below:</p>



<p style="text-align:center"><a class="fasc-button fasc-size-large fasc-type-flat fasc-rounded-medium ico-fa fasc-ico-before fa-github" style="background-color: #0364af; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="https://github.com/Truiton/AutoSuggestTextViewAPICall">Full Source Code</a></p>



<p>This is how the output of the above example would look:</p>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="665" height="1266" data-attachment-id="1989" data-permalink="https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/android-autocompletetextview/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?fit=665%2C1266&amp;ssl=1" data-orig-size="665,1266" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android AutoCompleteTextView" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?fit=158%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?fit=538%2C1024&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?resize=665%2C1266" alt="Android AutoCompleteTextView" class="wp-image-1989" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?w=665&amp;ssl=1 665w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?resize=158%2C300&amp;ssl=1 158w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?resize=538%2C1024&amp;ssl=1 538w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?resize=640%2C1218&amp;ssl=1 640w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2018/06/Android-AutoCompleteTextView.png?resize=600%2C1142&amp;ssl=1 600w" sizes="auto, (max-width: 665px) 100vw, 665px" /></figure></div>



<h2 class="wp-block-heading">Some Important properties of Android AutoCompleteTextView</h2>



<p>Now that we have a fair understanding of how an <a href="http://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/">Android&nbsp;AutoCompleteTextView</a> works, lets have a look at some of its frequently used properties:</p>



<ul class="wp-block-list"><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#setThreshold(int)">setThreshold(int threshold)</a> &#8211; This sets a character input threshold, for triggering the dropdown.</li><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#setCompletionHint(java.lang.CharSequence)">setCompletionHint(CharSequence&nbsp;hint)</a> &#8211; Once the threshold is reached and a dropdown is shown, over the bottom this completion hint is also shown.</li><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#setDropDownBackgroundResource(int)">setDropDownBackgroundResource(int id)</a> &#8211; With the help of this method, you can set a background resource for the dropdown list.</li><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#setDropDownBackgroundDrawable(android.graphics.drawable.Drawable)">setDropDownBackgroundDrawable(Drawable&nbsp;d)</a> &#8211; With this method, we can set a background drawable for auto suggest list. But on a separate note, if you wish to style the Android AutoCompleteTextView dropdown background you can also consider styling the list item of dropdown by using a custom xml for inflating the item(explained in next section).</li></ul>



<h2 class="wp-block-heading">Android AutoCompleteTextView dropdown positioning</h2>



<p>At times when making an Android autosuggest, we wish to move the dropdown and attach it to some other view on screen. This may sound complex, but its very simple to implement with Android&nbsp;AutoCompleteTextView, we just need to define a few properties in xml. To get started, lets discuss some properties for dropdown positioning of Andorid AutoCompleteTextView:</p>



<ul class="wp-block-list"><li><a rel="noopener noreferrer" href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#attr_android:dropDownAnchor" target="_blank">android:dropDownAnchor=&#8221;@id/selected_item&#8221;</a> &#8211; This property basically defines the view to which the dropdown popup of Android AutoSuggest should be attached to. This property can also be used by a java method <a rel="noopener noreferrer" href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#setDropDownAnchor(int)" target="_blank">setDropDownAnchor()</a>.</li></ul>



<p>When using the above property, if the dropdown length goes beyond the keyboard height, in some scenarios it will be automatically detached and positioned on top of the screen. To avoid this behaviour of Android AutoCompleteTextView, we can use the following properties, these will help in curbing the mentioned behaviour:</p>



<ul class="wp-block-list"><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#attr_android:dropDownHeight">android:dropDownHeight</a> &#8211; sets the height of auto suggest drop down.</li><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#attr_android:dropDownHorizontalOffset">android:dropDownHorizontalOffset</a> &#8211; sets the horizontal offset of the list from attached view.</li><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#attr_android:dropDownVerticalOffset">android:dropDownVerticalOffset</a> &#8211; sets the vertical offset of the list from attached view.</li><li><a href="https://developer.android.com/reference/android/widget/AutoCompleteTextView.html#attr_android:dropDownWidth">android:dropDownWidth</a> &#8211; sets the dropdown list width.</li></ul>



<p>Now addressing the issue of custom views in Android&nbsp;AutoCompleteTextView, to do so in the above piece of code firstly you need to make a new layout for the custom list item. Next, that xml resource needs to be specified in the adapter initiation like this: <code>new AutoSuggestAdapter(this,R.layout.custom_dropdown_item);</code>. Once this is done, in the adapter you need to implement the&nbsp;<code>getView()</code> method and use the custom layout xml. This way as a result you would see a list dropdown in an Android&nbsp;AutoCompleteTextView with a custom layout. That said, lets conclude this tutorial and please connect with us on Twitter, Facebook and Google+ for more updates.</p>
<p>The post <a href="https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/">Android AutoCompleteTextView: Suggestions from Web Service Call</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2018/06/android-autocompletetextview-suggestions-from-webservice-call/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1857</post-id>	</item>
		<item>
		<title>Introducing Android Mobile Vision API</title>
		<link>https://www.truiton.com/2017/05/introducing-android-mobile-vision-api/</link>
					<comments>https://www.truiton.com/2017/05/introducing-android-mobile-vision-api/#comments</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Sun, 28 May 2017 17:29:27 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Face Detection]]></category>
		<category><![CDATA[Image Recognition]]></category>
		<category><![CDATA[Mobile Vision API]]></category>
		<category><![CDATA[OCR]]></category>
		<guid isPermaLink="false">http://www.truiton.com/?p=1557</guid>

					<description><![CDATA[<p>In August 2015, Google announced the release of Android Mobile Vision API. At that time this API had mainly three&#160;components Face Detection, Barcode scanner and ways to capture the tracking of objects in real time. But later on some bugs were found in its implementation, due to which the access to this API was restricted&#8230;&#160;<a href="https://www.truiton.com/2017/05/introducing-android-mobile-vision-api/" rel="bookmark">Read More &#187;<span class="screen-reader-text">Introducing Android Mobile Vision API</span></a></p>
<p>The post <a href="https://www.truiton.com/2017/05/introducing-android-mobile-vision-api/">Introducing Android Mobile Vision API</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="950" height="530" data-attachment-id="1741" data-permalink="https://www.truiton.com/2017/05/introducing-android-mobile-vision-api/android-mobile-vision-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?fit=950%2C530&amp;ssl=1" data-orig-size="950,530" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="Android Mobile Vision Featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?fit=950%2C530&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?resize=950%2C530" alt="Android Mobile Vision API" class="wp-image-1741" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?w=950&amp;ssl=1 950w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?resize=600%2C335&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Mobile-Vision-Featured.jpg?resize=768%2C428&amp;ssl=1 768w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure></div>



<p></p>



<p>In August 2015, Google <a href="https://developers.google.com/vision/" target="_blank" rel="noopener noreferrer">announced</a> the release of Android Mobile Vision API. At that time this API had mainly three&nbsp;components Face Detection, Barcode scanner and ways to capture the tracking of objects in real time. But later on some bugs were found in its implementation, due to which the access to this API was restricted by Google&nbsp;to the existing users only. Then recently in <a href="https://developers.google.com/android/guides/releases" target="_blank" rel="noopener noreferrer">June 2016</a> these issues were resolved and Mobile Vision APIs were re-launched. But this time it had a few&nbsp;new features like OCR and scanning of Aztec barcodes. In the next sections lets understand what&nbsp;exactly is the new Mobile Vision API and how can we use it&nbsp;to&nbsp;build an efficient code base.</p>



<h2 class="wp-block-heading">&nbsp;</h2>



<h2 class="wp-block-heading">What is Android Mobile Vision API ?</h2>



<p>Ever wondered how to detect a face, a QR code or a Bar code on an Android Device? If yes; you might have heard of, or used the&nbsp;<a href="http://developer.android.com/reference/android/media/FaceDetector.Face.html" target="_blank" rel="noopener noreferrer">FaceDetector.Face</a>&nbsp;API of the Android framework, or the OpenCV SDK, or maybe you had opted for a cloud based solution like <a href="http://www.truiton.com/2016/06/android-image-recognition-google-cloud-vision-api/" target="_blank" rel="noopener noreferrer">Cloud Vision API</a>,&nbsp;which makes the requests to a web server, fetching the results for&nbsp;scans. But this new Android Mobile Vision API does not make any requests to a web server. Instead it performs real time image/video scanning on the device itself. Although this&nbsp;may sound a little in-effective, but its not. The Mobile Vision API is very efficient and deeply integrated in to the Android system by the means of <a href="https://developers.google.com/android/guides/overview" target="_blank" rel="noopener noreferrer">Google Play Services SDK</a>. This gives this API&nbsp;an added advantage over all other solutions, as&nbsp;being&nbsp;a developer you do not need to integrate any third party SDK to perform media analysis. All you may need to do is <a href="https://developers.google.com/android/guides/setup" target="_blank" rel="noopener noreferrer">integrate the Google Play Services</a> properly and start building on it. Android Mobile Vision API as of now performs&nbsp;three types of image/stream detection as shown in next sections.</p>



<h2 class="wp-block-heading">Setting up Android Mobile Vision&nbsp;Library</h2>



<p>When speaking of this new&nbsp;multipurpose Android offline image recognition library, the only downside is that one has to set it up before the actual usage. Although it does not mean any manual configuration but&nbsp;a tag needs to be added in the application manifest. So that the installer knows that an extra package is needed to be downloaded as the app is being installed. As of now the mobile vision API has three components, therefore all&nbsp;three&nbsp;dependencies can be included in a single manifest tag under the application tag as shown:</p>



<pre class="wp-block-preformatted lang:default decode:true">&lt;meta-data
            android:name="com.google.android.gms.vision.DEPENDENCIES"
            android:value="barcode,face,ocr"/&gt;</pre>



<p>This would instruct the OS to download the packages for all three types of offline image analysis. Next lets have a brief understanding of all the features of this powerful Mobile Vision API.</p>



<h3 class="wp-block-heading">1. Barcode and QR Code scanning on Android</h3>



<p>The Barcode Scanner API is used to scan various types of bar codes and qr codes. Some of them are:</p>



<ul class="wp-block-list"><li>1D barcodes: <a href="https://en.wikipedia.org/wiki/International_Article_Number_(EAN)" target="_blank" rel="noopener noreferrer">EAN-13, EAN-8</a>, <a href="https://en.wikipedia.org/wiki/Universal_Product_Code" target="_blank" rel="noopener noreferrer">UPC-A, UPC-E</a>, <a href="https://en.wikipedia.org/wiki/Code_39" target="_blank" rel="noopener noreferrer">Code-39</a>, <a href="https://en.wikipedia.org/wiki/Code_93" target="_blank" rel="noopener noreferrer">Code-93</a>, <a href="https://en.wikipedia.org/wiki/Code_128" target="_blank" rel="noopener noreferrer">Code-128</a>, <a href="https://en.wikipedia.org/wiki/Interleaved_2_of_5" target="_blank" rel="noopener noreferrer">ITF</a>, <a href="https://en.wikipedia.org/wiki/Codabar" target="_blank" rel="noopener noreferrer">Codabar</a></li><li>2D barcodes: <a href="https://en.wikipedia.org/wiki/QR_code" target="_blank" rel="noopener noreferrer">QR Code</a>, <a href="https://en.wikipedia.org/wiki/Data_Matrix" target="_blank" rel="noopener noreferrer">Data Matrix</a>, <a href="https://en.wikipedia.org/wiki/PDF417" target="_blank" rel="noopener noreferrer">PDF-417</a>, <a href="https://en.wikipedia.org/wiki/PDF417" target="_blank" rel="noopener noreferrer">AZTEC</a></li></ul>



<p>Using this Mobile Vision API for Bar codes is very simple, even with so many supported formats. All you need to do is write around&nbsp;10&nbsp;lines of code to parse a Barcode or QR Code.&nbsp;One of the most interesting things about this API is that, it also parses the type of barcode/QR code it is scanning.&nbsp;All the information about the scanned barcode or QR Code type is found in the <code><code></code></code><a href="https://developers.google.com/android/reference/com/google/android/gms/vision/barcode/Barcode.html#valueFormat">valueFormat</a> field of Barcode Object besides the scanned barcode. To learn more about the usage of Barcode Scanner API of the Android Mobile Vision API please refer to this tutorial:</p>



<p style="text-align:center"><a class="fasc-button fasc-size-medium fasc-type-flat fasc-rounded-medium" style="background-color: #33809e; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="http://www.truiton.com/2016/09/android-example-programmatically-scan-qr-code-and-bar-code/">Android Barcode Tutorial</a></p>



<h3 class="wp-block-heading">2. Optical Character Recognition (OCR)&nbsp;on Android</h3>



<p>Mobile Vision Text API is another great feature packed into this library. Its purpose is straight forward, i.e. text recognition in an image or a stream of frames.&nbsp;It can recognize a majority of Latin character based languages like English, French, Italian Dutch etc. Therefore if your app needs to extract text out of an image, this is the perfect solution&nbsp;for you. As once its dependencies are downloaded, you no more required to have an internet connection, all the character recognition takes place on device itself.</p>



<p>Incase you wonder; how would this Android Mobile Vision Text API deliver large results, as when scanning a page of a book- a lot of words could be scanned. But thankfully this API returns text in a structured way. It mainly divides text into three sections:</p>



<ol class="wp-block-list"><li><strong>Block</strong>: Top level structure, contains all the paragraphs.</li><li><strong>Line</strong>: Mid level structure, contains lines in a block.</li><li><strong>Word</strong>: Low level structure, contains a single word from line.</li></ol>



<p>To learn more about the Text API, please refer to this tutorial:</p>



<p style="text-align:center"><a class="fasc-button fasc-size-medium fasc-type-flat fasc-rounded-medium" style="background-color: #33809e; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="http://www.truiton.com/2016/11/optical-character-recognition-android-ocr/">Android OCR Tutorial</a></p>



<h3 class="wp-block-heading">3. Face Detection&nbsp;on Android</h3>



<p>This is the most powerful API in&nbsp;all, as it has human&nbsp;Face Detection capabilities.&nbsp;It is a perfectly suited API for any face filter or camera app, as it performs the analysis on the device itself once the package is downloaded. Interestingly it not only recognizes a face but can also extract the facial features of that face, including eyes nose and mouth etc. Since this API as of now does not support face recognition it cannot identify similarity between two faces, but can still classify the features like, if the eyes are open or not. The functionalities that Mobile Vision Face Detection API supports are:</p>



<ol class="wp-block-list"><li><strong>Landmark Detection:</strong> Face API understands the human face in terms of landmarks.&nbsp;When a face is scanned via this API, it identifies that face via landmarks. In simple terms face landmarks are: nose, mouth, left eye, and right eye etc. By using this API you can actually extract the position of all these landmarks.&nbsp;</li><li><strong>Classification:</strong> This API not only scans a face but can also apply some basic logic and identify certain characteristics on the scanned face. For ex. with this feature we can find out whether the face has its eyes open or not. Also we can find out the probability of a smile on that face.&nbsp;</li><li><strong>Tracking:</strong> This is the most interesting feature of this API, you can actually track a face in a video sequence through this API. This feature of Mobile Vision API can be used to identify and track a face in a video. Once again this is not an application of face recognition, instead it tracks the face through movement of that particular face in the video.&nbsp;</li></ol>



<p>To learn more in detail about Face Detection, please refer to this tutorial:</p>



<p style="text-align:center"><a class="fasc-button fasc-size-medium fasc-type-flat fasc-rounded-medium" style="background-color: #33809e; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="http://www.truiton.com/2017/05/android-face-detection-example/">Face Detection Tutorial</a>&nbsp;</p>



<h2 class="wp-block-heading">Tracking Faces, Bar codes&nbsp;and QR Codes Simultaneously</h2>



<p>Interestingly, if you want to scan and track multiple faces simultaneously, even that is possible through this API. All you need to do is initialize a <a href="https://developers.google.com/android/reference/com/google/android/gms/vision/MultiProcessor" target="_blank" rel="noopener noreferrer">MultiProcessor</a> and track multiple faces through this API. Also if you want to track multiple Bar codes or QR codes, same thing is applicable, as all of this is a part of <a href="http://www.truiton.com/2017/05/introducing-android-mobile-vision-api/">Mobile Vision API</a>, backed by Google Play Services. But even more interesting thing is that you can track Bar codes, QR codes and Faces in a single frame, by using the <a href="https://developers.google.com/android/reference/com/google/android/gms/vision/MultiDetector" target="_blank" rel="noopener noreferrer">MultiDetector</a> class of the same API suite. This makes the mobile vision APIs an outstanding leader in terms of features when compared to any other such library in the market. As its light, easy to integrate and very easy to use. For more updates, please connect with us on Twitter, Facebook and Google+.</p>
<p>The post <a href="https://www.truiton.com/2017/05/introducing-android-mobile-vision-api/">Introducing Android Mobile Vision API</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2017/05/introducing-android-mobile-vision-api/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1557</post-id>	</item>
		<item>
		<title>Android Face Detection Example</title>
		<link>https://www.truiton.com/2017/05/android-face-detection-example/</link>
					<comments>https://www.truiton.com/2017/05/android-face-detection-example/#comments</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Sun, 28 May 2017 16:58:13 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Face Detection]]></category>
		<category><![CDATA[Mobile Vision API]]></category>
		<guid isPermaLink="false">http://www.truiton.com/?p=1728</guid>

					<description><![CDATA[<p>Nowadays face filter apps are one of the most common apps available on a users phone, where a user can apply various funny filters on their face pictures. Interestingly the base tech that powers these sort of apps is similar to what we are going to discuss in this tutorial. That&#8217;s right we are going&#8230;&#160;<a href="https://www.truiton.com/2017/05/android-face-detection-example/" rel="bookmark">Read More &#187;<span class="screen-reader-text">Android Face Detection Example</span></a></p>
<p>The post <a href="https://www.truiton.com/2017/05/android-face-detection-example/">Android Face Detection Example</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="950" height="530" data-attachment-id="1738" data-permalink="https://www.truiton.com/2017/05/android-face-detection-example/android-face-detection-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?fit=950%2C530&amp;ssl=1" data-orig-size="950,530" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="Android Face Detection Featured" data-image-description="" data-image-caption="&lt;p&gt;Android Face Detection Featured&lt;/p&gt;
" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?fit=950%2C530&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?resize=950%2C530" alt="Android Face Detection Featured" class="wp-image-1738" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?w=950&amp;ssl=1 950w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?resize=600%2C335&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-Featured.jpg?resize=768%2C428&amp;ssl=1 768w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure></div>



<p></p>



<p>Nowadays face filter apps are one of the most common apps available on a users phone, where a user can apply various funny filters on their face pictures. Interestingly the base tech that powers these sort of apps is similar to what we are going to discuss in this tutorial. That&#8217;s right we are going to discuss an Android Face Detection API. Interestingly to power all these apps, officially Google has released an Android Face Detection API in&nbsp;their&nbsp;<a href="https://developers.google.com/vision/" target="_blank" rel="noopener noreferrer">Mobile Vision</a>&nbsp;set of APIs. Basically&nbsp;all the face filter apps detect a face through a face detection API, and apply various overlays on the selected picture.&nbsp;Although when speaking of&nbsp;Face Detection APIs for Android, we have multiple options.&nbsp;But for this article we will be discussing Google backed Mobile Vision APIs only. As its fast and has deeply integrated Android development SDK/APIs.</p>



<h2 class="wp-block-heading">Android Face Detection API &#8211; Mobile Vision</h2>



<p>When speaking of face detection, it is often misunderstood by face recognition, therefore let me put it&nbsp;discretely.&nbsp;As of now <a href="http://www.truiton.com/2017/05/introducing-android-mobile-vision-api/" target="_blank" rel="noopener noreferrer">Mobile Vision APIs</a> do not support Face Recognition, right now they only support face detection. Although it does have the ability to identify the characteristics of a face, which includes eyes, nose, mouth and smile etc. But besides these characteristics Mobile Vision Face Detection API can also track a face in a video sequence, which is&nbsp;again not an application of face recognition, but face detection as&nbsp;it is identified&nbsp;by tracking the movement of that particular face in the sequence. Also since this API is a part of Google&#8217;s Play Services library, it is not bundled as a part of the APK, instead an ad-on package is downloaded internally by&nbsp;the play services itself if it is not present to support Android face detection.&nbsp;To do so, we need to set up the play services with the mobile vision&nbsp;dependency in build.gradle file as shown below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">compile 'com.google.android.gms:play-services-vision:11.4.0'</pre>



<p>Also the build.gradle(project) should have this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com"
        }
    }
}</pre>



<p>Post this a <code>&lt;meta-data&gt;</code> tag for face detection api&nbsp;along with <code>&lt;uses-feature&gt;</code> and <code>&lt;uses-permission&gt;</code> tag for camera and accessing external storage needs to be added in the manifest as shown below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;manifest package="com.truiton.mobile.vision.facedetection"
          xmlns:android="http://schemas.android.com/apk/res/android">

    &lt;uses-feature
        android:name="android.hardware.camera"
        android:required="true"/>
    &lt;uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    &lt;application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        &lt;meta-data
            android:name="com.google.android.gms.vision.DEPENDENCIES"
            android:value="face"/>

        &lt;activity android:name=".MainActivity">
            &lt;intent-filter>
                &lt;action android:name="android.intent.action.MAIN"/>

                &lt;category android:name="android.intent.category.LAUNCHER"/>
            &lt;/intent-filter>
        &lt;/activity>
        &lt;provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            &lt;meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        &lt;/provider>
    &lt;/application>

&lt;/manifest></pre>



<h3 class="wp-block-heading">Android Face Detection Library &#8211; Features&nbsp;</h3>



<p>Next lets understand the features of Mobile Vision Face Detection&nbsp;APIs. As amazing things can be done by correct usage&nbsp;of this API. Broadly speaking, this API can perform detailed facial analysis- like detection of facial features and identifying their states. Currently its features can be divided&nbsp;into three categories shown below:</p>



<p><strong>1. Landmark Detection:</strong> One of the most important features of Mobile Vision Face Detection APIs is the detection of facial landmarks. In case you are wondering what are facial landmarks? They are the basic facial features or points of interest, like Nose, Eyes, and Mouth etc. Interestingly these features are detected very accurately by this Android Face Detection API. As of now following facial features are detected by this API:</p>



<ul class="wp-block-list"><li>Landmark.BOTTOM_MOUTH</li><li>Landmark.LEFT_CHEEK</li><li>Landmark.LEFT_EAR_TIP</li><li>Landmark.LEFT_EAR</li><li>Landmark.LEFT_EYE</li><li>Landmark.LEFT_MOUTH</li><li>Landmark.NOSE_BASE</li><li>Landmark.RIGHT_CHEEK</li><li>Landmark.RIGHT_EAR_TIP</li><li>Landmark.RIGHT_EAR</li><li>Landmark.RIGHT_EYE</li><li>Landmark.RIGHT_MOUTH</li></ul>



<p><strong>2. Facial Classification:</strong> Interestingly this API can also apply some logic on the detected facial landmarks and identify facial classifications. For ex. it can be detected through this API&nbsp;if the detected face has its eyes open or is smiling or not. Although this feature set may not sound very impressive as of now; but its very accurate and has a lot of room to grow. Maybe in near future some additional features might come in.</p>



<p><strong>3. Face Tracking:</strong> Another very powerful feature of <em>Mobile Vision Face Detection APIs</em> is this face tracking feature. It simply gives us the ability to track a face in a video sequence. Once again, here I would like to clarify that this is not Face Recognition, this feature simply works on face detection only. As it tracks that&nbsp;face based on its movement in the consecutive video frames.&nbsp;</p>



<h2 class="wp-block-heading">Android Face Detection API &#8211; Example</h2>



<p>Now that we have a basic understanding of how the Face Detection APIs work, here in this section we would build a short example where we showcase its capabilities. Since Android Face Detection is itself a huge topic we would limit the scope of this tutorial, and showcase&nbsp;the Facial Classification feature with Landmark Detection only.&nbsp;Also this would solve our primary use case of Face Detection.&nbsp;Therefore for this <a href="http://www.truiton.com/2017/05/android-face-detection-example/">Android Face Detection Example</a> we would simply take a picture from a camera and run face detection on it, by using the Mobile Vision Face Detection APIs. To start building,&nbsp;lets continue from the steps mentioned in the first section of this article and define a layout to take a picture as shown below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;android.support.constraint.ConstraintLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.truiton.mobile.vision.facedetection.MainActivity">

    &lt;ImageView
        android:id="@+id/imageView"
        android:layout_width="70dp"
        android:layout_height="70dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:srcCompat="@mipmap/truiton"/>

    &lt;Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="Scan Face"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_constraintLeft_creator="1"
        tools:layout_constraintRight_creator="1"
        />

    &lt;TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Scan Results:"
        android:textAllCaps="false"
        android:textStyle="normal|bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_constraintLeft_creator="1"
        tools:layout_constraintRight_creator="1"/>

    &lt;ScrollView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="8dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="1.0"
        tools:layout_constraintBottom_creator="1"
        tools:layout_constraintLeft_creator="1"
        tools:layout_constraintRight_creator="1"
        tools:layout_constraintTop_creator="1">

        &lt;LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            &lt;TextView
                android:id="@+id/results"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="8dp"/>

            &lt;ImageView
                android:id="@+id/scannedResults"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginBottom="8dp"
                android:layout_marginTop="8dp"/>
        &lt;/LinearLayout>
    &lt;/ScrollView>
&lt;/android.support.constraint.ConstraintLayout>
</pre>



<p>Here for this layout I have used <code>ConstraintLayout</code> as my root layout, but its not mandatory to use this for your activity&#8217;s layout. You can also use the normal <code>RelativeLayout</code> or <code>LinearLayout</code> as per your needs, but if you wish to use <code>ConstraintLayout</code>, please don&#8217;t forget to add its dependency in your build.gradle file, as shown below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">compile 'com.android.support.constraint:constraint-layout:1.0.2'</pre>



<p>Also full source code is available at the end of this tutorial. Next lets define the MainActivity for this Android Face Detection tutorial.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.mobile.vision.facedetection;


import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.face.FaceDetector;
import com.google.android.gms.vision.face.Landmark;

import java.io.File;
import java.io.FileNotFoundException;

public class MainActivity extends AppCompatActivity {
    private static final String LOG_TAG = "FACE API";
    private static final int PHOTO_REQUEST = 10;
    private TextView scanResults;
    private ImageView imageView;
    private Uri imageUri;
    private FaceDetector detector;
    private static final int REQUEST_WRITE_PERMISSION = 20;
    private static final String SAVED_INSTANCE_URI = "uri";
    private static final String SAVED_INSTANCE_BITMAP = "bitmap";
    private static final String SAVED_INSTANCE_RESULT = "result";
    Bitmap editedBitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        scanResults = (TextView) findViewById(R.id.results);
        imageView = (ImageView) findViewById(R.id.scannedResults);
        if (savedInstanceState != null) {
            editedBitmap = savedInstanceState.getParcelable(SAVED_INSTANCE_BITMAP);
            if (savedInstanceState.getString(SAVED_INSTANCE_URI) != null) {
                imageUri = Uri.parse(savedInstanceState.getString(SAVED_INSTANCE_URI));
            }
            imageView.setImageBitmap(editedBitmap);
            scanResults.setText(savedInstanceState.getString(SAVED_INSTANCE_RESULT));
        }
        detector = new FaceDetector.Builder(getApplicationContext())
                .setTrackingEnabled(false)
                .setLandmarkType(FaceDetector.ALL_LANDMARKS)
                .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
                .build();
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ActivityCompat.requestPermissions(MainActivity.this, new
                        String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_WRITE_PERMISSION:
                if (grantResults.length &gt; 0 &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    takePicture();
                } else {
                    Toast.makeText(MainActivity.this, "Permission Denied!", Toast.LENGTH_SHORT).show();
                }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PHOTO_REQUEST &amp;&amp; resultCode == RESULT_OK) {
            launchMediaScanIntent();
            try {
                scanFaces();
            } catch (Exception e) {
                Toast.makeText(this, "Failed to load Image", Toast.LENGTH_SHORT).show();
                Log.e(LOG_TAG, e.toString());
            }
        }
    }

    private void scanFaces() throws Exception {
        Bitmap bitmap = decodeBitmapUri(this, imageUri);
        if (detector.isOperational() &amp;&amp; bitmap != null) {
            editedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                    .getHeight(), bitmap.getConfig());
            float scale = getResources().getDisplayMetrics().density;
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setColor(Color.rgb(255, 61, 61));
            paint.setTextSize((int) (14 * scale));
            paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(3f);
            Canvas canvas = new Canvas(editedBitmap);
            canvas.drawBitmap(bitmap, 0, 0, paint);
            Frame frame = new Frame.Builder().setBitmap(editedBitmap).build();
            SparseArray&lt;Face&gt; faces = detector.detect(frame);
            scanResults.setText(null);
            for (int index = 0; index &lt; faces.size(); ++index) {
                Face face = faces.valueAt(index);
                canvas.drawRect(
                        face.getPosition().x,
                        face.getPosition().y,
                        face.getPosition().x + face.getWidth(),
                        face.getPosition().y + face.getHeight(), paint);
                scanResults.setText(scanResults.getText() + "Face " + (index + 1) + "\n");
                scanResults.setText(scanResults.getText() + "Smile probability:" + "\n");
                scanResults.setText(scanResults.getText() + String.valueOf(face.getIsSmilingProbability()) + "\n");
                scanResults.setText(scanResults.getText() + "Left Eye Open Probability: " + "\n");
                scanResults.setText(scanResults.getText() + String.valueOf(face.getIsLeftEyeOpenProbability()) + "\n");
                scanResults.setText(scanResults.getText() + "Right Eye Open Probability: " + "\n");
                scanResults.setText(scanResults.getText() + String.valueOf(face.getIsRightEyeOpenProbability()) + "\n");
                scanResults.setText(scanResults.getText() + "---------" + "\n");

                for (Landmark landmark : face.getLandmarks()) {
                    int cx = (int) (landmark.getPosition().x);
                    int cy = (int) (landmark.getPosition().y);
                    canvas.drawCircle(cx, cy, 5, paint);
                }
            }

            if (faces.size() == 0) {
                scanResults.setText("Scan Failed: Found nothing to scan");
            } else {
                imageView.setImageBitmap(editedBitmap);
                scanResults.setText(scanResults.getText() + "No of Faces Detected: " + "\n");
                scanResults.setText(scanResults.getText() + String.valueOf(faces.size()) + "\n");
                scanResults.setText(scanResults.getText() + "---------" + "\n");
            }
        } else {
            scanResults.setText("Could not set up the detector!");
        }
    }

    private void takePicture() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File photo = new File(Environment.getExternalStorageDirectory(), "picture.jpg");
        imageUri = FileProvider.getUriForFile(MainActivity.this,
                BuildConfig.APPLICATION_ID + ".provider", photo);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, PHOTO_REQUEST);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (imageUri != null) {
            outState.putParcelable(SAVED_INSTANCE_BITMAP, editedBitmap);
            outState.putString(SAVED_INSTANCE_URI, imageUri.toString());
            outState.putString(SAVED_INSTANCE_RESULT, scanResults.getText().toString());
        }
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        detector.release();
    }

    private void launchMediaScanIntent() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        mediaScanIntent.setData(imageUri);
        this.sendBroadcast(mediaScanIntent);
    }

    private Bitmap decodeBitmapUri(Context ctx, Uri uri) throws FileNotFoundException {
        int targetW = 600;
        int targetH = 600;
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(ctx.getContentResolver().openInputStream(uri), null, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;

        return BitmapFactory.decodeStream(ctx.getContentResolver()
                .openInputStream(uri), null, bmOptions);
    }
}
</pre>



<p>In the above piece of code, in <code>onCreate</code> method I have simply&nbsp;initialized the face detector by calling the <code>FaceDetector.Builder(getApplicationContext())</code> builder. This would download the Google Play Service dependencies for performing face detection and initialize them. In a way this also works as a safety measure to download the dependencies even when we specified the app to download the dependencies for face detection in the manifest (shown in first step). Also to make it event more reliable, we have also put a check; to check whether the detector is operational or not just before scanning the actual image in <code>scanFaces()</code> method. Full source code is available&nbsp;here:</p>



<p style="text-align:center"><a class="fasc-button fasc-size-large fasc-type-flat fasc-rounded-medium ico-fa fasc-ico-before fa-github" style="background-color: #0364af; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="https://github.com/Truiton/MobileVisionAPI/tree/master/FaceDetection">Full Source Code</a></p>



<p>Also as you can see above we have initialized the Mobile Vision Face Detector with two capabilities, i.e. <code>setLandmarkType(FaceDetector.ALL_LANDMARKS)</code> and <code>setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)</code>. This would identify all the facial landmarks and classifications on a detected face, rest of the code just shows how we have plotted it on screen, which is self explanatory. The end result would look something like this:</p>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="600" height="967" data-attachment-id="1739" data-permalink="https://www.truiton.com/2017/05/android-face-detection-example/android-face-detection-1/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-1.png?fit=600%2C967&amp;ssl=1" data-orig-size="600,967" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android Face Detection" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-1.png?fit=186%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-1.png?fit=600%2C967&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-1.png?resize=600%2C967" alt="Android Face Detection" class="wp-image-1739" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-1.png?w=600&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-1.png?resize=186%2C300&amp;ssl=1 186w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/05/Android-Face-Detection-1.png?resize=300%2C484&amp;ssl=1 300w" sizes="auto, (max-width: 600px) 100vw, 600px" /></figure></div>



<h2 class="wp-block-heading">Additional Capabilities</h2>



<p>In addition to all what we have discussed above in this <a href="http://www.truiton.com/2017/05/android-face-detection-example/">Android Face Detection Example</a>, there is one more capability present in these Face Detection APIs. That is the face tracking capability with <a href="https://developers.google.com/android/reference/com/google/android/gms/vision/MultiProcessor" target="_blank" rel="noopener noreferrer">MultiProcessor</a>. The great thing about this feature is that it can not only track a single face, but can also track multiple faces in a video sequence. &nbsp;But due to limited scope of this article it is not covered here. Also since the face detection APIs are a part of Google&#8217;s <a href="http://www.truiton.com/2017/05/introducing-android-mobile-vision-api/" target="_blank" rel="noopener noreferrer">Mobile Vision Suite</a>, we have the capability to build a multi detector. Where we can track multiple faces and multiple bar codes or QR codes in a single video sequence by using the <a href="https://developers.google.com/android/reference/com/google/android/gms/vision/MultiDetector" target="_blank" rel="noopener noreferrer">MultiDetector</a> class. This feature is&nbsp;something very new and very powerful which opens a whole new area to explore into. Connect with us on Twitter, Facebook and Google+ for more updates on this.&nbsp;</p>
<p>The post <a href="https://www.truiton.com/2017/05/android-face-detection-example/">Android Face Detection Example</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2017/05/android-face-detection-example/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1728</post-id>	</item>
		<item>
		<title>Android Bottom Navigation Bar Example</title>
		<link>https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/</link>
					<comments>https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/#comments</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Sat, 28 Jan 2017 14:23:50 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[app design guidelines]]></category>
		<category><![CDATA[Design Support Library]]></category>
		<category><![CDATA[Material Design]]></category>
		<guid isPermaLink="false">http://www.truiton.com/?p=1666</guid>

					<description><![CDATA[<p>Its been a while since Google introduced Material Design, but recently with Design Support Library v25&#160;they released a new widget to make an Android Bottom Navigation Bar, as described in the official material design specs. This new navigation component is called the&#160;BottomNavigationView and as mentioned, its packaged under the design support library, having full backward&#8230;&#160;<a href="https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/" rel="bookmark">Read More &#187;<span class="screen-reader-text">Android Bottom Navigation Bar Example</span></a></p>
<p>The post <a href="https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/">Android Bottom Navigation Bar Example</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="950" height="530" data-attachment-id="1671" data-permalink="https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/android-bottom-navigation-bar-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?fit=950%2C530&amp;ssl=1" data-orig-size="950,530" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="Android Bottom Navigation Bar &amp;#8211; Featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?fit=950%2C530&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?resize=950%2C530" alt="Android Bottom Navigation Bar" class="wp-image-1671" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?w=950&amp;ssl=1 950w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?resize=600%2C335&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-Bottom-Navigation-Bar-Featured.jpg?resize=768%2C428&amp;ssl=1 768w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure></div>



<p></p>



<p>Its been a while since Google introduced <a href="http://www.truiton.com/2015/02/android-material-design-backward-compatibility/" target="_blank" rel="noopener noreferrer">Material Design</a>, but recently with <a href="https://developer.android.com/topic/libraries/support-library/revisions.html#rev25-0-0" target="_blank" rel="noopener noreferrer">Design Support Library v25</a>&nbsp;they released a new widget to make an Android Bottom Navigation Bar, as described in the <a href="https://material.io/guidelines/components/bottom-navigation.html" target="_blank" rel="noopener noreferrer">official material design</a> specs. This new navigation component is called the&nbsp;<a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html" target="_blank" rel="noopener noreferrer">BottomNavigationView</a> and as mentioned, its packaged under the design support library, having full backward support. Although if you browse the internet, you may find many examples, showing how to implement an Android bottom navigation bar. But this new Android BottomNavigationView widget makes it very easy for the developers to build and deploy apps with bottom navigation, as its an&nbsp;official component.</p>



<h2 class="wp-block-heading">Android BottomNavigationView Widget</h2>



<p>At first when you look at the new BottomNavigationView widget it may look similar to the <code>TabLayout</code> of the same library. But but do not get confused, as its implementation is a lot different than that of the&nbsp;later one. As the new bottom bar navigation implementation of Android is based out of&nbsp;menu items. Hence to populate a <code>BottomNavigationView</code> you need to specify a menu resource file, unlike in the <code>TabLayout</code>. Although if you look at the final output i.e. the screen, there is still a striking similarity between the two. But putting this discussion to rest, lets have a look at the new features of the Android BottomNavigationView.</p>



<p>Whenever a new component is introduced, along with it some new methods and attributes are also added with it. Hence with the Android&#8217;s official bottom navigation widget the&nbsp;<a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html" target="_blank" rel="noopener noreferrer">BottomNavigationView</a>&nbsp;following new XML attributes are added:</p>



<ul class="wp-block-list"><li><code><code></code></code><a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html#attr_android.support.design:itemBackground" target="_blank" rel="noopener noreferrer">android.support.design:itemBackground</a>&nbsp;&#8211; It is used to set the background color of the navigation item. It does not take a <a href="https://developer.android.com/reference/android/content/res/ColorStateList.html" target="_blank" rel="noopener noreferrer">ColorStateList</a>, as per design specifications.</li><li><code><code></code></code><a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html#attr_android.support.design:itemIconTint" target="_blank" rel="noopener noreferrer">android.support.design:itemIconTint</a>&nbsp;&#8211; It is used to set the icon tint color, use a&nbsp;<a href="https://developer.android.com/reference/android/content/res/ColorStateList.html" target="_blank" rel="noopener noreferrer">ColorStateList</a>&nbsp;to specify colors for all states.</li><li><code><code></code></code><a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html#attr_android.support.design:itemTextColor" target="_blank" rel="noopener noreferrer">android.support.design:itemTextColor</a>&nbsp;&#8211; It is used to set the text color of the navigation item,&nbsp;use a&nbsp;<a href="https://developer.android.com/reference/android/content/res/ColorStateList.html" target="_blank" rel="noopener noreferrer">ColorStateList</a>&nbsp;to specify colors for all states.</li></ul>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="600" height="120" data-attachment-id="1673" data-permalink="https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/android-bottom-navigation-bar-1/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/android-bottom-navigation-bar-1.jpg?fit=600%2C120&amp;ssl=1" data-orig-size="600,120" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="android-bottom-navigation-bar-1" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/android-bottom-navigation-bar-1.jpg?fit=300%2C60&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/android-bottom-navigation-bar-1.jpg?fit=600%2C120&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/android-bottom-navigation-bar-1.jpg?resize=600%2C120" alt="android bottom navigation bar" class="wp-image-1673" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/android-bottom-navigation-bar-1.jpg?w=600&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/android-bottom-navigation-bar-1.jpg?resize=300%2C60&amp;ssl=1 300w" sizes="auto, (max-width: 600px) 100vw, 600px" /></figure></div>



<p>As I mentioned&nbsp;<code>BottomNavigationView</code> takes a <a href="https://developer.android.com/guide/topics/resources/menu-resource.html" target="_blank" rel="noopener noreferrer">menu resource</a> file to inflate the navigation items. To do so following are the ways in which it can be done:</p>



<ul class="wp-block-list"><li>XML
<ul>
<li><a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html#inflateMenu(int)" target="_blank" rel="noopener noreferrer"><code>app:menu</code></a></li>
</ul>
</li><li>Java
<ul>
<li><code><code></code></code><a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.html#inflateMenu(int)" target="_blank" rel="noopener noreferrer">BottomNavigationView.inflateMenu()</a></li>
</ul>
</li></ul>



<p>Once a <code>BottomNavigationView</code> is inflated and visible, a click listener can be attached to it:</p>



<ul class="wp-block-list"><li><code><code></code></code><a href="https://developer.android.com/reference/android/support/design/widget/BottomNavigationView.OnNavigationItemSelectedListener.html" target="_blank" rel="noopener noreferrer">BottomNavigationView.OnNavigationItemSelectedListener</a></li></ul>



<p>Method used to select a specific item in the BottomNavigationView:</p>



<ul class="wp-block-list"><li><code>BottomNavigationView.getMenu().getItem(index).setChecked(true);</code></li></ul>



<p>Although this component gives us the&nbsp;flexibility of changing screen content dynamically. But it is advised to not implement <a href="https://material.io/guidelines/components/bottom-navigation.html#bottom-navigation-behavior" target="_blank" rel="noopener noreferrer">swiping views</a>&nbsp;with an Android bottom navigation bar as per specs. Therefore&nbsp;this rules out the possibility of using a ViewPager with the bottom navigation bar. Instead a simple view or a set of fragments for complex implementation can be used. Therefore here in this tutorial, I will show how to implement a BottomNavigationView with a set of fragments.&nbsp;Lets have look at the example below.</p>



<h2 class="wp-block-heading">Android Bottom Navigation Bar Example</h2>



<p>To demonstrate a working example of Android BottomNavigationView widget, I would make three fragments and switch between them by using the bottom navigation bar.&nbsp;Here are the steps:</p>



<h3 class="wp-block-heading">Step 1 : Add the dependencies</h3>



<p>To start off with an example of bottom navigation bar on android , first we need to include following dependencies in our build.gradle file.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">compile 'com.android.support:appcompat-v7:25.1.0'
compile 'com.android.support:design:25.1.0'
compile 'com.android.support:support-v4:25.1.0'</pre>



<h3 class="wp-block-heading">&nbsp;</h3>



<h3 class="wp-block-heading">Step 2 : Define the Fragments</h3>



<p>For this example I&nbsp;will be building a screen with three fragments, which could be switched by the BottomNavigationView. Hence before jumping on to the main screen, lets define three fragments.</p>



<p>Fragment 1:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context="com.truiton.bottomnavigation.ItemOneFragment">

    &lt;ImageView
        android:id="@+id/truiton_image"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        android:src="@mipmap/truiton"/>

    &lt;TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/truiton_image"
        android:layout_centerHorizontal="true"
        android:text="Fragment 1"
        android:textSize="30sp"/>

&lt;/RelativeLayout>
</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.bottomnavigation;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ItemOneFragment extends Fragment {
    public static ItemOneFragment newInstance() {
        ItemOneFragment fragment = new ItemOneFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_item_one, container, false);
    }
}
</pre>



<p>Fragment 2:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context="com.truiton.bottomnavigation.ItemTwoFragment">

    &lt;ImageView
        android:id="@+id/truiton_image"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        android:src="@mipmap/truiton"/>

    &lt;TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/truiton_image"
        android:layout_centerHorizontal="true"
        android:text="Fragment 2"
        android:textSize="30sp"/>

&lt;/RelativeLayout>
</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.bottomnavigation;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ItemTwoFragment extends Fragment {
    public static ItemTwoFragment newInstance() {
        ItemTwoFragment fragment = new ItemTwoFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_item_two, container, false);
    }
}
</pre>



<p>Fragment 3:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context="com.truiton.bottomnavigation.ItemThreeFragment">

    &lt;ImageView
        android:id="@+id/truiton_image"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        android:src="@mipmap/truiton"/>

    &lt;TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/truiton_image"
        android:layout_centerHorizontal="true"
        android:text="Fragment 3"
        android:textSize="30sp"/>

&lt;/RelativeLayout>
</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.bottomnavigation;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ItemThreeFragment extends Fragment {
    public static ItemThreeFragment newInstance() {
        ItemThreeFragment fragment = new ItemThreeFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_item_three, container, false);
    }
}
</pre>



<h3 class="wp-block-heading">Step 3 : Defining the bottom navigation menu XML</h3>



<p>As mentioned before to populate the actual items into an&nbsp;Android bottom navigation bar, a menu type XML is used. This XML should contain at minimum three attributes:</p>



<ul class="wp-block-list"><li>android:title</li><li>android:icon</li><li>android:id</li></ul>



<p>For this example of BottomNavigationView, I would make a menu of three items:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;menu xmlns:android="http://schemas.android.com/apk/res/android">
    &lt;item
        android:id="@+id/action_item1"
        android:icon="@drawable/ic_account_box_black_24dp"
        android:title="@string/item_1"/>
    &lt;item
        android:id="@+id/action_item2"
        android:icon="@drawable/ic_account_circle_black_24dp"
        android:title="@string/item_2"/>
    &lt;item
        android:id="@+id/action_item3"
        android:icon="@drawable/ic_assignment_ind_black_24dp"
        android:title="@string/item_3"/>
&lt;/menu></pre>



<h3 class="wp-block-heading">Step 4 : Defining the Activity XML</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;RelativeLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.truiton.bottomnavigation.MainActivity">

    &lt;FrameLayout
        android:id="@+id/frame_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/navigation"
        android:animateLayoutChanges="true">

    &lt;/FrameLayout>

    &lt;android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@color/colorPrimary"
        app:itemIconTint="@color/nav_item_state_list"
        app:itemTextColor="@color/nav_item_state_list"
        app:menu="@menu/bottom_navigation_items"/>
&lt;/RelativeLayout>
</pre>



<p>As you can see above, for attributes&nbsp;<code>app:itemIconTint</code> and <code>app:itemTextColor</code>, I have used a&nbsp;<a href="https://developer.android.com/reference/android/content/res/ColorStateList.html" target="_blank" rel="noopener noreferrer">ColorStateList</a>. Please make sure when you make a color state list, its according to the <a href="https://material.io/guidelines/components/bottom-navigation.html" target="_blank" rel="noopener noreferrer">Material design specs</a> for bottom navigation bar. Full source code is available at the end of the tutorial.</p>



<h3 class="wp-block-heading">&nbsp;</h3>



<h3 class="wp-block-heading">Step 5 : Defining the activity with bottom navigation bar</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.bottomnavigation;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomNavigationView bottomNavigationView = (BottomNavigationView)
                findViewById(R.id.navigation);

        bottomNavigationView.setOnNavigationItemSelectedListener
                (new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                        Fragment selectedFragment = null;
                        switch (item.getItemId()) {
                            case R.id.action_item1:
                                selectedFragment = ItemOneFragment.newInstance();
                                break;
                            case R.id.action_item2:
                                selectedFragment = ItemTwoFragment.newInstance();
                                break;
                            case R.id.action_item3:
                                selectedFragment = ItemThreeFragment.newInstance();
                                break;
                        }
                        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                        transaction.replace(R.id.frame_layout, selectedFragment);
                        transaction.commit();
                        return true;
                    }
                });

        //Manually displaying the first fragment - one time only
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.frame_layout, ItemOneFragment.newInstance());
        transaction.commit();

        //Used to select an item programmatically
        //bottomNavigationView.getMenu().getItem(2).setChecked(true);
    }
}
</pre>



<p>As you can see above when making a screen with the help of BottomNavigationView we have to initialize it with a default view. As there is no <code>ViewPager</code> here, we are doing it all manually. By default when a <code>BottomNavigationView</code> is initialized it is loaded with the first item selected. But&nbsp;if you wish to load the screen with any other item selected, you can do so by getting the menu item and setting it checked as shown above. For full source code, please refer to the following link:</p>



<p style="text-align:center"><a class="fasc-button fasc-size-large fasc-type-flat fasc-rounded-medium ico-fa fasc-ico-before fa-github" style="background-color: #0364af; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="https://github.com/Truiton/BottomNavigation">Full Source Code</a></p>



<p>The final output would look like this:</p>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="600" height="967" data-attachment-id="1676" data-permalink="https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/android-bottom-navigation-bar-2/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-bottom-navigation-bar-2.png?fit=600%2C967&amp;ssl=1" data-orig-size="600,967" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Android bottom navigation bar -2" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-bottom-navigation-bar-2.png?fit=186%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-bottom-navigation-bar-2.png?fit=600%2C967&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-bottom-navigation-bar-2.png?resize=600%2C967" alt="Android bottom navigation bar" class="wp-image-1676" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-bottom-navigation-bar-2.png?w=600&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-bottom-navigation-bar-2.png?resize=186%2C300&amp;ssl=1 186w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2017/01/Android-bottom-navigation-bar-2.png?resize=300%2C484&amp;ssl=1 300w" sizes="auto, (max-width: 600px) 100vw, 600px" /></figure></div>



<h2 class="wp-block-heading">BottomNavigationView Limitations</h2>



<p>Although the view itself is recently released, hence it is bound to have some issues. But if you are trying to build an Android screen with bottom navigation, here is a list of&nbsp;issues you might face:</p>



<ul class="wp-block-list"><li>Item Background cannot be colored for selected state.</li><li>It does not have a bottom navigation behavior, hence no integration is available for FAB, Snackbar, and CoordinatorLayout.</li><li>Ethically swiping of views should not be done &#8211; Stated in <a href="https://material.io/guidelines/components/bottom-navigation.html" target="_blank" rel="noopener noreferrer">Material Design guidelines</a>.</li><li>Text and icon sizes cannot be changed.</li><li>No way to hide title for non selected items.</li><li>Only 5 items can be added at a time.</li></ul>



<p>But besides all this, building an Android bottom navigation bar has become a lot more simpler with the new BottomNavigationBar widget. As this is the new official component for bottom navigation.&nbsp;Also when speaking of shaping a product, giving upfront options like the bottom navigation has always gotten more traction,&nbsp;since it presents all the options to a user right away. Hope this helped, follow us on Twitter, Facebook and Google+ for more updates.</p>
<p>The post <a href="https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/">Android Bottom Navigation Bar Example</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2017/01/android-bottom-navigation-bar-example/feed/</wfw:commentRss>
			<slash:comments>20</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1666</post-id>	</item>
		<item>
		<title>Optical Character Recognition on Android &#8211; OCR</title>
		<link>https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/</link>
					<comments>https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/#comments</comments>
		
		<dc:creator><![CDATA[Mohit Gupt]]></dc:creator>
		<pubDate>Sun, 06 Nov 2016 15:12:47 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Image Recognition]]></category>
		<category><![CDATA[Mobile Vision API]]></category>
		<category><![CDATA[OCR]]></category>
		<guid isPermaLink="false">http://www.truiton.com/?p=1606</guid>

					<description><![CDATA[<p>Android itself is a smart OS, still it lacked a very basic feature of text recognition. But not anymore; with the official Optical Character Recognition API of Android and the Mobile Vision library, now Android can perform OCR very efficiently and correctly. I did a very basic feature test to have a look at the&#8230;&#160;<a href="https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/" rel="bookmark">Read More &#187;<span class="screen-reader-text">Optical Character Recognition on Android &#8211; OCR</span></a></p>
<p>The post <a href="https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/">Optical Character Recognition on Android &#8211; OCR</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="950" height="530" data-attachment-id="1612" data-permalink="https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/android-ocr-library-featured/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?fit=950%2C530&amp;ssl=1" data-orig-size="950,530" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}" data-image-title="android-ocr-library-featured" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?fit=300%2C167&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?fit=950%2C530&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?resize=950%2C530" alt="android ocr library - featured" class="wp-image-1612" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?w=950&amp;ssl=1 950w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?resize=600%2C335&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?resize=300%2C167&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-Featured.jpg?resize=768%2C428&amp;ssl=1 768w" sizes="auto, (max-width: 950px) 100vw, 950px" /></figure></div>



<p></p>



<p>Android itself is a smart OS, still it lacked a very basic feature of text recognition. But not anymore; with the official Optical Character Recognition API of Android and the Mobile Vision library, now Android can perform OCR very efficiently and correctly. I did a very basic feature test to have a look at the new functionality and found out its very fast and easy to use. Here in this Optical Character Recognition(OCR) example of Android, I would simply import the library, click a picture of a piece of text and look for text blocks in it. But before doing so lets take an overview of Android Mobile Vision API to understand the working of Text API better.</p>



<h2 class="wp-block-heading">Android Mobile Vision Library</h2>



<p>Consider a scenario where you wish to scan&nbsp;and an image or a video stream and&nbsp;detect&nbsp;faces, barcodes, QR codes or Text in&nbsp;it on Android. Astonishingly till now no such framework existed on Android. But now Google has introduced <a href="https://developers.google.com/vision/" target="_blank" rel="noopener noreferrer">Mobile Vision APIs</a>. These set of APIs&nbsp;provide a very easy to use programming interfaces through which we can scan Faces, Barcodes, QR Codes and Text without writing huge amount of code.&nbsp;And the best part is that these can be used offline as well, i.e. only once when the app is downloaded the required dependencies are downloaded, post that an internet connection is not required any more. As this feature is introduced on Android through the Google Play services.&nbsp;To enable your app to use Mobile Vision APIs, you need to add this dependency in your <code>build.gradle</code> file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">compile 'com.google.android.gms:play-services-vision:11.4.0'</pre>



<p>Please Note: Learn more on how to <a href="https://developers.google.com/android/guides/setup" target="_blank" rel="noopener noreferrer">setup Google Play Services</a>. Or learn more about <a href="http://www.truiton.com/2017/05/introducing-android-mobile-vision-api/">Mobile Vision API</a>.</p>



<h2 class="wp-block-heading">Introducing an Android OCR Library &#8211; Text Recognition API</h2>



<p>Since the Android OS was brought on to production devices, Optical Character Recognition has been a common area of research. But this <a href="https://developers.google.com/vision/text-overview" target="_blank" rel="noopener noreferrer">Text Recognition API</a> of Mobile Vision suite would bring all these researches to a stop. As this Google powered API contains&nbsp;features like multiple language recognition where languages are like : English, French, German, Spanish or&nbsp;any other Latin based text. Also the text can be parsed from a stream of frames i.e. a video and displayed on the screen in real time as displayed in the image above. But due to the scope of this Android OCR Library example we would keep things simple and scan the text from an image only, as this tutorial is targeted for beginners. Apart from this the interesting part is, all this is done offline by the Google Play services itself, i.e. no internet connection is required after once it has been set up in the app (shown in steps ahead). &nbsp;Now when it comes to structuring the text,&nbsp;this&nbsp;Android OCR library not only recognizes the text but can also divide the&nbsp;captured text into the following categories:</p>



<ol class="wp-block-list"><li>Block &#8211;&nbsp;<code><code></code></code><a href="https://developers.google.com/android/reference/com/google/android/gms/vision/text/TextBlock" target="_blank" rel="noopener noreferrer">TextBlock</a> &#8211; A top level object where a scanned paragraph or column is&nbsp;captured.</li><li>Line &#8211; <code><code></code></code><a href="https://developers.google.com/android/reference/com/google/android/gms/vision/text/Line" target="_blank" rel="noopener noreferrer">Line</a> &#8211; A line of text captured from a block of text.</li><li>Word &#8211; <code><code></code></code><a href="https://developers.google.com/android/reference/com/google/android/gms/vision/text/Element" target="_blank" rel="noopener noreferrer">Element</a> &#8211; A single word recognized in a <code>Line</code>.</li></ol>



<h2 class="wp-block-heading">Android OCR Example</h2>



<p>Now that we have a basic understanding of Android OCR library, particularly the Text Recognition API. I will demonstrate by an example where we would simply take a picture and scan for text in it. Now as a thumb rule to do so first we may need to set up our Android app to download the play services dependency for&nbsp;Optical Character Recognition. Therefore please&nbsp;include the block of code below in your manifest&nbsp;to instruct installer to download the OCR dependency at the time of installing the app.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;meta-data
            android:name="com.google.android.gms.vision.DEPENDENCIES"
            android:value="ocr"/></pre>



<p><span style="text-decoration: underline;">Please Note:</span> <em>This is not a mandatory step, but helps in downloading the dependencies beforehand. Also the link to full source code is at the end of this tutorial.</em></p>



<p>Next lets define a layout to display the scanned results:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="xml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">&lt;?xml version="1.0" encoding="utf-8"?>
&lt;android.support.constraint.ConstraintLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.truiton.mobile.vision.ocr.MainActivity">

    &lt;ImageView
        android:id="@+id/imageView"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="16dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/truiton"
        tools:layout_constraintLeft_creator="1"
        tools:layout_constraintRight_creator="1"/>

    &lt;Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="Scan Text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_constraintLeft_creator="1"
        tools:layout_constraintRight_creator="1"
        />

    &lt;TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="40dp"
        android:text="Scan Results:"
        android:textAllCaps="false"
        android:textStyle="normal|bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        tools:layout_constraintLeft_creator="1"
        tools:layout_constraintRight_creator="1"/>

    &lt;ScrollView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="8dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        tools:layout_constraintTop_creator="1"
        tools:layout_constraintRight_creator="1"
        tools:layout_constraintBottom_creator="1"
        tools:layout_constraintLeft_creator="1">

        &lt;LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            &lt;TextView
                android:id="@+id/results"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                tools:layout_constraintLeft_creator="1"
                tools:layout_constraintRight_creator="1"
                tools:layout_constraintTop_creator="1"/>
        &lt;/LinearLayout>
    &lt;/ScrollView>
&lt;/android.support.constraint.ConstraintLayout>
</pre>



<p>I was playing around with <code><code></code></code><a href="https://developer.android.com/training/constraint-layout/index.html" target="_blank" rel="noopener noreferrer">ConstraintLayout</a> in Android. Hence made it in Constraint layout, although its not a requirement to use <code>ConstraintLayout</code> for this Android OCR Library example. The above layout basically contains a <code>ScrollView</code> to accurately display the scanned text. Next lets define the main Activity:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">package com.truiton.mobile.vision.ocr;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.text.Text;
import com.google.android.gms.vision.text.TextBlock;
import com.google.android.gms.vision.text.TextRecognizer;

import java.io.File;
import java.io.FileNotFoundException;

public class MainActivity extends AppCompatActivity {
    private static final String LOG_TAG = "Text API";
    private static final int PHOTO_REQUEST = 10;
    private TextView scanResults;
    private Uri imageUri;
    private TextRecognizer detector;
    private static final int REQUEST_WRITE_PERMISSION = 20;
    private static final String SAVED_INSTANCE_URI = "uri";
    private static final String SAVED_INSTANCE_RESULT = "result";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        scanResults = (TextView) findViewById(R.id.results);
        if (savedInstanceState != null) {
            imageUri = Uri.parse(savedInstanceState.getString(SAVED_INSTANCE_URI));
            scanResults.setText(savedInstanceState.getString(SAVED_INSTANCE_RESULT));
        }
        detector = new TextRecognizer.Builder(getApplicationContext()).build();
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ActivityCompat.requestPermissions(MainActivity.this, new
                        String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_WRITE_PERMISSION:
                if (grantResults.length &gt; 0 &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    takePicture();
                } else {
                    Toast.makeText(MainActivity.this, "Permission Denied!", Toast.LENGTH_SHORT).show();
                }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PHOTO_REQUEST &amp;&amp; resultCode == RESULT_OK) {
            launchMediaScanIntent();
            try {
                Bitmap bitmap = decodeBitmapUri(this, imageUri);
                if (detector.isOperational() &amp;&amp; bitmap != null) {
                    Frame frame = new Frame.Builder().setBitmap(bitmap).build();
                    SparseArray&lt;TextBlock&gt; textBlocks = detector.detect(frame);
                    String blocks = "";
                    String lines = "";
                    String words = "";
                    for (int index = 0; index &lt; textBlocks.size(); index++) {
                        //extract scanned text blocks here
                        TextBlock tBlock = textBlocks.valueAt(index);
                        blocks = blocks + tBlock.getValue() + "\n" + "\n";
                        for (Text line : tBlock.getComponents()) {
                            //extract scanned text lines here
                            lines = lines + line.getValue() + "\n";
                            for (Text element : line.getComponents()) {
                                //extract scanned text words here
                                words = words + element.getValue() + ", ";
                            }
                        }
                    }
                    if (textBlocks.size() == 0) {
                        scanResults.setText("Scan Failed: Found nothing to scan");
                    } else {
                        scanResults.setText(scanResults.getText() + "Blocks: " + "\n");
                        scanResults.setText(scanResults.getText() + blocks + "\n");
                        scanResults.setText(scanResults.getText() + "---------" + "\n");
                        scanResults.setText(scanResults.getText() + "Lines: " + "\n");
                        scanResults.setText(scanResults.getText() + lines + "\n");
                        scanResults.setText(scanResults.getText() + "---------" + "\n");
                        scanResults.setText(scanResults.getText() + "Words: " + "\n");
                        scanResults.setText(scanResults.getText() + words + "\n");
                        scanResults.setText(scanResults.getText() + "---------" + "\n");
                    }
                } else {
                    scanResults.setText("Could not set up the detector!");
                }
            } catch (Exception e) {
                Toast.makeText(this, "Failed to load Image", Toast.LENGTH_SHORT)
                        .show();
                Log.e(LOG_TAG, e.toString());
            }
        }
    }

    private void takePicture() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File photo = new File(Environment.getExternalStorageDirectory(), "picture.jpg");
        imageUri = FileProvider.getUriForFile(MainActivity.this,
                BuildConfig.APPLICATION_ID + ".provider", photo);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(intent, PHOTO_REQUEST);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (imageUri != null) {
            outState.putString(SAVED_INSTANCE_URI, imageUri.toString());
            outState.putString(SAVED_INSTANCE_RESULT, scanResults.getText().toString());
        }
        super.onSaveInstanceState(outState);
    }

    private void launchMediaScanIntent() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        mediaScanIntent.setData(imageUri);
        this.sendBroadcast(mediaScanIntent);
    }

    private Bitmap decodeBitmapUri(Context ctx, Uri uri) throws FileNotFoundException {
        int targetW = 600;
        int targetH = 600;
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(ctx.getContentResolver().openInputStream(uri), null, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;

        return BitmapFactory.decodeStream(ctx.getContentResolver()
                .openInputStream(uri), null, bmOptions);
    }
}
</pre>



<p>In the above piece of code, I simply initialized&nbsp;a <code>TextRecognizer</code> and asked the user to grant the permission to store the captured image on disk. Post which, when an image like shown below is captured, we resize the image in method&nbsp;<code>decodeBitmapUri</code> to a smaller size so that, it can be scanned faster. Once the image is scaled, we check for operational&nbsp;<code>TextRecognizer</code>. Then after the detector is operational, we scan out the text from picture.</p>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="800" height="448" data-attachment-id="1616" data-permalink="https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/android-ocr-library-1/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?fit=800%2C448&amp;ssl=1" data-orig-size="800,448" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="android-ocr-library-1" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?fit=300%2C168&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?fit=800%2C448&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?resize=800%2C448" alt="android ocr library" class="wp-image-1616" srcset="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?w=800&amp;ssl=1 800w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?resize=600%2C336&amp;ssl=1 600w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?resize=300%2C168&amp;ssl=1 300w, https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-1.png?resize=768%2C430&amp;ssl=1 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /></figure></div>



<p>When the Android OCR library &#8211; the Mobile Vision, returned the text from the picture above, it was very accurate. Have a look at the result below:</p>



<div class="wp-block-image"><figure class="aligncenter"><img data-recalc-dims="1" loading="lazy" decoding="async" width="272" height="480" data-attachment-id="1617" data-permalink="https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/android-ocr-library-2/" data-orig-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-2.gif?fit=272%2C480&amp;ssl=1" data-orig-size="272,480" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="android-ocr-library-2" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-2.gif?fit=170%2C300&amp;ssl=1" data-large-file="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-2.gif?fit=272%2C480&amp;ssl=1" src="https://i0.wp.com/www.truiton.com/wp-content/uploads/2016/11/Android-OCR-Library-2.gif?resize=272%2C480" alt="android ocr library " class="wp-image-1617"/></figure></div>



<p>For full source code, please refer to the link below:</p>



<p style="text-align:center"><a class="fasc-button fasc-size-large fasc-type-flat fasc-rounded-medium ico-fa fasc-ico-before fa-github" style="background-color: #0364af; color: #ffffff;" target="_blank" rel="noopener noreferrer" href="https://github.com/Truiton/MobileVisionAPI/tree/master/OCRSample">Full Source Code</a></p>



<p>Hence I believe this is one of the best OCR libraries available for Android till date. As it gives the unique capability of offline text scanning, without compromising on&nbsp;quality.&nbsp;Therefore if you have to make an app where it is required to scan the text and process it, use the Text API of Mobile Vision for Optical Character Recognition. For more posts like this, please connect with us on Twitter, Facebook and Google+. Hope this helped.</p>
<p>The post <a href="https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/">Optical Character Recognition on Android &#8211; OCR</a> appeared first on <a href="https://www.truiton.com">Truiton</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.truiton.com/2016/11/optical-character-recognition-android-ocr/feed/</wfw:commentRss>
			<slash:comments>16</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1606</post-id>	</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 
Minified using Disk

Served from: www.truiton.com @ 2026-06-28 00:23:38 by W3 Total Cache
-->