<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Paul Franco</title>
    <description>The latest articles on DEV Community by Paul Franco (@paulfranco).</description>
    <link>https://dev.to/paulfranco</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F461534%2F103ddbd3-53ca-45e2-be6f-040b753ceaca.jpg</url>
      <title>DEV Community: Paul Franco</title>
      <link>https://dev.to/paulfranco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/paulfranco"/>
    <language>en</language>
    <item>
      <title>How to Track Composable Visibility in Jetpack Compose — with a custom .trackVisibility Modifier</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Sat, 03 May 2025 05:29:25 +0000</pubDate>
      <link>https://dev.to/paulfranco/how-to-track-composable-visibility-in-jetpack-compose-with-a-custom-trackvisibility-modifier-5bad</link>
      <guid>https://dev.to/paulfranco/how-to-track-composable-visibility-in-jetpack-compose-with-a-custom-trackvisibility-modifier-5bad</guid>
      <description>&lt;p&gt;In Compose apps, it’s often necessary to know if a Composable is visible on screen and by how much. Whether you’re logging ad impressions, auto-playing videos, lazy-loading data, or triggering animations, visibility tracking is critical.&lt;/p&gt;

&lt;p&gt;Jetpack Compose doesn’t expose a built-in way to detect visibility like legacy Views (ViewTreeObserver, RecyclerView.OnScrollListener). But with the power of Modifier.Node, we can create our own.&lt;/p&gt;

&lt;p&gt;Today we’ll build and explain a &lt;code&gt;trackVisibility&lt;/code&gt; modifier from scratch — with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Full working code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Line-by-line explanations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Best practices and optimization tips&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the &lt;code&gt;trackVisibility&lt;/code&gt; Modifier Does
&lt;/h2&gt;

&lt;p&gt;This custom modifier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Calculates how visible a Composable is (from 0.0 to 1.0)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compares it against a threshold (default 50%)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Triggers a callback when the visibility changes significantly&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Full Source Code with Explanations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Define the visibility info structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class VisibilityInfo(
    val isVisible: Boolean,
    val visiblePercentage: Float,
    val bounds: Rect,
    val isAboveThreshold: Boolean
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class encapsulates visibility state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;isVisible&lt;/code&gt;: Whether any portion is visible&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;visiblePercentage&lt;/code&gt;: How much of the view is visible&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bounds&lt;/code&gt;: The view's window bounds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;isAboveThreshold&lt;/code&gt;: Whether it meets your visibility target&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2: The &lt;code&gt;Modifier.Node&lt;/code&gt; Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private class VisibilityTrackerNode(
    var thresholdPercentage: Float,
    var onVisibilityChanged: (VisibilityInfo) -&amp;gt; Unit,
) : Modifier.Node(), GlobalPositionAwareModifierNode {

    private var previousVisibilityPercentage: Float? = null
    private val minimumVisibilityDelta = 0.01f

    override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
        val boundsInWindow = coordinates.boundsInWindow()
        val parentBounds = coordinates.parentLayoutCoordinates?.boundsInWindow()

        if (parentBounds == null || !coordinates.isAttached) {
            previousVisibilityPercentage = 0f
            return
        }

        val visibleLeft = max(boundsInWindow.left, parentBounds.left)
        val visibleRight = min(boundsInWindow.right, parentBounds.right)
        val visibleTop = max(boundsInWindow.top, parentBounds.top)
        val visibleBottom = min(boundsInWindow.bottom, parentBounds.bottom)

        val visibleWidth = max(0f, visibleRight - visibleLeft)
        val visibleHeight = max(0f, visibleBottom - visibleTop)

        val visibleArea = visibleWidth * visibleHeight
        val totalArea = (coordinates.size.width * coordinates.size.height).toFloat().takeIf { it &amp;gt; 0 } ?: return

        val visibilityPercentage = (visibleArea / totalArea).coerceIn(0f, 1f)

        val visibilityDifference = previousVisibilityPercentage?.let { previous -&amp;gt;
            abs(visibilityPercentage - previous)
        } ?: Float.MAX_VALUE

        if (visibilityDifference &amp;gt;= minimumVisibilityDelta) {
            onVisibilityChanged(
                VisibilityInfo(
                    isVisible = visibilityPercentage &amp;gt; 0f,
                    visiblePercentage = visibilityPercentage,
                    bounds = boundsInWindow,
                    isAboveThreshold = visibilityPercentage &amp;gt;= thresholdPercentage
                )
            )
            previousVisibilityPercentage = visibilityPercentage
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;GlobalPositionAwareModifierNode&lt;/code&gt; gives us access to layout bounds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We calculate the overlap between the view and its parent to determine how much is visible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We emit a callback if the visibility changed significantly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3: The &lt;code&gt;ModifierNodeElement&lt;/code&gt; Glue&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private class VisibilityTrackerElement(
    private val thresholdPercentage: Float,
    private val onVisibilityChanged: (VisibilityInfo) -&amp;gt; Unit,
) : ModifierNodeElement&amp;lt;VisibilityTrackerNode&amp;gt;() {

    override fun create() = VisibilityTrackerNode(thresholdPercentage, onVisibilityChanged)

    override fun update(node: VisibilityTrackerNode) {
        node.thresholdPercentage = thresholdPercentage
        node.onVisibilityChanged = onVisibilityChanged
    }

    override fun equals(other: Any?) = other is VisibilityTrackerElement &amp;amp;&amp;amp;
        other.thresholdPercentage == thresholdPercentage &amp;amp;&amp;amp;
        other.onVisibilityChanged == onVisibilityChanged

    override fun hashCode(): Int {
        var result = thresholdPercentage.hashCode()
        result = 31 * result + onVisibilityChanged.hashCode()
        return result
    }

    override fun InspectorInfo.inspectableProperties() {
        name = "trackVisibility"
        properties["thresholdPercentage"] = thresholdPercentage
        properties["onVisibilityChanged"] = onVisibilityChanged
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This element binds the logic to the Compose modifier chain and handles recomposition safety.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Public Modifier Extension&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun Modifier.trackVisibility(
    thresholdPercentage: Float = 0.5f,
    onVisibilityChanged: (VisibilityInfo) -&amp;gt; Unit,
): Modifier = this then VisibilityTrackerElement(thresholdPercentage, onVisibilityChanged)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the clean, declarative API you use in Composables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Usage Example with ViewModel
&lt;/h2&gt;

&lt;p&gt;Here's how you would call a &lt;code&gt;ViewModel&lt;/code&gt; function from inside &lt;code&gt;trackVisibility&lt;/code&gt; safely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*

@Composable
fun ShopCardWithTracking(shopId: String, viewModel: ShopListViewModel) {
    var hasLogged by remember(shopId) { mutableStateOf(false) }

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(250.dp)
            .trackVisibility(thresholdPercentage = 0.6f) { info -&amp;gt;
                if (info.isAboveThreshold &amp;amp;&amp;amp; !hasLogged) {
                    hasLogged = true
                    viewModel.trackImpression(shopId)
                }
            }
    ) {
        Text("Shop ID: $shopId")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure you import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid the "property delegate must have a getValue/setValue" compiler error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full LazyColumn Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Composable
fun ShopListScreen(viewModel: ShopListViewModel = viewModel()) {
    val shops = listOf("A1", "B2", "C3", "D4")

    LazyColumn {
        items(properties) { propertyId -&amp;gt;
            ShopCardWithTracking(shopId, viewModel)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a simple ViewModel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ShopListViewModel : ViewModel() {
    private val _loggedImpressions = mutableSetOf&amp;lt;String&amp;gt;()

    fun trackImpression(shopId: String) {
        if (_loggedImpressions.add(shopId)) {
            Log.d("Impression", "Logged impression for $shopId")
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices &amp;amp; Optimizations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;minimumVisibilityDelta&lt;/code&gt; to avoid over-triggering callbacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid expensive logic inside &lt;code&gt;onVisibilityChanged&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Guard with &lt;code&gt;hasLogged&lt;/code&gt; to prevent duplicate triggers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep &lt;code&gt;ViewModel&lt;/code&gt; interactions lightweight.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Keep It Tight: Using Locally Scoped Helper Functions in Kotlin Use Cases</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Fri, 25 Apr 2025 02:57:07 +0000</pubDate>
      <link>https://dev.to/paulfranco/keep-it-tight-using-locally-scoped-helper-functions-in-kotlin-use-cases-5004</link>
      <guid>https://dev.to/paulfranco/keep-it-tight-using-locally-scoped-helper-functions-in-kotlin-use-cases-5004</guid>
      <description>&lt;p&gt;In modern Android and Kotlin development, especially when following clean architecture, we aim for focused, testable, and readable use cases. One subtle yet powerful technique to help us achieve that is placing small, tightly-bound helper functions inside a function like &lt;code&gt;invoke()&lt;/code&gt; — rather than elevating them to the class level.&lt;/p&gt;

&lt;p&gt;Here’s how and why that matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Real Example&lt;/strong&gt;&lt;br&gt;
Let’s say you have a feature that displays business hours for some sort of business like a dental clinic. You’ve got a &lt;code&gt;BusinessSchedule&lt;/code&gt; proto model or API response and you want to display:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;"Open Today: 9:00 AM - 5:00 PM"&lt;/code&gt; if today’s hours are valid&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;"Open Tomorrow: ..."&lt;/code&gt; if today is closed but tomorrow is open&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Or the next available day like &lt;code&gt;"Open Thursday:..."&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Or a fallback like &lt;code&gt;"Contact us for available business hours"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might implement a use case like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class GetBusinessAvailabilityScheduleUseCase {

    operator fun invoke(businessSchedule: List&amp;lt;BusinessSchedule&amp;gt;): String {
        val dayNames = listOf("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
        val today = LocalDate.now().dayOfWeek.value % 7
        val tomorrow = (today + 1) % 7

        fun hasValidHours(index: Int): Boolean {
            val schedule = businessSchedule.getOrNull(index)
            val open = schedule?.open?.value.orEmpty()
            val close = schedule?.close?.value.orEmpty()
            return open.isNotBlank() &amp;amp;&amp;amp; close.isNotBlank()
        }

        fun formatSchedule(prefix: String, index: Int): String {
            val schedule = businessSchedule[index]
            val open = schedule.open?.value.orEmpty()
            val close = schedule.close?.value.orEmpty()
            return "$prefix: $open - $close"
        }

        return when {
            hasValidHours(today) -&amp;gt; formatSchedule("Open Today", today)
            hasValidHours(tomorrow) -&amp;gt; formatSchedule("Open Tomorrow", tomorrow)
            else -&amp;gt; {
                for (i in 0..6) {
                    val index = (today + i + 1) % 7
                    if (hasValidHours(index)) {
                        val dayName = dayNames[index]
                        return formatSchedule("Open $dayName", index)
                    }
                }
                "Contact us for available business hours"
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Use Local Helper Functions?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Encapsulation&lt;/strong&gt;&lt;br&gt;
Helpers like &lt;code&gt;hasValidHours()&lt;/code&gt; and &lt;code&gt;formatSchedule()&lt;/code&gt; are implementation details. They don’t belong to the class's public API and aren’t useful anywhere else. Keeping them inside the invoke() keeps the rest of your class clean and focused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Readability&lt;/strong&gt;&lt;br&gt;
Keeping helper logic near the place it’s used creates a narrative flow in your code. You don’t have to scroll around to find where something like &lt;code&gt;hasValidHours()&lt;/code&gt; is defined — it’s right there, scoped to the logic it supports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Refactor Safety&lt;/strong&gt;&lt;br&gt;
When helpers are class-level, other developers might start reusing them in unintended ways. If they’re scoped locally, the compiler ensures they only exist where they're needed, which makes future refactors less risky.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Access to Local Variables&lt;/strong&gt;&lt;br&gt;
These functions can "close over" values like &lt;code&gt;today&lt;/code&gt;, &lt;code&gt;dayNames&lt;/code&gt;, or &lt;code&gt;businessSchedule&lt;/code&gt;, without requiring additional parameters. This reduces parameter clutter and makes your logic more concise.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Extract Them
&lt;/h2&gt;

&lt;p&gt;There’s a tipping point. If a helper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Is reused across multiple functions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Becomes complex enough to deserve testing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Or starts to feel like a domain concept on its own&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... then it’s time to &lt;strong&gt;extract&lt;/strong&gt; it to a private method or even a standalone utility.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;hasValidHours()&lt;/code&gt; could be extracted to a shared &lt;code&gt;ScheduleUtils&lt;/code&gt; if it's reused elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This pattern — defining small, single-use helpers inside &lt;code&gt;invoke()&lt;/code&gt; — is a clean, idiomatic way to write Kotlin use cases. It encourages encapsulation, local reasoning, and less API pollution, making your code more maintainable and testable over time.&lt;/p&gt;

&lt;p&gt;It’s a small trick — but when applied consistently, it has a big payoff.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Define helper functions inside &lt;code&gt;invoke()&lt;/code&gt; if they’re only used there.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It improves readability, encapsulation, and refactorability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extract them only if they become reusable or complex.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Securing and Injecting Google Maps API Key in an Android App</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Mon, 03 Mar 2025 21:36:20 +0000</pubDate>
      <link>https://dev.to/paulfranco/securing-and-injecting-google-maps-api-key-in-an-android-app-14kp</link>
      <guid>https://dev.to/paulfranco/securing-and-injecting-google-maps-api-key-in-an-android-app-14kp</guid>
      <description>&lt;p&gt;When developing an Android application, securely managing sensitive API keys such as the Google Maps API Key is crucial. Hardcoding API keys in &lt;code&gt;strings.xml&lt;/code&gt; or source code poses a security risk, as they can be easily extracted from decompiled APKs. Instead, we use Gradle properties and &lt;code&gt;resValue&lt;/code&gt; to inject the API key dynamically into the app while keeping it out of the source code repository.&lt;/p&gt;

&lt;p&gt;In this blog post, we'll walk through how to securely manage and inject the Google Maps API key in an Android project, ensuring that it remains safe while still being accessible where needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Store the API Key in secrets.properties
&lt;/h2&gt;

&lt;p&gt;First, we store the API key in a local properties file that is not included in version control (Git) to prevent it from being leaked.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;secrets.properties&lt;/code&gt; in the root directory of your project.&lt;/p&gt;

&lt;p&gt;Add the following line (replace with your actual key):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GOOGLE_MAP_API_KEY=your_actual_google_maps_api_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;secrets.properties&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; to ensure it is not committed to the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secrets.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the API key is stored securely and will not be pushed to GitHub or shared in version control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Load the API Key in &lt;code&gt;build.gradle.kts&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Since we need to use this API key within Gradle, we need to load it from &lt;code&gt;secrets.properties&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Modify the &lt;code&gt;build.gradle.kts&lt;/code&gt; file and add the following snippet before the &lt;code&gt;android&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val localProperties = Properties()
val localPropertiesFile = File(rootDir, "secrets.properties")
if (localPropertiesFile.exists() &amp;amp;&amp;amp; localPropertiesFile.isFile) {
    localPropertiesFile.inputStream().use {
        localProperties.load(it)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet:&lt;/p&gt;

&lt;p&gt;Loads the &lt;code&gt;secrets.properties&lt;/code&gt; file at runtime.&lt;/p&gt;

&lt;p&gt;Extracts the &lt;code&gt;GOOGLE_MAP_API_KEY&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;Ensures the file exists before trying to read it, preventing crashes.&lt;/p&gt;

&lt;p&gt;This must be placed at the top of &lt;code&gt;build.gradle.kts&lt;/code&gt; so that the properties are available before any build configurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Inject the API Key into &lt;code&gt;res/values/strings.xml&lt;/code&gt; Using &lt;code&gt;resValue&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of manually adding the API key to &lt;code&gt;strings.xml&lt;/code&gt;, we use &lt;code&gt;resValue&lt;/code&gt; in Gradle to inject it dynamically.&lt;/p&gt;

&lt;p&gt;Modify your &lt;code&gt;build.gradle.kts&lt;/code&gt; inside the &lt;code&gt;android&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android {
    buildTypes {
        getByName("debug") {
            val googleMapsApiKey = localProperties.getProperty("GOOGLE_MAP_API_KEY") ?: ""
            resValue("string", "google_maps_key", googleMapsApiKey)
        }

        getByName("release") {
            val googleMapsApiKey = localProperties.getProperty("GOOGLE_MAP_API_KEY") ?: ""
            resValue("string", "google_maps_key", googleMapsApiKey)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How &lt;code&gt;resValue&lt;/code&gt; Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It injects the API key into the compiled &lt;code&gt;res/values/strings.xml&lt;/code&gt; at build time.&lt;/p&gt;

&lt;p&gt;The key never appears in source code or XML files, reducing security risks.&lt;/p&gt;

&lt;p&gt;The generated key can be accessed using &lt;code&gt;@string/google_maps_key&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Use the API Key in &lt;code&gt;AndroidManifest.xml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Since &lt;code&gt;resValue&lt;/code&gt; makes &lt;code&gt;google_maps_key&lt;/code&gt; available as a string resource, you can now reference it in &lt;code&gt;AndroidManifest.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="@string/google_maps_key" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that Google Maps SDK can access the API key without hardcoding it anywhere in your project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Step 5: Access the API Key in Kotlin Code (If Needed)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you need to use the API key in Kotlin (for example, to initialize Google Maps dynamically), you can retrieve it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val apiKey = context.getString(R.string.google_maps_key)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to access the API key programmatically while keeping it securely stored.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Android: Determine how many users are using DarkMode</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Wed, 17 Jul 2024 08:58:35 +0000</pubDate>
      <link>https://dev.to/paulfranco/android-determine-how-many-users-are-using-darkmode-58dj</link>
      <guid>https://dev.to/paulfranco/android-determine-how-many-users-are-using-darkmode-58dj</guid>
      <description>&lt;p&gt;On Android, determining how many users are using dark mode can be achieved through a few methods, but it generally involves collecting analytics data from your app. Here's how you can approach it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Firebase Analytics&lt;/strong&gt;&lt;br&gt;
Firebase Analytics is a powerful tool for collecting user data and behavior analytics. You can log a custom event to track the theme mode preference of your users.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add Firebase to your Android project&lt;/strong&gt;: Follow the Firebase setup instructions to add Firebase to your project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Log the dark mode preference&lt;/strong&gt;: Create a function to log an event whenever the user changes the theme or when the app starts. Here's an example of how you can do it:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase

fun logThemeMode(isDarkMode: Boolean) {
    val firebaseAnalytics = Firebase.analytics
    val themeMode = if (isDarkMode) "dark" else "light"
    val bundle = Bundle().apply {
        putString("theme_mode", themeMode)
    }
    firebaseAnalytics.logEvent("user_theme_mode", bundle)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detect the current theme mode&lt;/strong&gt;: You can detect whether the user is in dark mode using the following code:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val isDarkMode = when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
    Configuration.UI_MODE_NIGHT_YES -&amp;gt; true
    Configuration.UI_MODE_NIGHT_NO -&amp;gt; false
    else -&amp;gt; false
}
logThemeMode(isDarkMode)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;View analytics in Firebase&lt;/strong&gt;: After integrating the above code, you can view the analytics data in the Firebase console under the Events section. Look for the user_theme_mode event to see the theme mode distribution among your users.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Using Custom Analytics&lt;/strong&gt;&lt;br&gt;
If you are using a custom analytics solution, you can follow a similar approach by sending a custom event or property to your analytics server whenever the theme changes or the app starts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detect the current theme mode&lt;/strong&gt;: Use the same method as above to detect whether the user is using dark mode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Send the theme mode data&lt;/strong&gt;: Send this information to your analytics server. The implementation will depend on your custom analytics setup.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Checking System Default&lt;/strong&gt;&lt;br&gt;
You can also check the default system settings for dark mode, though this will only give you an idea of the preferred mode and not actual usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val nightModeFlags = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
val isDarkMode = when (nightModeFlags) {
    Configuration.UI_MODE_NIGHT_YES -&amp;gt; true
    Configuration.UI_MODE_NIGHT_NO -&amp;gt; false
    else -&amp;gt; false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Combining these methods with your analytics setup will provide you with insights into how many users are using dark mode on their Android devices.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>darkmode</category>
    </item>
    <item>
      <title>Android Jetpack: Navigation Architecture Component</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Sun, 27 Sep 2020 22:03:11 +0000</pubDate>
      <link>https://dev.to/paulfranco/android-jetpack-navigation-architecture-component-1oe5</link>
      <guid>https://dev.to/paulfranco/android-jetpack-navigation-architecture-component-1oe5</guid>
      <description>&lt;p&gt;If you have been developing Android applications for some time you know that providing proper navigation between Activities and Fragments can be a time extensive and complex task. The recently released Android Jetpack Navigation Architecture Component makes this task much easier by providing many building tools needed to handle in-app navigation while also helping us visualize our app’s navigation flow.&lt;/p&gt;

&lt;p&gt;The Navigation Component consists of three key building blocks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigation Graph which is an XML resource that contains all navigation-related information like all off our app’s destinations or fragments and all of the possible paths our users could navigate through our app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NavHostFragment which is special widget we can add to our app layout that will Host all of the destinations or fragments from our navigation graph.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;NavController is a Kotlin object that keeps track of the user’s current position within the navigation graph and orchestrates the exchange of destination content in the NavHostFragment as our users move through the destinations in our navigation graph.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to illustrate how easy it is to use the Navigation Architecture Component, lets go ahead and create a new project in Android Studio.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frwkblbs3yav8z6qni3w7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frwkblbs3yav8z6qni3w7.png" alt="Alt Text" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will name this project NavDemo.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnhbhgav3przi3maqpwek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnhbhgav3przi3maqpwek.png" alt="Alt Text" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we need to declare the Navigation Component’s dependencies to our app level build.gradle file. The current dependencies can be found at &lt;a href="https://developer.android.com/jetpack/androidx/releases/navigation" rel="noopener noreferrer"&gt;https://developer.android.com/jetpack/androidx/releases/navigation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdz63upgoy1ffpcviejm6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdz63upgoy1ffpcviejm6.png" alt="Alt Text" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we want to be able to pass data between fragments or destinations in our app we need to use Safe Args. In order to use Safe Args in our project we need to declare some dependencies to our project level build.gladle file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7h6fv2fjw9urgqbh9roa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7h6fv2fjw9urgqbh9roa.png" alt="Alt Text" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also need to add a plugin to our app level build.gradle file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F62qbp0tmlm4xe9681wjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F62qbp0tmlm4xe9681wjg.png" alt="Alt Text" width="696" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this project we are also going to use the Android Jetpack Data Binding Library. We don’t need to use Data Binding in this project and the Navigation Component does not rely on it but is recommended as we begin to work on larger real-world projects. In order to enable data binding we just need to set dataBinding to true in the buildFeatures block of the app level build.gradle file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs3v15mxw5qdibgb89ob7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs3v15mxw5qdibgb89ob7.png" alt="Alt Text" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to properly use data binding in our project we need to set layout tags to be the outermost tags in our layout xml files.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu0heec35scqdhzs5ai9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu0heec35scqdhzs5ai9t.png" alt="Alt Text" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let create a Data Binding object in the MainActivity.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpxhugolybjsd45taw8vi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpxhugolybjsd45taw8vi.png" alt="Alt Text" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have set up our project to use Data Binding and Navigation we can move forward and begin building our Navigation Graph.&lt;/p&gt;

&lt;p&gt;First, we will create a file that will contain our navigation graph. To create this file you can right click on your app folder which will prompt a menu to pop up. Select New. Then select Android Resource File.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fakmecb81wotnj1k5xfjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fakmecb81wotnj1k5xfjl.png" alt="Alt Text" width="720" height="797"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new window will pop up. Choose Navigation as the Resource Type. I will name this file nav_graph.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwaw5kf3tjns4waz7xnbd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwaw5kf3tjns4waz7xnbd.png" alt="Alt Text" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the file has been created you can see that android created a new folder named navigation in within the res folder. Inside the navigation folder we will find our nav_graph file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fopvxkgubk13j2txyr0c5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fopvxkgubk13j2txyr0c5.png" alt="Alt Text" width="613" height="877"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To host the navigation graph we need a NavHostFragment. The navigation graph connects to the other parts of the app through the NaVHostFragment. If we switch to the Design View we will see a notification that says “No NavHostFragments found”.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0fj9venwuj3afdpak7lq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0fj9venwuj3afdpak7lq.png" alt="Alt Text" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to add a NavHostFragment we nee to open our activity_main.xml file and remove the TextView.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg98n043j7200rhcskz5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg98n043j7200rhcskz5g.png" alt="Alt Text" width="800" height="501"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7l4c8i199ybypszgomfh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7l4c8i199ybypszgomfh.png" alt="Alt Text" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then want to switch to Design Mode and seach for NavHostFragment.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzh5zb27v90a2lnpmgzl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzh5zb27v90a2lnpmgzl7.png" alt="Alt Text" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can select the NavHostFragment and drag it into the layout prompting a pop-up to appear.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw8lbbccxvsaelgp1j7s7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw8lbbccxvsaelgp1j7s7.png" alt="Alt Text" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this pop-up we can see that we can select the nav_graph we created earlier. Select the nav_graph option and press the OK button. Then press of the Infer Constraints button. Now we have set the activity_main as NavHostFragment.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv6oes6lcf2zdmi6locq1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv6oes6lcf2zdmi6locq1.png" alt="Alt Text" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we go back to our navigation graph we can see that the activity_main is set as the NavHostFragment.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvwudc9w1q7ywoyqrv6hk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvwudc9w1q7ywoyqrv6hk.png" alt="Alt Text" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we have to create our Navigation Destinations. I will create a destination by clicking on the green plus button.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvxvn3qqyaytotp9fa4a9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvxvn3qqyaytotp9fa4a9.png" alt="Alt Text" width="578" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A pop-up will appear with different types of fragments available. I will choose Fragment (Blank).&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6y0xk962v48sd3kq5hqu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6y0xk962v48sd3kq5hqu.png" alt="Alt Text" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will name this fragment HomeFragment. After clicking the Finish button, the fragment will appear in my navigation graph.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faltpe7s45lsntlj73zo4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faltpe7s45lsntlj73zo4.png" alt="Alt Text" width="800" height="511"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhclfsdmfdystagyjigqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhclfsdmfdystagyjigqn.png" alt="Alt Text" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our layout folder now has an additional file for the homeFragment. Let’s open this file and make some small changes to the design.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdg5wflvlvvnj8fgbjvu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdg5wflvlvvnj8fgbjvu3.png" alt="Alt Text" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will simply remove the TextView, add an EditText and a Button. Since we are using data binding we also need to add layout tags as the outer most tags in the xml and set up our binding object in our HomeFragment Class.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx6ccihgqznpimx718q34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx6ccihgqznpimx718q34.png" alt="Alt Text" width="800" height="595"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F60cybqu3jn5reqsu2435.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F60cybqu3jn5reqsu2435.png" alt="Alt Text" width="800" height="700"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu5etqiznckb84otj3v5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu5etqiznckb84otj3v5y.png" alt="Alt Text" width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have set up our Home Fragment we need to add additional destinations to our Navigation Graph by repeating the process. I will name this additional destination SecondFragment. However, this fragment will only contain a single TextView.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg7fipnp2x5ebyc3wu14e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg7fipnp2x5ebyc3wu14e.png" alt="Alt Text" width="800" height="510"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftut1rto43x5jn641leiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftut1rto43x5jn641leiu.png" alt="Alt Text" width="651" height="568"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgzcjrups7kpgheyj50s2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgzcjrups7kpgheyj50s2.png" alt="Alt Text" width="800" height="592"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi1v35hzizu8xv205bwc1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi1v35hzizu8xv205bwc1.png" alt="Alt Text" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you look at our Navigation Graph you will see that we now have two desinations, the homeFragment and the secondFragment.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frtw4jamxx2hekp4h8is3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frtw4jamxx2hekp4h8is3.png" alt="Alt Text" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you run this app you will see the homeFragment is displayed, but it you click on the Submit button nothing will happen. This is because we have not set any Navigation Actions.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0o9oz6i0d9ek19df6d40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0o9oz6i0d9ek19df6d40.png" alt="Alt Text" width="311" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add a Navigation action from the homeFragment to the secondFragment all we have to do is click on the circular icon on the right side of the homeFragment and drag the line that appears into the secondFragment. If successful an arrow will appear that points from the homeFragment to the secondFragment.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fde7l7e66beqpibo7ybw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fde7l7e66beqpibo7ybw3.png" alt="Alt Text" width="800" height="578"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs8yc3yudrgzd6k87ha9c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs8yc3yudrgzd6k87ha9c.png" alt="Alt Text" width="800" height="569"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F51klficn022ipyixj77z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F51klficn022ipyixj77z.png" alt="Alt Text" width="671" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same can be done if you want to create a Navigation Action from the secondFragment to the homeFragment. Android Studio automatically gives the navigation actions an id but you can change the id if you want. The id can be found in the attributes inspector.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsunucx1szhfzzteffrj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsunucx1szhfzzteffrj8.png" alt="Alt Text" width="221" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you switch to the Text Mode in the navigation graph you will see that our navigation graph contains two fragments, the homeFragment and the secondFragment. The startDestination in our navigation is set to homeFragment. The homeFragment contains an action with a destination of secondFragment.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxxx4xxc0o270w6ya7vuf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxxx4xxc0o270w6ya7vuf.png" alt="Alt Text" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can open our HomeFragment file and set an onClickListener on our submitButton. Within this block we need to find the Navigation Controller and Navigate to our destination using the Navigation action id : action_homeFragment_toSecondFragment.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuwvqelkkdh0n83lgsff9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuwvqelkkdh0n83lgsff9.png" alt="Alt Text" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we run out app and press the submit button you will see that our users can now move from the homeFragment to the secondFragment. However, if you type something in the EditText and then press the submit button, you will still move from one screen to the next but the information you typed in the EditText does not get transferred to the second screen. To accomplish this we need to get the user input as a bundle and set this bundle as the second argument of the navigate function.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxk843ewc4tqm8yv7sr7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxk843ewc4tqm8yv7sr7a.png" alt="Alt Text" width="800" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is important to note that the best practice of passing data between destination is using a ViewModels but for this tutorial we will use a bundle as it is the Android Navigation Component allows us to use bundles to pass data.&lt;/p&gt;

&lt;p&gt;In our secondFragment we need to receive the data from the arguments. Then we can display the data in our TextView.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3tazogej6i91mmprejdo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3tazogej6i91mmprejdo.png" alt="Alt Text" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we run out app you will see that if you type something in the EditText and press the submit button the app will navigate to the secondFragment and display the information in the TextView.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3odn944fw8vgxj1rzdoj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3odn944fw8vgxj1rzdoj.png" alt="Alt Text" width="800" height="704"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was a simple example on how to use the Android Jetpack Navigation Component. There is much more you can do with it like set animations as you move from one destination to another and so much more. If you want to learn more about the Navigation Component I invite you to visit Android’s official documentation here: &lt;a href="https://developer.android.com/guide/navigation/navigation-getting-started" rel="noopener noreferrer"&gt;https://developer.android.com/guide/navigation/navigation-getting-started&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>jetpack</category>
      <category>navigation</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Kotlin - "Lazy" initialization</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Fri, 18 Sep 2020 12:05:59 +0000</pubDate>
      <link>https://dev.to/paulfranco/kotlin-lazy-initialization-apl</link>
      <guid>https://dev.to/paulfranco/kotlin-lazy-initialization-apl</guid>
      <description>&lt;p&gt;One of the most interesting features of the Kotlin syntax is Lazy initialization but it is also a concept that can be a little tricky to understand. The concept of Lazy initialization was designed to prevent the unnecessary initialization of objects. Lets imagine that you have a are running a program and you want to print out a string. That’s pretty easy to do right?&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgopj8bs289id2pjcidqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgopj8bs289id2pjcidqx.png" alt="1-SYjvlFCUlNVrK7tctOMQWA" width="700" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what if getting this string was from an expensive operation? Well this is where we can use Lazy initialization.&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5h9ps6oiu00ffnat7haj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5h9ps6oiu00ffnat7haj.png" alt="1-4pCZ2RVPLTENyCcJmj9eZA" width="700" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we run this it looks very similar but as we dig further something very interesting begins to happen. In order to illustrate this we will print the name multiple times and also add another print statement withing the lazy block.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbza35u22jncn7o4ahihe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbza35u22jncn7o4ahihe.png" alt="1-WnS0CweLt-bAhdab5rxNkA" width="700" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we run this code we can see that “processing” was printed once while the name was printed multiple times. Why is this? Well, the reason is that when the first println(name) function was called, Kotlin evaluated, executed the code in the Lazy block and saved the computed value. This computed value was then returned each subsequent time without having to evaluate and execute the code in the lazy block again.&lt;/p&gt;

&lt;p&gt;Now, let imagine that we are performing some sort of network call or long running operation. To simulate this we will add a sleep function in our code.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsdw1ponh83zo4be1mzpp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsdw1ponh83zo4be1mzpp.png" alt="Screen Shot 2020-09-18 at 5.02.41 AM" width="800" height="478"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq8roqd1fg6n8vx2ya7zs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq8roqd1fg6n8vx2ya7zs.png" alt="Screen Shot 2020-09-18 at 5.02.56 AM" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, “processing…” was printed to the console and a few seconds later “Paul” was printed out three times almost simultaneously. This is because when the first println(name) function was called, the lazy block was evaluated and executed, the computed value was then saved by Kotlin and when the second and third println(name) function was called the computed value of the name variable only needed to be returned. With Lazy initialization, the value gets computed ONLY upon first access.  &lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>lazy</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Kotlin - Understanding the "open" keyword</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Wed, 16 Sep 2020 01:37:23 +0000</pubDate>
      <link>https://dev.to/paulfranco/kotlin-understanding-the-open-keyword-229g</link>
      <guid>https://dev.to/paulfranco/kotlin-understanding-the-open-keyword-229g</guid>
      <description>&lt;p&gt;Inheritance is the cornerstone of Object-Oriented Programming . OOP is the process of acquiring or using the properties and characteristics of one class by another.&lt;/p&gt;

&lt;p&gt;In Kotlin, the classes, functions, and variables are final by default meaning that they cannot be inherited from by any other class. In order to make a class inheritable to the other classes, you must mark it with the open keyword otherwise you will get an error saying “type is final so can’t be inherited”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2cswqmf6adwwq3ny46jx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2cswqmf6adwwq3ny46jx.png" alt="Alt Text" width="700" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As seen in the image above. RaceCar inherits from Vehicle but no other class can inherit from RaceCar because the RaceCar class is not marked with the open keyword. In the RaceCar class we are able to override the driveFast() function because it is marked with the open keyword inside the parent class Vehicle.&lt;/p&gt;

</description>
      <category>kotlin</category>
    </item>
    <item>
      <title>Android Jetpack: DataBinding Library</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Fri, 04 Sep 2020 15:57:21 +0000</pubDate>
      <link>https://dev.to/paulfranco/android-jetpack-databinding-library-5134</link>
      <guid>https://dev.to/paulfranco/android-jetpack-databinding-library-5134</guid>
      <description>&lt;p&gt;Android Jetpack was introduced in 2018 by Google in order to help developers accelerate android development. Jetpack is a set of components, tools, libraries, and architectural guidance that makes it quick and easy to build great Android applications. One of these libraries is Data Binding.&lt;/p&gt;

&lt;p&gt;The Data Binding Library is a support library that allows developers to bind UI elements in the layout to data sources in the application using a declarative format rather than doing so programmatically. Layouts are often defined in activities with code that calls UI framework methods. For example, the code below calls the findViewById() function to find a TextView and bind it to the messageView variable and the EditText to the nameText variable.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2w4a08jv8uaa8c4jiyxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2w4a08jv8uaa8c4jiyxk.png" alt="Alt Text" width="700" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time we use the findViewById() function to obtain references to views, the Android system has to go through the View hierarchy and find it at runtime. In a large application, this could be many layouts and hundreds of views. Currently, most of the Android phones in the market have a refresh frequency of at least 60 hertz meaning that the screen refreshes at least 60 times per second or approximately every 16 milliseconds. Some phones in the market have higher refresh frequencies giving the Android system even less time to recreate the views. Therefore, having to go through the view hierarchy, again and again, is not a great idea because it reduces the performance of large Android applications.&lt;/p&gt;

&lt;p&gt;Data Binding creates a binding object that contains a reference to each view of a layout sparing the Android system from having to go through the view hierarchy, again and again, to find a reference to a view at runtime. Data Binding not only improves the performance of the app but eliminates the use of the findViewById() function making code easier to read and maintain.&lt;/p&gt;

&lt;p&gt;The first thing we need to do to implement Data Binding in our Android application is to enable dataBinding in the buildFeatures block of the apps build.gradle file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fahclicmhenwid5ciakqz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fahclicmhenwid5ciakqz.png" alt="Alt Text" width="700" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to generate a binding class for the XML layout. To do this we have to wrap the XML layout with   tags.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft656rufle9t854vzf08a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft656rufle9t854vzf08a.png" alt="Alt Text" width="700" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then have to move the xmlns lines from the constraint layout into the opening  tag.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzh86t3md7vh1sqxb9aiv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzh86t3md7vh1sqxb9aiv.png" alt="Alt Text" width="700" height="250"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fine2crl4qle7poest0nq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fine2crl4qle7poest0nq.png" alt="Alt Text" width="700" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Data Binding library will take the name of the layout, in this case, activity_main, and will create a Data Binding object with a similar name like ActivityMainBinding.&lt;/p&gt;

&lt;p&gt;In our MainActivity file, we currently have a Button that uses the findViewById() function. We then set an onClickListener that calls the displayGreeting() function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fttd5bqqwqgk5a9n151lm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fttd5bqqwqgk5a9n151lm.png" alt="Alt Text" width="700" height="305"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84j7vx1yymqo9inxi07i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84j7vx1yymqo9inxi07i.png" alt="Alt Text" width="554" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the displayGreeting() function we declare and initialize a variable named messageView of type TextView and we use the findViewById() to find the view reference. We do the same for variable nameText of type EditText. We then change the text of the messageView and append the text that the user enters in the nameText EditText of the application.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpwi2wbv2cijot6v7cvie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpwi2wbv2cijot6v7cvie.png" alt="Alt Text" width="700" height="147"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwrnz0li1ij0cxp9feswy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwrnz0li1ij0cxp9feswy.png" alt="Alt Text" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use the Data Binding object and simplify our code we have to declare a reference variable for it in our MainActivity.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2rdk64eabejn5n637d1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2rdk64eabejn5n637d1.png" alt="Alt Text" width="700" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we are now using Data Binding we no longer need the setContentView() function in our onCreate() method.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fklxs4jw2v19avd1d46bx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fklxs4jw2v19avd1d46bx.png" alt="Alt Text" width="661" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will instead initialize the Data Binding object with DataBindingUti.setContentView().&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpuj0ptiu23q5t77v6frd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpuj0ptiu23q5t77v6frd.png" alt="Alt Text" width="700" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Data Binding object contains properties for each of the views in the activity_main layout. It used id names for each of the views and created its own reference by getting rid of the underscore and camel casing the name. For example: The Button id in the XML layout is submit_button and the Data Binding object created its own reference with the name submitButton.&lt;/p&gt;

&lt;p&gt;We no longer need the findViewById() functions and we can remove them.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnc36zb9cva76evh37kum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnc36zb9cva76evh37kum.png" alt="Alt Text" width="740" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now use the Binding object. Instead of button.setOnClickListerner. we will use binding.submitButton.setOnClickListener.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fazriwmm35n3bpyzghozt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fazriwmm35n3bpyzghozt.png" alt="Alt Text" width="700" height="75"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now do the same for the other view references in the displayGreeting() function.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdq3hndt6uqozf0rhhrbz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdq3hndt6uqozf0rhhrbz.png" alt="Alt Text" width="756" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, Data Binding allows us to write readable and maintainable code while improving the applications performance.&lt;/p&gt;

</description>
      <category>android</category>
      <category>jetpack</category>
      <category>databinding</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Android Jetpack: 2Way DataBinding</title>
      <dc:creator>Paul Franco</dc:creator>
      <pubDate>Tue, 01 Sep 2020 15:12:03 +0000</pubDate>
      <link>https://dev.to/paulfranco/android-jetpack-2way-databinding-4hac</link>
      <guid>https://dev.to/paulfranco/android-jetpack-2way-databinding-4hac</guid>
      <description>&lt;p&gt;With the introduction of Android Jetpack’s ViewModel and Data Binding we are able to reduce the number of lines of code in out apps significantly. In this article we will walk through a simple application that implements 2-way Data Binding.&lt;/p&gt;

&lt;p&gt;With 2-Way Data Binding when the value of the object changes, the User Interface changes and when the UI changes, the value of the object changes.&lt;/p&gt;

&lt;p&gt;Lets begin by starting a new Project in Android Studio. Select Empty Activity as the project template.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdqkjn3qfvjzkp9bvr4gl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdqkjn3qfvjzkp9bvr4gl.png" alt="Alt Text" width="700" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ll be naming the project TwoWayDemo.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdj0ik1kq5btdo7927khs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdj0ik1kq5btdo7927khs.png" alt="Alt Text" width="700" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to enable Data Binding in the buildFeatures block, add the dependencies for ViewModel and LiveData in the dependencies block, and apply the kotlin-kapt plugin in the app’s build.gradle file. A list of updated dependencies for Lifecycle-aware components can be found here: &lt;a href="https://developer.android.com/jetpack/androidx/releases/lifecycle" rel="noopener noreferrer"&gt;https://developer.android.com/jetpack/androidx/releases/lifecycle&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffexi0eqsdq89z7k66bkv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffexi0eqsdq89z7k66bkv.png" alt="Alt Text" width="700" height="361"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpsutd0eflll7bwa35zri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpsutd0eflll7bwa35zri.png" alt="Alt Text" width="700" height="374"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhu5pmnjuuukzlmf5ids5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhu5pmnjuuukzlmf5ids5.png" alt="Alt Text" width="700" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we will create a ViewModel Class called MainActivityViewModel which for now will only hold a single MutableLiveData of type String. MutableLiveData is Read/Write while LiveData is ReadOnly. We will initialize a variable of fullName with the initial value of “John Doe”.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fokaipi4umkkys7pr0xyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fokaipi4umkkys7pr0xyw.png" alt="Alt Text" width="700" height="342"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F749qsal3pcerk8lxlxpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F749qsal3pcerk8lxlxpn.png" alt="Alt Text" width="700" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to utilize data binding, we need to add Layout Tags as the outermost tags in our activity_main.xml file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fociazhdftrxmj5sm32hi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fociazhdftrxmj5sm32hi.png" alt="Alt Text" width="700" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we need to add Data Tags and define a reference variable for the MainActivityViewModel Class.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fez55uydfvl58ftrs102a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fez55uydfvl58ftrs102a.png" alt="Alt Text" width="700" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now bind the value of the fullname MutableLiveData to the TextView.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2aanmo4e0aarlzzq1jqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2aanmo4e0aarlzzq1jqr.png" alt="Alt Text" width="539" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To complete our initial set up we need to define our data binding object in our MainActivity and replace the setContentView with our binding object.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyz0f8qvprg9wu4m9038s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyz0f8qvprg9wu4m9038s.png" alt="Alt Text" width="700" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to define a reference variable for our ViewModel.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs9s7jgxbwoun5esdlc6m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs9s7jgxbwoun5esdlc6m.png" alt="Alt Text" width="700" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now need to assign this viewModel Object to the viewModel object we defined in out activity_main layout file.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpzj6fw519stl320io07d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpzj6fw519stl320io07d.png" alt="Alt Text" width="700" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, since we are using LiveData we have to set MainActivity as the LifeCycle owner.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6gb4k0ro989wjwleoej3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6gb4k0ro989wjwleoej3.png" alt="Alt Text" width="700" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we run our app, we should be able to see a TextView with the fullname value we defined earlier in our MainActivityViewModel class.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fapd771odldpoeuou2q4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fapd771odldpoeuou2q4a.png" alt="Alt Text" width="417" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is one-way data binding. We bound a view to a ViewModel Object. The bound views are displaying the values of the properties of the ViewModel object. Now that we have implemented one-way data binding, lets make a few changes to illustrate 2-way data binding.&lt;/p&gt;

&lt;p&gt;Above the TextView, lets add an EditText so that when we type something on the EditText it will be immediately displayed in the TextView.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frftl1eydlfuj3dd24bi3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frftl1eydlfuj3dd24bi3.png" alt="Alt Text" width="700" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have bound the EditText to viewModel.fullname, we can see that both the EditText and the TextView are displaying “John Doe”.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv5gee8dl1so2b8srushs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv5gee8dl1so2b8srushs.png" alt="Alt Text" width="370" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if we try to change the EditText to Robert Smith, nothing happens to the EditText.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fch52dn9lpplcva4xqjju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fch52dn9lpplcva4xqjju.png" alt="Alt Text" width="370" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because our app is still only implementing one-way data binding. In order to fully implement 2-way data binding we have to make a small change in our activity_main layout out file. In our EditText we have to add a = sign in between the @ and { of our text property.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd45u7xc4d3kfanbh4pm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd45u7xc4d3kfanbh4pm2.png" alt="Alt Text" width="537" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also have to annotate our fullname variable in out MainActivityViewModel with the Bindable annotation.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fow6ilpdgdm03i9bb7kij.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fow6ilpdgdm03i9bb7kij.png" alt="Alt Text" width="529" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last step is to extend Observable and implement its methods.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgx48xslxdrdmtqb5lrpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgx48xslxdrdmtqb5lrpu.png" alt="Alt Text" width="700" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you run the app you will see that as you type something in the EditText the TextView will automatically display whatever you wrote. This was a simple example of how to implement 2-way Data Binding with ViewModel and LiveData.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi1adqc12phx3mjok0k7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi1adqc12phx3mjok0k7a.png" alt="Alt Text" width="380" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>jetpack</category>
      <category>databinding</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
