<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Romman Sabbir | Senior Android Engineer | Music Producer]]></title><description><![CDATA[Senior Android Engineer (Kotlin, Threading, Clean Arch, JetPack) | Music Producer]]></description><link>https://rommansabbir.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 04 Sep 2026 17:35:55 GMT</lastBuildDate><atom:link href="https://rommansabbir.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Kotlin : Channels vs Flow in Practice]]></title><description><![CDATA[Introduction
Choosing between Channels and Flow causes more confusion than almost any other Kotlin coroutine concept. This isn't about which is "better" - they solve different problems. This guide provides clear, practical rules with real examples yo...]]></description><link>https://rommansabbir.com/kotlin-channels-vs-flow-in-practice</link><guid isPermaLink="true">https://rommansabbir.com/kotlin-channels-vs-flow-in-practice</guid><category><![CDATA[Kotlin]]></category><category><![CDATA[Channels]]></category><category><![CDATA[flow]]></category><category><![CDATA[coroutines]]></category><category><![CDATA[coroutines-flow]]></category><category><![CDATA[kmp]]></category><category><![CDATA[Android]]></category><category><![CDATA[iOS]]></category><category><![CDATA[compose multiplatform]]></category><category><![CDATA[Kotlin Multiplatform]]></category><category><![CDATA[kotlin coroutines]]></category><category><![CDATA[kotlin-flow]]></category><category><![CDATA[kotlin beginner]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[techblog]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Thu, 01 Jan 2026 11:03:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767265062728/e0ebb650-a20b-4fc7-826f-de32fd054d3d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Choosing between Channels and Flow causes more confusion than almost any other Kotlin coroutine concept. This isn't about which is "better" - they solve different problems. This guide provides clear, practical rules with real examples you can use immediately in your projects.</p>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-chapter-1-the-fundamental-distinction">Chapter 1: The Fundamental Distinction</h2>
<h3 id="heading-channels-communication-mechanism">Channels: Communication Mechanism</h3>
<p>Channels are for <strong>coroutine-to-coroutine communication</strong>. Think of them as pipes where one coroutine puts data in and another takes it out. Each piece of data is consumed exactly once.</p>
<h3 id="heading-flow-data-stream-abstraction">Flow: Data Stream Abstraction</h3>
<p>Flow is for <strong>asynchronous data streams</strong>. Think of them as sequences of values over time that can be transformed, combined, and processed.</p>
<p><strong>Simple Analogy:</strong></p>
<ul>
<li><p><strong>Channel</strong> = Handing off a physical document to a coworker (once they take it, you don't have it anymore)</p>
</li>
<li><p><strong>Flow</strong> = A live data feed that multiple people can watch simultaneously</p>
</li>
</ul>
<h2 id="heading-chapter-2-channel-in-practice">Chapter 2: Channel in Practice</h2>
<h3 id="heading-when-you-absolutely-need-a-channel">When You Absolutely Need a Channel</h3>
<h4 id="heading-example-1-work-queue-pattern">Example 1: Work Queue Pattern</h4>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Image processing pipeline - each image should be processed exactly once</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageProcessor</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> processingChannel = Channel&lt;ImageJob&gt;(capacity = Channel.UNLIMITED)

    <span class="hljs-keyword">init</span> {
        launchProcessorWorkers(count = <span class="hljs-number">4</span>)
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">launchProcessorWorkers</span><span class="hljs-params">(count: <span class="hljs-type">Int</span>)</span></span> {
        repeat(count) { workerId -&gt;
            launch(Dispatchers.IO) {
                <span class="hljs-keyword">for</span> (job <span class="hljs-keyword">in</span> processingChannel) {
                    <span class="hljs-comment">// Each job is consumed by exactly one worker</span>
                    processImage(job)
                }
            }
        }
    }

    <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">submitJob</span><span class="hljs-params">(job: <span class="hljs-type">ImageJob</span>)</span></span> {
        processingChannel.send(job)
    }
}
</code></pre>
<h4 id="heading-example-2-request-response-coordination">Example 2: Request-Response Coordination</h4>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Communication between two specific coroutines</span>
<span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">coordinateTask</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> responseChannel = Channel&lt;Result&gt;()

    launch {
        <span class="hljs-comment">// Worker does some work</span>
        <span class="hljs-keyword">val</span> result = performComplexCalculation()
        responseChannel.send(result)
    }

    <span class="hljs-comment">// Original coroutine waits for the response</span>
    <span class="hljs-keyword">val</span> result = responseChannel.receive()
    handleResult(result)
}
</code></pre>
<h3 id="heading-channel-characteristics-to-remember">Channel Characteristics to Remember:</h3>
<ul>
<li><p><strong>Single consumption</strong>: Each element has exactly one consumer</p>
</li>
<li><p><strong>Hot</strong>: Produces values even without collectors</p>
</li>
<li><p><strong>Blocking send</strong>: Can suspend if buffer is full (backpressure)</p>
</li>
<li><p><strong>ConflatedChannel</strong>: Drops previous value when buffer is full (useful for latest state)</p>
</li>
</ul>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-chapter-3-flow-in-practice">Chapter 3: Flow in Practice</h2>
<h3 id="heading-when-to-use-regular-flow">When to Use Regular Flow</h3>
<h4 id="heading-example-1-database-observation">Example 1: Database Observation</h4>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Each collector gets its own independent stream</span>
<span class="hljs-meta">@Dao</span>
<span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserDao</span> </span>{
    <span class="hljs-meta">@Query(<span class="hljs-meta-string">"SELECT * FROM users"</span>)</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">observeUsers</span><span class="hljs-params">()</span></span>: Flow&lt;List&lt;User&gt;&gt;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRepository</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getActiveUsers</span><span class="hljs-params">()</span></span>: Flow&lt;List&lt;User&gt;&gt; = 
        userDao.observeUsers()
            .map { users -&gt; users.filter { it.isActive } }
            .flowOn(Dispatchers.IO)
}

<span class="hljs-comment">// In ViewModel</span>
<span class="hljs-keyword">val</span> activeUsers: Flow&lt;List&lt;User&gt;&gt; = repository.getActiveUsers()

<span class="hljs-comment">// In UI (each collector starts fresh)</span>
lifecycleScope.launch {
    activeUsers.collect { users -&gt;
        updateUserList(users)
    }
}
</code></pre>
<h4 id="heading-example-2-network-data-stream">Example 2: Network Data Stream</h4>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Cold stream - nothing happens until collection</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">fetchStockPrices</span><span class="hljs-params">(symbol: <span class="hljs-type">String</span>)</span></span>: Flow&lt;PriceUpdate&gt; = flow {
    <span class="hljs-keyword">val</span> webSocket = createWebSocketConnection(symbol)
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
            <span class="hljs-keyword">val</span> update = webSocket.receiveUpdate()
            emit(update)
        }
    } <span class="hljs-keyword">finally</span> {
        webSocket.close()
    }
}

<span class="hljs-comment">// Each collector creates a new WebSocket connection</span>
viewModelScope.launch {
    fetchStockPrices(<span class="hljs-string">"GOOGL"</span>)
        .collect { update -&gt;
            updateUi(update)
        }
}
</code></pre>
<h2 id="heading-chapter-4-stateflow-for-ui-state-essential">Chapter 4: StateFlow for UI State (Essential)</h2>
<h3 id="heading-the-right-way-to-handle-ui-state">The Right Way to Handle UI State</h3>
<h4 id="heading-example-screen-state-management">Example: Screen State Management</h4>
<pre><code class="lang-kotlin"><span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginScreenState</span></span>(
    <span class="hljs-keyword">val</span> email: String = <span class="hljs-string">""</span>,
    <span class="hljs-keyword">val</span> password: String = <span class="hljs-string">""</span>,
    <span class="hljs-keyword">val</span> isLoading: <span class="hljs-built_in">Boolean</span> = <span class="hljs-literal">false</span>,
    <span class="hljs-keyword">val</span> error: String? = <span class="hljs-literal">null</span>,
    <span class="hljs-keyword">val</span> isLoggedIn: <span class="hljs-built_in">Boolean</span> = <span class="hljs-literal">false</span>
)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginViewModel</span> : <span class="hljs-type">ViewModel</span></span>() {
    <span class="hljs-comment">// Private mutable state</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> _uiState = MutableStateFlow(LoginScreenState())

    <span class="hljs-comment">// Public immutable state</span>
    <span class="hljs-keyword">val</span> uiState: StateFlow&lt;LoginScreenState&gt; = _uiState

    <span class="hljs-comment">// State updates</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onEmailChanged</span><span class="hljs-params">(email: <span class="hljs-type">String</span>)</span></span> {
        _uiState.update { it.copy(email = email) }
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onPasswordChanged</span><span class="hljs-params">(password: <span class="hljs-type">String</span>)</span></span> {
        _uiState.update { it.copy(password = password) }
    }

    <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">login</span><span class="hljs-params">()</span></span> {
        _uiState.update { it.copy(isLoading = <span class="hljs-literal">true</span>, error = <span class="hljs-literal">null</span>) }

        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">val</span> result = authRepository.login(
                email = _uiState.value.email,
                password = _uiState.value.password
            )
            _uiState.update { 
                it.copy(isLoading = <span class="hljs-literal">false</span>, isLoggedIn = result.success) 
            }
        } <span class="hljs-keyword">catch</span> (e: Exception) {
            _uiState.update { 
                it.copy(isLoading = <span class="hljs-literal">false</span>, error = e.message) 
            }
        }
    }
}

<span class="hljs-comment">// In Activity/Fragment</span>
lifecycleScope.launch {
    viewModel.uiState
        .distinctUntilChanged()
        .collect { state -&gt;
            <span class="hljs-comment">// React to state changes</span>
            binding.emailEditText.setText(state.email)
            binding.progressBar.isVisible = state.isLoading
            binding.errorText.text = state.error
        }
}
</code></pre>
<h3 id="heading-why-stateflow-beats-livedata-for-ui-state">Why StateFlow Beats LiveData for UI State:</h3>
<ol>
<li><p><strong>Coroutine-native</strong>: No lifecycle observers needed</p>
</li>
<li><p><strong>Null safety</strong>: Must have initial value</p>
</li>
<li><p><strong>Better testing</strong>: Can be collected in tests easily</p>
</li>
<li><p><strong>Flow operators</strong>: <code>map</code>, <code>filter</code>, <code>combine</code>, etc.</p>
</li>
</ol>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-chapter-5-sharedflow-for-events">Chapter 5: SharedFlow for Events</h2>
<h3 id="heading-handling-one-time-events-correctly">Handling One-Time Events Correctly</h3>
<h4 id="heading-example-1-ui-events-snackbar-navigation">Example 1: UI Events (Snackbar, Navigation)</h4>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Common mistake: Using Channel for events</span>
<span class="hljs-comment">// WRONG: val events = Channel&lt;Event&gt;()</span>

<span class="hljs-comment">// CORRECT: Using SharedFlow</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EventViewModel</span> : <span class="hljs-type">ViewModel</span></span>() {
    <span class="hljs-comment">// Private mutable flow with replay for new collectors</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> _events = MutableSharedFlow&lt;UiEvent&gt;(
        replay = <span class="hljs-number">0</span>, <span class="hljs-comment">// No replay for one-time events</span>
        extraBufferCapacity = <span class="hljs-number">10</span>
    )

    <span class="hljs-keyword">val</span> events: SharedFlow&lt;UiEvent&gt; = _events.asSharedFlow()

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showMessage</span><span class="hljs-params">(message: <span class="hljs-type">String</span>)</span></span> {
        viewModelScope.launch {
            _events.emit(UiEvent.ShowSnackbar(message))
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">navigateTo</span><span class="hljs-params">(destination: <span class="hljs-type">String</span>)</span></span> {
        viewModelScope.launch {
            _events.emit(UiEvent.Navigate(destination))
        }
    }
}

<span class="hljs-keyword">sealed</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UiEvent</span> </span>{
    <span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShowSnackbar</span></span>(<span class="hljs-keyword">val</span> message: String) : UiEvent()
    <span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Navigate</span></span>(<span class="hljs-keyword">val</span> destination: String) : UiEvent()
}

<span class="hljs-comment">// In Activity/Fragment - safely collect events</span>
lifecycleScope.launch {
    viewModel.events
        .<span class="hljs-keyword">catch</span> { e -&gt; Log.e(<span class="hljs-string">"EventCollection"</span>, <span class="hljs-string">"Error"</span>, e) }
        .collect { event -&gt;
            <span class="hljs-keyword">when</span> (event) {
                <span class="hljs-keyword">is</span> UiEvent.ShowSnackbar -&gt; showSnackbar(event.message)
                <span class="hljs-keyword">is</span> UiEvent.Navigate -&gt; navigateTo(event.destination)
            }
        }
}
</code></pre>
<h4 id="heading-example-2-broadcast-updates">Example 2: Broadcast Updates</h4>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Multiple observers need same updates</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LocationManager</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> _locationUpdates = MutableSharedFlow&lt;Location&gt;(
        replay = <span class="hljs-number">1</span>, <span class="hljs-comment">// New observers get last location</span>
        extraBufferCapacity = <span class="hljs-number">50</span>
    )

    <span class="hljs-keyword">val</span> locationUpdates: SharedFlow&lt;Location&gt; = _locationUpdates.asSharedFlow()

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">startListening</span><span class="hljs-params">()</span></span> {
        <span class="hljs-comment">// Simulate location updates</span>
        launch {
            <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
                <span class="hljs-keyword">val</span> location = fetchCurrentLocation()
                _locationUpdates.emit(location)
                delay(<span class="hljs-number">1000</span>)
            }
        }
    }
}

<span class="hljs-comment">// Multiple screens can observe the same location</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MapFragment</span> </span>{
    <span class="hljs-keyword">init</span> {
        lifecycleScope.launch {
            locationManager.locationUpdates.collect { location -&gt;
                updateMap(location)
            }
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WeatherFragment</span> </span>{
    <span class="hljs-keyword">init</span> {
        lifecycleScope.launch {
            locationManager.locationUpdates.collect { location -&gt;
                updateWeather(location)
            }
        }
    }
}
</code></pre>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-chapter-6-common-patterns-and-solutions">Chapter 6: Common Patterns and Solutions</h2>
<h3 id="heading-pattern-1-search-with-debounce">Pattern 1: Search with Debounce</h3>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SearchViewModel</span> : <span class="hljs-type">ViewModel</span></span>() {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> searchQuery = MutableStateFlow(<span class="hljs-string">""</span>)

    <span class="hljs-keyword">val</span> searchResults: StateFlow&lt;SearchResult&gt; = searchQuery
        .debounce(<span class="hljs-number">300</span>) <span class="hljs-comment">// Wait 300ms after last keystroke</span>
        .distinctUntilChanged()
        .filter { it.length &gt;= <span class="hljs-number">3</span> } <span class="hljs-comment">// Only search if 3+ chars</span>
        .mapLatest { query -&gt; <span class="hljs-comment">// Cancel previous search</span>
            <span class="hljs-keyword">if</span> (query.isEmpty()) {
                SearchResult.Empty
            } <span class="hljs-keyword">else</span> {
                SearchResult.Loading
                <span class="hljs-keyword">try</span> {
                    SearchResult.Success(repository.search(query))
                } <span class="hljs-keyword">catch</span> (e: Exception) {
                    SearchResult.Error(e.message)
                }
            }
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(<span class="hljs-number">5000</span>),
            initialValue = SearchResult.Empty
        )

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onQueryChanged</span><span class="hljs-params">(query: <span class="hljs-type">String</span>)</span></span> {
        searchQuery.value = query
    }
}
</code></pre>
<h3 id="heading-pattern-2-combining-multiple-flows">Pattern 2: Combining Multiple Flows</h3>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DashboardViewModel</span> : <span class="hljs-type">ViewModel</span></span>() {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> userFlow = userRepository.observeUser()
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> messagesFlow = chatRepository.observeMessages()
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> notificationsFlow = notificationRepository.observeNotifications()

    <span class="hljs-keyword">val</span> dashboardState: StateFlow&lt;DashboardState&gt; = combine(
        userFlow,
        messagesFlow,
        notificationsFlow
    ) { user, messages, notifications -&gt;
        DashboardState(
            userName = user.name,
            unreadMessages = messages.count { !it.isRead },
            notificationCount = notifications.size,
            lastMessage = messages.lastOrNull()?.preview
        )
    }
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(),
        initialValue = DashboardState()
    )
}
</code></pre>
<h3 id="heading-pattern-3-retry-with-exponential-backoff">Pattern 3: Retry with Exponential Backoff</h3>
<pre><code class="lang-kotlin"><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">fetchWithRetry</span><span class="hljs-params">()</span></span>: Flow&lt;Data&gt; = flow {
    <span class="hljs-keyword">var</span> currentDelay = <span class="hljs-number">1000L</span> <span class="hljs-comment">// Start with 1 second</span>
    <span class="hljs-keyword">val</span> maxDelay = <span class="hljs-number">30000L</span> <span class="hljs-comment">// Max 30 seconds</span>

    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span> = api.fetchData()
            emit(<span class="hljs-keyword">data</span>)
            delay(<span class="hljs-number">5000</span>) <span class="hljs-comment">// Normal delay between successful fetches</span>
        } <span class="hljs-keyword">catch</span> (e: IOException) {
            <span class="hljs-comment">// Exponential backoff on failure</span>
            delay(currentDelay)
            currentDelay = (currentDelay * <span class="hljs-number">2</span>).coerceAtMost(maxDelay)
        }
    }
}
</code></pre>
<h2 id="heading-chapter-7-migration-guide-channel-sharedflow">Chapter 7: Migration Guide (Channel → SharedFlow)</h2>
<h3 id="heading-before-old-channel-pattern">Before (Old Channel Pattern):</h3>
<pre><code class="lang-kotlin"><span class="hljs-comment">// OLD: Channel for events</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OldViewModel</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> eventChannel = Channel&lt;Event&gt;(Channel.BUFFERED)
    <span class="hljs-keyword">val</span> events = eventChannel.receiveAsFlow()

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">sendEvent</span><span class="hljs-params">(event: <span class="hljs-type">Event</span>)</span></span> {
        viewModelScope.launch {
            eventChannel.send(event)
        }
    }
}
</code></pre>
<h3 id="heading-after-modern-sharedflow">After (Modern SharedFlow):</h3>
<pre><code class="lang-kotlin"><span class="hljs-comment">// NEW: SharedFlow for events</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewViewModel</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> _events = MutableSharedFlow&lt;Event&gt;(
        extraBufferCapacity = <span class="hljs-number">64</span>
    )
    <span class="hljs-keyword">val</span> events = _events.asSharedFlow()

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">sendEvent</span><span class="hljs-params">(event: <span class="hljs-type">Event</span>)</span></span> {
        viewModelScope.launch {
            _events.emit(event)
        }
    }
}
</code></pre>
<h3 id="heading-benefits-of-migration">Benefits of Migration:</h3>
<ol>
<li><p><strong>Multiple collectors</strong>: Multiple screens can listen</p>
</li>
<li><p><strong>No lifecycle issues</strong>: SharedFlow is safer with lifecycle</p>
</li>
<li><p><strong>Better operators</strong>: Can use <code>catch</code>, <code>onEach</code>, etc.</p>
</li>
<li><p><strong>Cleaner API</strong>: No need to wrap in <code>receiveAsFlow()</code></p>
</li>
</ol>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-chapter-8-decision-framework">Chapter 8: Decision Framework</h2>
<h3 id="heading-quick-decision-tree">Quick Decision Tree:</h3>
<ol>
<li><p><strong>Are you representing UI state that should always have a value?</strong></p>
<ul>
<li><p>✅ <strong>StateFlow</strong></p>
</li>
<li><p>❌ Not Channel, not regular Flow</p>
</li>
</ul>
</li>
<li><p><strong>Are you emitting one-time events (snackbars, navigation)?</strong></p>
<ul>
<li><p>✅ <strong>SharedFlow</strong> (replay = 0)</p>
</li>
<li><p>❌ Not Channel, not StateFlow</p>
</li>
</ul>
</li>
<li><p><strong>Do multiple collectors need the same data stream?</strong></p>
<ul>
<li><p>✅ <strong>SharedFlow</strong> (with appropriate replay)</p>
</li>
<li><p>❌ Not Channel (single consumer)</p>
</li>
</ul>
</li>
<li><p><strong>Is each piece of data consumed by exactly one worker?</strong></p>
<ul>
<li><p>✅ <strong>Channel</strong> (work queues, task distribution)</p>
</li>
<li><p>❌ Not Flow, not SharedFlow</p>
</li>
</ul>
</li>
<li><p><strong>Do you need a cold stream that starts fresh for each collector?</strong></p>
<ul>
<li><p>✅ <strong>Regular Flow</strong></p>
</li>
<li><p>❌ Not Channel (hot), not StateFlow (always has value)</p>
</li>
</ul>
</li>
<li><p><strong>Are you coordinating between two specific coroutines?</strong></p>
<ul>
<li><p>✅ <strong>Channel</strong> (request-response patterns)</p>
</li>
<li><p>❌ Not SharedFlow (broadcast)</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-chapter-9-performance-considerations">Chapter 9: Performance Considerations</h2>
<h3 id="heading-memory-usage">Memory Usage:</h3>
<ul>
<li><p><strong>StateFlow</strong>: Stores one value in memory</p>
</li>
<li><p><strong>SharedFlow</strong>: Stores replay cache + buffer</p>
</li>
<li><p><strong>Channel</strong>: Stores buffer (size depends on capacity)</p>
</li>
<li><p><strong>Regular Flow</strong>: No storage (cold stream)</p>
</li>
</ul>
<h3 id="heading-backpressure-handling">Backpressure Handling:</h3>
<ul>
<li><p><strong>Channel</strong>: Suspends sender when buffer full</p>
</li>
<li><p><strong>Flow</strong>: Built-in backpressure via suspension</p>
</li>
<li><p><strong>SharedFlow</strong>: Drops or buffers based on configuration</p>
</li>
<li><p><strong>StateFlow</strong>: Always accepts new values (replaces old)</p>
</li>
</ul>
<h3 id="heading-collector-overhead">Collector Overhead:</h3>
<ul>
<li><p>Each <strong>Flow</strong> collector creates independent execution</p>
</li>
<li><p><strong>SharedFlow</strong> shares execution among collectors</p>
</li>
<li><p><strong>Channel</strong> has no collectors (only receivers)</p>
</li>
</ul>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-chapter-10-testing-strategies">Chapter 10: Testing Strategies</h2>
<h3 id="heading-testing-stateflow">Testing StateFlow:</h3>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Test</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> `uiState should update on login success`<span class="hljs-params">()</span></span> = runTest {
    <span class="hljs-keyword">val</span> viewModel = LoginViewModel(mockRepository)

    <span class="hljs-comment">// Set up initial state</span>
    viewModel.onEmailChanged(<span class="hljs-string">"test@example.com"</span>)
    viewModel.onPasswordChanged(<span class="hljs-string">"password"</span>)

    <span class="hljs-comment">// Collect values</span>
    <span class="hljs-keyword">val</span> collectedStates = mutableListOf&lt;LoginScreenState&gt;()
    <span class="hljs-keyword">val</span> job = launch {
        viewModel.uiState.collect { collectedStates.add(it) }
    }

    <span class="hljs-comment">// Trigger action</span>
    viewModel.login()

    <span class="hljs-comment">// Verify state transitions</span>
    assertThat(collectedStates).containsExactly(
        LoginScreenState(email = <span class="hljs-string">"test@example.com"</span>, password = <span class="hljs-string">"password"</span>),
        LoginScreenState(email = <span class="hljs-string">"test@example.com"</span>, password = <span class="hljs-string">"password"</span>, isLoading = <span class="hljs-literal">true</span>),
        LoginScreenState(email = <span class="hljs-string">"test@example.com"</span>, password = <span class="hljs-string">"password"</span>, isLoggedIn = <span class="hljs-literal">true</span>)
    )

    job.cancel()
}
</code></pre>
<h3 id="heading-testing-sharedflow-events">Testing SharedFlow Events:</h3>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Test</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> `should emit snackbar event on error`<span class="hljs-params">()</span></span> = runTest {
    <span class="hljs-keyword">val</span> viewModel = EventViewModel()
    <span class="hljs-keyword">val</span> events = mutableListOf&lt;UiEvent&gt;()

    <span class="hljs-comment">// Collect events</span>
    <span class="hljs-keyword">val</span> job = launch {
        viewModel.events.collect { events.add(it) }
    }

    <span class="hljs-comment">// Trigger error</span>
    viewModel.showMessage(<span class="hljs-string">"Error occurred"</span>)

    <span class="hljs-comment">// Verify event was emitted</span>
    assertThat(events).containsExactly(
        UiEvent.ShowSnackbar(<span class="hljs-string">"Error occurred"</span>)
    )

    job.cancel()
}
</code></pre>
<h2 id="heading-summary-rules-of-thumb">Summary: Rules of Thumb</h2>
<ol>
<li><p><strong>UI State = StateFlow</strong> (always)</p>
</li>
<li><p><strong>Events = SharedFlow</strong> (almost always)</p>
</li>
<li><p><strong>Data streams = Flow or SharedFlow</strong> (depending on sharing needs)</p>
</li>
<li><p><strong>Work coordination = Channel</strong> (rare, specific cases)</p>
</li>
<li><p><strong>When in doubt, start with Flow/SharedFlow, not Channel</strong></p>
</li>
</ol>
<p>Remember: Channels are low-level primitives. Most application code should use the higher-level abstractions (Flow, StateFlow, SharedFlow). Reserve Channels for specific coordination patterns where you truly need single-consumer semantics.</p>
<hr />
<p>That’s it for today. Happy coding…</p>
]]></content:encoded></item><item><title><![CDATA[Kotlin Channels: A Simple, Practical Guide (Beginner → Advanced)]]></title><description><![CDATA[This guide explains what Channels are, when to use them, how to use them correctly, and when NOT to use them — in simple, professional language.

1. What problem do Channels solve?
In Kotlin coroutines, you often have multiple coroutines running at t...]]></description><link>https://rommansabbir.com/kotlin-channels-a-simple-practical-guide-beginner-advanced</link><guid isPermaLink="true">https://rommansabbir.com/kotlin-channels-a-simple-practical-guide-beginner-advanced</guid><category><![CDATA[Kotlin]]></category><category><![CDATA[Channels]]></category><category><![CDATA[kotlin beginner]]></category><category><![CDATA[Kotlin Multiplatform]]></category><category><![CDATA[kotlin coroutines]]></category><category><![CDATA[kotlin-flow]]></category><category><![CDATA[Threading]]></category><category><![CDATA[coroutines]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[backpressure]]></category><category><![CDATA[Threads]]></category><category><![CDATA[rendezvous]]></category><category><![CDATA[kmp]]></category><category><![CDATA[Android]]></category><category><![CDATA[iOS]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Tue, 30 Dec 2025 11:36:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767094238647/bfe4fc1d-0fac-407a-943a-b90de8733853.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>This guide explains <strong>what Channels are</strong>, <strong>when to use them</strong>, <strong>how to use them correctly</strong>, and <strong>when NOT to use them</strong> — in simple, professional language.</p>
</blockquote>
<h2 id="heading-1-what-problem-do-channels-solve">1. What problem do Channels solve?</h2>
<p>In Kotlin coroutines, you often have <strong>multiple coroutines running at the same time</strong>.</p>
<p>Sometimes one coroutine:</p>
<ul>
<li><p>produces data (events, tasks, values)</p>
</li>
<li><p>another coroutine consumes that data</p>
</li>
</ul>
<p>You need a <strong>safe, suspendable way</strong> to pass data between them.</p>
<p>👉 <strong>Channel</strong> is Kotlin’s solution for this.</p>
<h2 id="heading-2-what-is-a-channel-simple-definition">2. What is a Channel (simple definition)</h2>
<p>A <strong>Channel</strong> is a <strong>thread-safe communication primitive</strong> used to:</p>
<ul>
<li><p>send values from one coroutine</p>
</li>
<li><p>receive those values in another coroutine</p>
</li>
</ul>
<p>Key properties:</p>
<ul>
<li><p><code>send()</code> suspends if the channel cannot accept data</p>
</li>
<li><p><code>receive()</code> suspends if no data is available</p>
</li>
<li><p>Channels respect coroutine cancellation</p>
</li>
</ul>
<h2 id="heading-3-basic-channel-rendezvous">3. Basic Channel (Rendezvous)</h2>
<h3 id="heading-characteristics">Characteristics</h3>
<ul>
<li><p>No buffer (capacity = 0)</p>
</li>
<li><p>Sender and receiver must meet</p>
</li>
<li><p>Guarantees backpressure</p>
</li>
</ul>
<h3 id="heading-example-background-task-ui-layer">Example: Background task → UI layer</h3>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> kotlinx.coroutines.*
<span class="hljs-keyword">import</span> kotlinx.coroutines.channels.Channel

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> = runBlocking {
    <span class="hljs-keyword">val</span> resultChannel = Channel&lt;String&gt;()

    <span class="hljs-comment">// Background work</span>
    launch(Dispatchers.Default) {
        <span class="hljs-keyword">val</span> result = heavyComputation()
        resultChannel.send(result) <span class="hljs-comment">// suspends until received</span>
    }

    <span class="hljs-comment">// UI or caller</span>
    launch {
        <span class="hljs-keyword">val</span> value = resultChannel.receive()
        println(<span class="hljs-string">"Result received: <span class="hljs-variable">$value</span>"</span>)
    }
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">heavyComputation</span><span class="hljs-params">()</span></span>: String {
    Thread.sleep(<span class="hljs-number">500</span>)
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Success"</span>
}
</code></pre>
<h3 id="heading-when-this-is-good">When this is good</h3>
<ul>
<li><p>Strict one-to-one communication</p>
</li>
<li><p>You want producer to slow down if consumer is not ready</p>
</li>
<li><p>Event-style handoff</p>
</li>
</ul>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-4-buffered-channel-queue-behavior">4. Buffered Channel (Queue behavior)</h2>
<h3 id="heading-characteristics-1">Characteristics</h3>
<ul>
<li><p>Holds multiple values</p>
</li>
<li><p>Producer can run ahead (up to capacity)</p>
</li>
<li><p>Reduces suspension overhead</p>
</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> channel = Channel&lt;<span class="hljs-built_in">Int</span>&gt;(capacity = <span class="hljs-number">10</span>)
</code></pre>
<h3 id="heading-example-logging-system">Example: Logging system</h3>
<pre><code class="lang-kotlin"><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> = runBlocking {
    <span class="hljs-keyword">val</span> logChannel = Channel&lt;String&gt;(capacity = <span class="hljs-number">50</span>)

    <span class="hljs-comment">// Log producer (fast)</span>
    launch {
        repeat(<span class="hljs-number">100</span>) {
            logChannel.send(<span class="hljs-string">"Log message #<span class="hljs-variable">$it</span>"</span>)
        }
        logChannel.close()
    }

    <span class="hljs-comment">// Log consumer (slow IO)</span>
    launch(Dispatchers.IO) {
        <span class="hljs-keyword">for</span> (log <span class="hljs-keyword">in</span> logChannel) {
            writeLogToDisk(log)
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">writeLogToDisk</span><span class="hljs-params">(log: <span class="hljs-type">String</span>)</span></span> {
    Thread.sleep(<span class="hljs-number">50</span>)
    println(<span class="hljs-string">"Written: <span class="hljs-variable">$log</span>"</span>)
}
</code></pre>
<h3 id="heading-when-to-use">When to use</h3>
<ul>
<li><p>Logging</p>
</li>
<li><p>Analytics</p>
</li>
<li><p>Background batching</p>
</li>
<li><p>Task queues</p>
</li>
</ul>
<h2 id="heading-5-channel-as-a-work-queue-multiple-consumers">5. Channel as a Work Queue (Multiple Consumers)</h2>
<h3 id="heading-pattern">Pattern</h3>
<ul>
<li><p>One producer</p>
</li>
<li><p>Many consumers</p>
</li>
<li><p>Each item processed once</p>
</li>
</ul>
<h3 id="heading-example-processing-network-requests">Example: Processing network requests</h3>
<pre><code class="lang-kotlin"><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> = runBlocking {
    <span class="hljs-keyword">val</span> requestChannel = Channel&lt;<span class="hljs-built_in">Int</span>&gt;(capacity = <span class="hljs-number">20</span>)

    <span class="hljs-comment">// Producer</span>
    launch {
        repeat(<span class="hljs-number">10</span>) {
            requestChannel.send(it)
        }
        requestChannel.close()
    }

    <span class="hljs-comment">// Workers</span>
    repeat(<span class="hljs-number">3</span>) { workerId -&gt;
        launch {
            <span class="hljs-keyword">for</span> (request <span class="hljs-keyword">in</span> requestChannel) {
                handleRequest(workerId, request)
            }
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">handleRequest</span><span class="hljs-params">(workerId: <span class="hljs-type">Int</span>, request: <span class="hljs-type">Int</span>)</span></span> {
    Thread.sleep(<span class="hljs-number">200</span>)
    println(<span class="hljs-string">"Worker <span class="hljs-variable">$workerId</span> handled request <span class="hljs-variable">$request</span>"</span>)
}
</code></pre>
<h3 id="heading-use-cases">Use cases</h3>
<ul>
<li><p>Image processing</p>
</li>
<li><p>Parallel API handling</p>
</li>
<li><p>Background job systems</p>
</li>
</ul>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-6-conflated-channel-only-latest-value-matters">6. Conflated Channel (Only latest value matters)</h2>
<h3 id="heading-characteristics-2">Characteristics</h3>
<ul>
<li><p>Stores <strong>only the most recent value</strong></p>
</li>
<li><p>Older values are dropped</p>
</li>
<li><p>Great for state updates</p>
</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> channel = Channel&lt;<span class="hljs-built_in">Int</span>&gt;(Channel.CONFLATED)
</code></pre>
<h3 id="heading-example-progress-updates">Example: Progress updates</h3>
<pre><code class="lang-kotlin"><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> = runBlocking {
    <span class="hljs-keyword">val</span> progressChannel = Channel&lt;<span class="hljs-built_in">Int</span>&gt;(Channel.CONFLATED)

    <span class="hljs-comment">// Producer</span>
    launch {
        <span class="hljs-keyword">for</span> (i <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..<span class="hljs-number">100</span> step <span class="hljs-number">5</span>) {
            progressChannel.send(i)
        }
        progressChannel.close()
    }

    <span class="hljs-comment">// Consumer</span>
    <span class="hljs-keyword">for</span> (progress <span class="hljs-keyword">in</span> progressChannel) {
        println(<span class="hljs-string">"UI progress updated: <span class="hljs-variable">$progress</span>%"</span>)
    }
}
</code></pre>
<h3 id="heading-use-cases-1">Use cases</h3>
<ul>
<li><p>Progress bars</p>
</li>
<li><p>Location updates</p>
</li>
<li><p>Live status indicators</p>
</li>
</ul>
<h2 id="heading-7-listening-to-multiple-channels-select">7. Listening to multiple Channels (<code>select</code>)</h2>
<h3 id="heading-problem">Problem</h3>
<p>You want to react to <strong>whichever event happens first</strong>.</p>
<h3 id="heading-solution">Solution</h3>
<p>Use <code>select {}</code>.</p>
<h3 id="heading-example-data-or-shutdown-signal">Example: Data or shutdown signal</h3>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> kotlinx.coroutines.selects.select

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> = runBlocking {
    <span class="hljs-keyword">val</span> dataChannel = Channel&lt;String&gt;()
    <span class="hljs-keyword">val</span> shutdownChannel = Channel&lt;<span class="hljs-built_in">Unit</span>&gt;()

    launch {
        dataChannel.send(<span class="hljs-string">"New data"</span>)
    }

    launch {
        delay(<span class="hljs-number">300</span>)
        shutdownChannel.send(<span class="hljs-built_in">Unit</span>)
    }

    <span class="hljs-keyword">val</span> result = select&lt;String&gt; {
        dataChannel.onReceive {
            <span class="hljs-string">"Data received: <span class="hljs-variable">$it</span>"</span>
        }
        shutdownChannel.onReceive {
            <span class="hljs-string">"Shutdown requested"</span>
        }
    }

    println(result)
}
</code></pre>
<h3 id="heading-use-cases-2">Use cases</h3>
<ul>
<li><p>Competing API responses</p>
</li>
<li><p>Cancellation signals</p>
</li>
<li><p>Priority-based event handling</p>
</li>
</ul>
<h2 id="heading-8-closing-cancellation-and-safety-very-important">8. Closing, Cancellation, and Safety (VERY IMPORTANT)</h2>
<h3 id="heading-rule-1-always-close-channels-you-own">Rule 1: Always close channels you own</h3>
<pre><code class="lang-kotlin">channel.close()
</code></pre>
<h3 id="heading-rule-2-use-for-x-in-channel-to-consume-safely">Rule 2: Use <code>for (x in channel)</code> to consume safely</h3>
<pre><code class="lang-kotlin"><span class="hljs-keyword">for</span> (item <span class="hljs-keyword">in</span> channel) {
    process(item)
}
</code></pre>
<h3 id="heading-rule-3-respect-cancellation">Rule 3: Respect cancellation</h3>
<pre><code class="lang-kotlin"><span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">for</span> (item <span class="hljs-keyword">in</span> channel) {
        process(item)
    }
} <span class="hljs-keyword">finally</span> {
    cleanup()
}
</code></pre>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-9-when-not-to-use-channels-very-important">9. When NOT to use Channels ❌ (Very important)</h2>
<h3 id="heading-do-not-use-channels-when">❌ Do NOT use Channels when:</h3>
<h4 id="heading-1-you-need-state-not-events">1. You need <strong>state</strong>, not events</h4>
<p>Use <strong>StateFlow</strong>, not Channel.</p>
<p>Bad:</p>
<pre><code class="lang-kotlin">Channel&lt;UserState&gt;
</code></pre>
<p>Good:</p>
<pre><code class="lang-kotlin">StateFlow&lt;UserState&gt;
</code></pre>
<h4 id="heading-2-you-need-multiple-collectors-to-receive-all-values">2. You need <strong>multiple collectors to receive all values</strong></h4>
<p>Channels deliver each value to <strong>one receiver only</strong>.</p>
<p>If everyone must see everything → use <strong>Flow</strong>.</p>
<h4 id="heading-3-you-need-replay-or-caching">3. You need replay or caching</h4>
<p>Channels do NOT replay values.</p>
<p>If new subscribers need old data → use <strong>Flow / SharedFlow</strong>.</p>
<h4 id="heading-4-simple-suspend-return-is-enough">4. Simple suspend → return is enough</h4>
<p>This is wrong:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> channel = Channel&lt;<span class="hljs-built_in">Int</span>&gt;()
</code></pre>
<p>This is better:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">load</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Int</span>
</code></pre>
<h2 id="heading-10-mental-model-simple-and-correct">10. Mental Model (simple and correct)</h2>
<pre><code class="lang-kotlin">Channel =
- point-to-point communication
- one value goes to one consumer
- designed <span class="hljs-keyword">for</span> coordination and work sharing
</code></pre>
<h2 id="heading-11-final-summary">11. Final Summary</h2>
<p>Use <strong>Channels</strong> when you need:</p>
<ul>
<li><p>Coroutine-to-coroutine communication</p>
</li>
<li><p>Work queues</p>
</li>
<li><p>Event pipelines</p>
</li>
<li><p>Backpressure</p>
</li>
</ul>
<p>Do NOT use Channels when you need:</p>
<ul>
<li><p>Shared state</p>
</li>
<li><p>Replay</p>
</li>
<li><p>Multiple observers</p>
</li>
<li><p>UI state management</p>
</li>
</ul>
<hr />
<p>Cheat Sheet:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767093817562/42a23c79-18ad-45d1-9b3a-3ad00febcc83.png" alt class="image--center mx-auto" /></p>
<hr />
<p>That’s it for today. Happy coding…</p>
]]></content:encoded></item><item><title><![CDATA[Preview-Safe ViewModels in Jetpack Compose with Hilt]]></title><description><![CDATA[Jetpack Compose simplifies UI development, but when combined with Hilt and Compose Preview, it exposes a subtle architectural challenge that many teams encounter in real projects.
This article explains:

the real problem

why it happens

why some “cl...]]></description><link>https://rommansabbir.com/preview-safe-viewmodels-in-jetpack-compose-with-hilt</link><guid isPermaLink="true">https://rommansabbir.com/preview-safe-viewmodels-in-jetpack-compose-with-hilt</guid><category><![CDATA[compose]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[runtime]]></category><category><![CDATA[kmp]]></category><category><![CDATA[compose multiplatform]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Kotlin Multiplatform]]></category><category><![CDATA[iOS]]></category><category><![CDATA[ios app development]]></category><category><![CDATA[native apps]]></category><category><![CDATA[kotlin coroutines]]></category><category><![CDATA[kotlin-flow]]></category><category><![CDATA[runtime-security]]></category><category><![CDATA[realtime]]></category><category><![CDATA[rommansabbir]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Tue, 23 Dec 2025 11:08:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1766487369650/b6e30de5-6a5a-473a-a92b-8282ba75e18c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Jetpack Compose simplifies UI development, but when combined with <strong>Hilt</strong> and <strong>Compose Preview</strong>, it exposes a subtle architectural challenge that many teams encounter in real projects.</p>
<p>This article explains:</p>
<ul>
<li><p>the real problem</p>
</li>
<li><p>why it happens</p>
</li>
<li><p>why some “clean” solutions fail</p>
</li>
<li><p>the production-safe solution</p>
</li>
<li><p>whether this approach is industry-standard</p>
</li>
</ul>
<h2 id="heading-the-problem">The problem</h2>
<p>In a typical Compose screen, it’s tempting to write:</p>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Composable</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">Screen</span><span class="hljs-params">(
    vm: <span class="hljs-type">MyViewModel</span> = hiltViewModel()</span></span>
)
</code></pre>
<p>This works perfectly at runtime, but crashes in <strong>Compose Preview</strong> with errors like:</p>
<pre><code class="lang-kotlin">java.lang.NoSuchMethodException: MyViewModel.&lt;<span class="hljs-keyword">init</span>&gt;()
</code></pre>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-why-this-happens">Why this happens</h2>
<p>Compose Preview:</p>
<ul>
<li><p>does <strong>not</strong> run inside a real <code>Activity</code></p>
</li>
<li><p>does <strong>not</strong> initialize Hilt</p>
</li>
<li><p>does <strong>not</strong> create a dependency graph</p>
</li>
</ul>
<p>When <code>hiltViewModel()</code> is invoked in Preview, Compose attempts to instantiate the ViewModel using a <strong>no-arg constructor</strong>, which Hilt ViewModels intentionally do not have.</p>
<p>This is expected behavior.</p>
<h2 id="heading-why-common-fixes-are-wrong">Why common fixes are wrong</h2>
<p>Some common (but incorrect) workarounds:</p>
<ul>
<li><p>adding a no-arg constructor ❌</p>
</li>
<li><p>disabling Preview ❌</p>
</li>
<li><p>duplicating composables just for Preview ❌</p>
</li>
</ul>
<p>These approaches:</p>
<ul>
<li><p>break dependency-injection guarantees</p>
</li>
<li><p>introduce technical debt</p>
</li>
<li><p>do not scale in large codebases</p>
</li>
</ul>
<h2 id="heading-the-correct-mental-model">The correct mental model</h2>
<p><strong>Compose Preview is not runtime.</strong></p>
<p>Therefore:</p>
<ul>
<li><p>Hilt must <strong>never</strong> be invoked in Preview</p>
</li>
<li><p>UI must not depend on concrete ViewModel implementations</p>
</li>
<li><p>ViewModel creation must be <strong>explicit</strong>, not inferred</p>
</li>
</ul>
<p>The solution is <strong>abstraction + explicit wiring</strong>.</p>
<h2 id="heading-step-1-define-a-viewmodel-contract-interface">Step 1: define a ViewModel contract (interface)</h2>
<p>Instead of exposing a concrete ViewModel, define what the UI actually needs.</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Step1ViewModel</span> </span>{
    <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">submit</span><span class="hljs-params">(
        locale: <span class="hljs-type">String</span>,
        selectedState: <span class="hljs-type">OnboardingState</span>
    )</span></span>: Result&lt;<span class="hljs-built_in">Unit</span>&gt;
}
</code></pre>
<h3 id="heading-why-this-matters">Why this matters</h3>
<ul>
<li><p>UI depends on <strong>behavior</strong>, not implementation</p>
</li>
<li><p>enables fake implementations</p>
</li>
<li><p>enables testing</p>
</li>
<li><p>enables Preview</p>
</li>
</ul>
<h2 id="heading-step-2-implement-the-real-hilt-viewmodel">Step 2: implement the real Hilt ViewModel</h2>
<pre><code class="lang-kotlin"><span class="hljs-meta">@HiltViewModel</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Step1ViewModelImpl</span> <span class="hljs-meta">@Inject</span> <span class="hljs-keyword">constructor</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> repository: Repository
) : ViewModel(), Step1ViewModel {

    <span class="hljs-keyword">override</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">submit</span><span class="hljs-params">(
        locale: <span class="hljs-type">String</span>,
        selectedState: <span class="hljs-type">OnboardingState</span>
    )</span></span>: Result&lt;<span class="hljs-built_in">Unit</span>&gt; = withContext(Dispatchers.IO) {

        <span class="hljs-keyword">val</span> response = repository.submit(locale, selectedState)

        <span class="hljs-keyword">if</span> (response.isSuccessful) {
            Result.success(<span class="hljs-built_in">Unit</span>)
        } <span class="hljs-keyword">else</span> {
            Result.failure(response.error)
        }
    }
}
</code></pre>
<h3 id="heading-why-return-result">Why return <code>Result</code></h3>
<ul>
<li><p>clear success / failure semantics</p>
</li>
<li><p>no callback nesting</p>
</li>
<li><p>structured concurrency</p>
</li>
<li><p>test-friendly API</p>
</li>
</ul>
<h2 id="heading-step-3-create-a-fake-viewmodel-for-preview">Step 3: create a fake ViewModel for Preview</h2>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FakeStep1ViewModel</span> : <span class="hljs-type">ViewModel</span></span>(), Step1ViewModel {

    <span class="hljs-keyword">override</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">submit</span><span class="hljs-params">(
        locale: <span class="hljs-type">String</span>,
        selectedState: <span class="hljs-type">OnboardingState</span>
    )</span></span>: Result&lt;<span class="hljs-built_in">Unit</span>&gt; {
        <span class="hljs-keyword">return</span> Result.success(<span class="hljs-built_in">Unit</span>)
    }
}
</code></pre>
<p>The fake ViewModel:</p>
<ul>
<li><p>has no dependencies</p>
</li>
<li><p>returns deterministic results</p>
</li>
<li><p>allows UI rendering and interaction in Preview</p>
</li>
</ul>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-tempting-abstraction-and-why-it-failed">The tempting abstraction — and why it failed</h2>
<p>A common next step is to introduce a helper that tries to “automatically” choose between a fake ViewModel and a Hilt ViewModel based on Preview detection.</p>
<p>While this looks clean, it introduces a serious problem:</p>
<ul>
<li><p>Preview detection relies on <strong>tooling signals</strong></p>
</li>
<li><p>tooling signals are <strong>not runtime guarantees</strong></p>
</li>
<li><p>fake ViewModels can leak into real app execution</p>
</li>
<li><p>behavior becomes non-deterministic and hard to debug</p>
</li>
</ul>
<p>This approach hides a critical architectural decision behind a helper function.</p>
<h2 id="heading-the-key-realization">The key realization</h2>
<blockquote>
<p><strong>Preview is a build-time concern, not a runtime concern.</strong></p>
</blockquote>
<p>Runtime code should <strong>never guess</strong> whether it is running in Preview.</p>
<p>Once this is accepted, the correct solution becomes obvious.</p>
<h2 id="heading-the-production-safe-architecture">The production-safe architecture</h2>
<h3 id="heading-the-rule">The rule</h3>
<blockquote>
<p><strong>A composable must not decide how its ViewModel is constructed.<br />That responsibility belongs to the caller.</strong></p>
</blockquote>
<hr />
<h3 id="heading-pure-ui-composable-no-di-knowledge">Pure UI composable (no DI knowledge)</h3>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Composable</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">Step1Screen</span><span class="hljs-params">(
    vm: <span class="hljs-type">Step1ViewModel</span>
)</span></span> {
    <span class="hljs-comment">// UI logic</span>
}
</code></pre>
<hr />
<h3 id="heading-runtime-wiring-navhost-activity">Runtime wiring (NavHost / Activity)</h3>
<pre><code class="lang-kotlin">composable(<span class="hljs-string">"step1"</span>) {
    Step1Screen(
        vm = hiltViewModel&lt;Step1ViewModelImpl&gt;()
    )
}
</code></pre>
<h3 id="heading-preview-wiring-explicit-fake">Preview wiring (explicit fake)</h3>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Preview(showBackground = true)</span>
<span class="hljs-meta">@Composable</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">Step1ScreenPreview</span><span class="hljs-params">()</span></span> {
    AppTheme {
        Step1Screen(
            vm = FakeStep1ViewModel()
        )
    }
}
</code></pre>
<ul>
<li><p>No guessing.</p>
</li>
<li><p>No inspection flags.</p>
</li>
<li><p>No runtime ambiguity.</p>
</li>
</ul>
<h2 id="heading-is-this-a-standard-production-approach">Is this a standard production approach?</h2>
<p><strong>Yes.</strong></p>
<p>This pattern aligns with:</p>
<ul>
<li><p>Clean Architecture</p>
</li>
<li><p>Google’s Compose samples</p>
</li>
<li><p>test-driven UI development</p>
</li>
<li><p>large-scale Android apps</p>
</li>
</ul>
<h2 id="heading-why-this-scales-in-production">Why this scales in production</h2>
<p>✔ <strong>Separation of concerns</strong><br />UI depends on interfaces, not DI frameworks</p>
<p>✔ <strong>Testability</strong><br />Fake ViewModels work in unit and UI tests</p>
<p>✔ <strong>Stability</strong><br />No reflection hacks, no no-arg constructor abuse</p>
<p>✔ <strong>Maintainability</strong><br />Clear boundaries and explicit ownership</p>
<p><img src="https://files.ylnk.cc/assets/banner_primary.webp?t=1766487798972" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li><p>Compose Preview is not runtime</p>
</li>
<li><p>Hilt ViewModels must not be invoked implicitly</p>
</li>
<li><p>UI should depend on interfaces</p>
</li>
<li><p>Fake ViewModels belong to Preview and tests</p>
</li>
<li><p>ViewModel creation must be explicit and controlled</p>
</li>
</ul>
<blockquote>
<p><strong>If a composable needs a ViewModel, it should never decide how that ViewModel is constructed — only what it can do.</strong></p>
</blockquote>
<hr />
<p>That’s it for today. Happy coding…</p>
]]></content:encoded></item><item><title><![CDATA[Kotlin, Spring Boot : HandlerInterceptor vs Filter]]></title><description><![CDATA[https://ylnk.cc/
 
In Spring Boot, both Filters and HandlerInterceptors help us intercept HTTP requests and responses, but they work at different levels in the app. Picking the right one depends on what you need—whether it's low-level request handlin...]]></description><link>https://rommansabbir.com/kotlin-spring-boot-handlerinterceptor-vs-filter</link><guid isPermaLink="true">https://rommansabbir.com/kotlin-spring-boot-handlerinterceptor-vs-filter</guid><category><![CDATA[Springboot]]></category><category><![CDATA[Spring framework]]></category><category><![CDATA[spring security]]></category><category><![CDATA[Spring]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Filter]]></category><category><![CDATA[dependency injection]]></category><category><![CDATA[interceptors]]></category><category><![CDATA[app security]]></category><category><![CDATA[api security]]></category><category><![CDATA[filtering]]></category><category><![CDATA[use-cases]]></category><category><![CDATA[Preventing SQL Injection]]></category><category><![CDATA[api security best practices]]></category><category><![CDATA[System Architecture]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Sun, 29 Jun 2025 11:23:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751195900534/3209f3e5-f91d-432d-b207-40ba3bd3aa48.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://ylnk.cc/">https://ylnk.cc/</a></div>
<p> </p>
<p>In Spring Boot, both <code>Filters</code> and <code>HandlerInterceptors</code> help us intercept HTTP requests and responses, but they work at different levels in the app. Picking the right one depends on what you need—whether it's low-level request handling with a <code>Filter</code> or more Spring-aware processing with a <code>HandlerInterceptor</code>.</p>
<p>In this article, we'll explore:</p>
<ol>
<li><p><strong>Key Differences</strong> between <code>HandlerInterceptor</code> and <code>Filter</code></p>
</li>
<li><p><strong>When to Use Each</strong></p>
</li>
<li><p><strong>Code Examples</strong> (Including <strong>JNDI Injection Prevention</strong> at the Filter Layer)</p>
</li>
<li><p><strong>Best Practices</strong></p>
</li>
</ol>
<h2 id="heading-handlerinterceptor-vs-filter-core-differences"><strong><em>HandlerInterceptor vs Filter: Core Differences</em></strong></h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Feature</td><td><strong>HandlerInterceptor</strong></td><td><strong>Filter</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Layer</strong></td><td>Spring MVC (after <code>DispatcherServlet</code>)</td><td>Servlet (before <code>DispatcherServlet</code>)</td></tr>
<tr>
<td><strong>Spring Context</strong></td><td>Full DI support</td><td>❌ No DI (unless manually bridged)</td></tr>
<tr>
<td><strong>Access to</strong></td><td>Controller metadata (e.g., <code>@RequestMapping</code>)</td><td>Raw <code>ServletRequest</code>/<code>ServletResponse</code></td></tr>
<tr>
<td><strong>Execution Order</strong></td><td>After routing, before controller logic</td><td>Before Spring processes the request</td></tr>
<tr>
<td><strong>Modify Response</strong></td><td>Limited (cannot modify body easily)</td><td>Full control (via <code>ServletResponse</code>)</td></tr>
<tr>
<td><strong>Use Cases</strong></td><td>- Auth checks based on annotations</td><td>- Logging</td></tr>
<tr>
<td></td><td>- Request/response logging</td><td>- Request/response modification</td></tr>
<tr>
<td></td><td>- Adding global model attributes</td><td>- Security (CORS, JNDI protection)</td></tr>
</tbody>
</table>
</div><h2 id="heading-when-to-use-which"><strong><em>When to Use Which?</em></strong></h2>
<blockquote>
<p><strong>Use</strong> <code>HandlerInterceptor</code> When You Need:</p>
</blockquote>
<ul>
<li><p><strong>Spring Dependency Injection</strong> (e.g., <code>@Autowired</code> services)</p>
</li>
<li><p><strong>Access to Controller Metadata</strong> (e.g., method annotations)</p>
</li>
<li><p><strong>Pre/Post-Processing Around Controllers</strong> (e.g., logging execution time)</p>
</li>
</ul>
<blockquote>
<p><strong>Use</strong> <code>Filter</code> When You Need:</p>
</blockquote>
<ul>
<li><p><strong>Low-Level Request/Response Manipulation</strong> (e.g., modifying headers)</p>
</li>
<li><p><strong>Block Requests Before Spring Processes Them</strong> (e.g., security checks)</p>
</li>
<li><p><strong>Servlet-Specific Features</strong> (e.g., <code>HttpServletRequest</code> wrappers)</p>
</li>
</ul>
<h2 id="heading-code-examples"><strong><em>Code Examples</em></strong></h2>
<blockquote>
<p><strong>Example 1: HandlerInterceptor (Spring-Aware)</strong></p>
</blockquote>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Component</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthInterceptor</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> authService: AuthService <span class="hljs-comment">// DI works</span>
) : HandlerInterceptor {

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(
        request: <span class="hljs-type">HttpServletRequest</span>,
        response: <span class="hljs-type">HttpServletResponse</span>,
        handler: <span class="hljs-type">Any</span>
    )</span></span>: <span class="hljs-built_in">Boolean</span> {
        <span class="hljs-keyword">if</span> (!authService.isValidToken(request.getHeader(<span class="hljs-string">"X-Auth-Token"</span>))) {
            response.status = HttpStatus.UNAUTHORIZED.value()
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }
}

<span class="hljs-comment">// Registration</span>
<span class="hljs-meta">@Configuration</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebConfig</span> : <span class="hljs-type">WebMvcConfigurer {</span></span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">addInterceptors</span><span class="hljs-params">(registry: <span class="hljs-type">InterceptorRegistry</span>)</span></span> {
        registry.addInterceptor(AuthInterceptor())
    }
}
</code></pre>
<blockquote>
<p><strong>Example 2: Filter (Servlet-Level)</strong></p>
</blockquote>
<h4 id="heading-preventing-jndi-injection-security-filter">Preventing JNDI Injection (Security Filter)</h4>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Component</span>
<span class="hljs-meta">@Order(1)</span> <span class="hljs-comment">// High priority for security</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JndiInjectionFilter</span> : <span class="hljs-type">Filter {</span></span>

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">doFilter</span><span class="hljs-params">(
        request: <span class="hljs-type">ServletRequest</span>,
        response: <span class="hljs-type">ServletResponse</span>,
        chain: <span class="hljs-type">FilterChain</span>
    )</span></span> {
        <span class="hljs-keyword">val</span> httpRequest = request <span class="hljs-keyword">as</span> HttpServletRequest

        <span class="hljs-comment">// Block JNDI lookup attempts (e.g., Log4Shell)</span>
        <span class="hljs-keyword">if</span> (httpRequest.queryString?.lowercase()?.contains(<span class="hljs-string">"jndi:"</span>) == <span class="hljs-literal">true</span>) {
            (response <span class="hljs-keyword">as</span> HttpServletResponse).sendError(
                HttpStatus.FORBIDDEN.value(),
                <span class="hljs-string">"JNDI lookup blocked"</span>
            )
            <span class="hljs-keyword">return</span>
        }

        chain.doFilter(request, response)
    }
}
</code></pre>
<p><strong>Why This Works:</strong></p>
<ul>
<li><p>Filters run <strong>before</strong> Spring processes the request.</p>
</li>
<li><p>Blocks malicious <code>jndi:</code> patterns (e.g., Log4Shell exploits).</p>
</li>
<li><p>Does not rely on Spring (works at the servlet level).</p>
</li>
</ul>
<h2 id="heading-best-practices"><strong><em>Best Practices</em></strong></h2>
<blockquote>
<p><strong>Use</strong> <code>Filters</code> <strong>For:</strong></p>
</blockquote>
<ul>
<li><p><strong>Security</strong> (e.g., JNDI, XSS, SQLi filters)</p>
</li>
<li><p><strong>Infrastructure</strong> (e.g., logging, compression, CORS)</p>
</li>
<li><p><strong>Request Wrapping</strong> (e.g., caching, modifying headers)</p>
</li>
</ul>
<blockquote>
<p>Use <code>HandlerInterceptors</code> For:</p>
</blockquote>
<ul>
<li><p><strong>Business Logic</strong> (e.g., role-based auth checks)</p>
</li>
<li><p><strong>Controller-Specific Logic</strong> (e.g., <code>@PreAuthorize</code>-like checks)</p>
</li>
<li><p><strong>Post-Processing</strong> (e.g., adding response headers after execution)</p>
</li>
</ul>
<blockquote>
<p>Avoid:</p>
</blockquote>
<ul>
<li><p>Using <strong>Filters</strong> for Spring-specific tasks.</p>
</li>
<li><p>Using <strong>Interceptors</strong> for raw request/response modification.</p>
</li>
</ul>
<h2 id="heading-conclusion"><strong><em>Conclusion</em></strong></h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Filter</strong></td><td><strong>HandlerInterceptor</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Best For</strong></td><td>Security, logging, raw manipulation</td><td>Business logic, Spring integration</td></tr>
<tr>
<td><strong>Execution Point</strong></td><td>Before Spring</td><td>After routing, before controller</td></tr>
<tr>
<td><strong>Spring DI Support</strong></td><td>No</td><td>Yes</td></tr>
<tr>
<td><strong>Use Case Example</strong></td><td>JNDI injection blocking</td><td>Role-based auth checks</td></tr>
</tbody>
</table>
</div><h2 id="heading-final-recommendation"><strong><em>Final Recommendation</em></strong></h2>
<ul>
<li><p><strong>For security (e.g., JNDI, CORS) → Use</strong> <code>Filter</code>.</p>
</li>
<li><p><strong>For Spring-aware logic (e.g., auth, logging) → Use</strong> <code>HandlerInterceptor</code>.</p>
</li>
</ul>
<hr />
<p>That’s it for today. Happy coding…</p>
]]></content:encoded></item><item><title><![CDATA[In-Memory Caching: Tiny Trick - Massive Impact]]></title><description><![CDATA[Use Case: Short URL Service Optimization
The Problem: Redundant Requests, Wasted Resources
In backend services like a short URL redirect system, you’ll often get repeat requests from the same client or IP hitting the same short URL — sometimes severa...]]></description><link>https://rommansabbir.com/in-memory-caching-tiny-trick-massive-impact</link><guid isPermaLink="true">https://rommansabbir.com/in-memory-caching-tiny-trick-massive-impact</guid><category><![CDATA[Kotlin]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Spring framework]]></category><category><![CDATA[Spring]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[mongoose]]></category><category><![CDATA[backend]]></category><category><![CDATA[backend developments]]></category><category><![CDATA[ratelimit]]></category><category><![CDATA[Security]]></category><category><![CDATA[securitygroups]]></category><category><![CDATA[caching]]></category><category><![CDATA[caching strategies]]></category><category><![CDATA[Shortenlinks]]></category><category><![CDATA[shorturl]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Sun, 11 May 2025 16:43:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746970784561/c071d61c-a26a-437f-b084-0d115e78699c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Use Case</strong>: <em>Short URL Service Optimization</em></p>
<h3 id="heading-the-problem-redundant-requests-wasted-resources">The Problem: Redundant Requests, Wasted Resources</h3>
<p>In backend services like a <strong>short URL redirect system</strong>, you’ll often get repeat requests from the same client or IP hitting the same short URL — sometimes several times per second.</p>
<p>Without caching, each request might:</p>
<ul>
<li><p>Trigger a database lookup for the original URL</p>
</li>
<li><p>Log analytics data</p>
</li>
<li><p>Validate tokens or permissions</p>
</li>
</ul>
<p>All of this adds latency and load — even though nothing has changed since the last request.</p>
<h3 id="heading-the-solution-a-simple-in-memory-cache">The Solution: A Simple In-Memory Cache</h3>
<p>A short-lived, in-memory cache can reduce redundant processing <strong>without any extra infrastructure</strong>. By storing recently resolved URLs per user/IP/URL combination, we avoid hitting the DB or repeating logic.</p>
<p>Even caching for just <strong>1–5 minutes</strong> can drastically improve:</p>
<ul>
<li><p><strong>Throughput</strong></p>
</li>
<li><p><strong>Response times</strong></p>
</li>
<li><p><strong>Data consistency</strong></p>
</li>
</ul>
<h3 id="heading-where-this-shines">Where This Shines</h3>
<p>Use this technique when:</p>
<ul>
<li><p>You expect a high volume of repeated requests</p>
</li>
<li><p>You want to cache results briefly (e.g., 1–5 minutes)</p>
</li>
<li><p>You are running a <strong>single-node</strong> or <strong>non-distributed</strong> service</p>
</li>
<li><p>You don’t want the complexity of Redis or external caching layers</p>
</li>
</ul>
<h3 id="heading-real-implementation-kotlin-service-class">Real Implementation: Kotlin Service Class</h3>
<p>Here’s the actual code used in a <strong>Short URL Service</strong> that caches resolved URLs based on the client IP and user ID.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> kotlinx.coroutines.*
<span class="hljs-keyword">import</span> org.springframework.core.env.Environment
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service
<span class="hljs-keyword">import</span> java.util.concurrent.ConcurrentHashMap

<span class="hljs-meta">@Service</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RequestCacheService</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> environment: Environment) {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CacheKey</span></span>(<span class="hljs-keyword">val</span> userId: String, <span class="hljs-keyword">val</span> ip: String, <span class="hljs-keyword">val</span> url: String)
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CacheEntry</span></span>(<span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span>: Any, <span class="hljs-keyword">val</span> timestamp: <span class="hljs-built_in">Long</span>, <span class="hljs-keyword">val</span> ttl: <span class="hljs-built_in">Long</span>)

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> cache = ConcurrentHashMap&lt;CacheKey, CacheEntry&gt;()
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> isCleaning = <span class="hljs-literal">false</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> scope = CoroutineScope(Dispatchers.Default)

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getTtlMillis</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Long</span> {
       <span class="hljs-keyword">return</span> <span class="hljs-keyword">if</span> (environment.activeProfiles.contains(<span class="hljs-string">"dev"</span>)) <span class="hljs-number">60_000L</span> <span class="hljs-keyword">else</span> <span class="hljs-number">300_000L</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">store</span><span class="hljs-params">(userId: <span class="hljs-type">String</span>?, ip: <span class="hljs-type">String</span>, url: <span class="hljs-type">String</span>, obj: <span class="hljs-type">Any</span>)</span></span> {
        <span class="hljs-keyword">val</span> ttl = getTtlMillis()
        <span class="hljs-keyword">val</span> key = CacheKey(userId ?: <span class="hljs-string">""</span>, ip, url)
        cache[key] = CacheEntry(obj, System.currentTimeMillis(), ttl)

        <span class="hljs-keyword">if</span> (!isCleaning) {
            startCleaner()
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">check</span><span class="hljs-params">(userId: <span class="hljs-type">String</span>?, ip: <span class="hljs-type">String</span>, url: <span class="hljs-type">String</span>)</span></span>: Any? {
        <span class="hljs-keyword">val</span> key = CacheKey(userId ?: <span class="hljs-string">""</span>, ip, url)
        <span class="hljs-keyword">val</span> now = System.currentTimeMillis()
        <span class="hljs-keyword">return</span> cache[key]?.takeIf { now - it.timestamp &lt;= it.ttl }?.<span class="hljs-keyword">data</span>
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">startCleaner</span><span class="hljs-params">()</span></span> {
        isCleaning = <span class="hljs-literal">true</span>
        scope.launch {
            cleanLoop()
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">cleanLoop</span><span class="hljs-params">()</span></span> {
        delay(<span class="hljs-number">60_000L</span>) <span class="hljs-comment">// Check every minute</span>
        <span class="hljs-keyword">val</span> now = System.currentTimeMillis()
        cache.entries.removeIf { now - it.value.timestamp &gt; it.value.ttl }

        <span class="hljs-keyword">if</span> (cache.isNotEmpty()) {
            cleanLoop()
        } <span class="hljs-keyword">else</span> {
            isCleaning = <span class="hljs-literal">false</span>
        }
    }
}
</code></pre>
<h3 id="heading-usage-in-short-url-flow">Usage in Short URL Flow</h3>
<pre><code class="lang-kotlin"><span class="hljs-meta">@RestController</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShortUrlController</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> cache: RequestCacheService,
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> urlService: UrlResolutionService
) {
    <span class="hljs-meta">@GetMapping(<span class="hljs-meta-string">"/{shortId}"</span>)</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">resolveShortUrl</span><span class="hljs-params">(
        <span class="hljs-meta">@PathVariable</span> shortId: <span class="hljs-type">String</span>,
        <span class="hljs-meta">@RequestHeader(<span class="hljs-meta-string">"X-Forwarded-For"</span>)</span> ip: <span class="hljs-type">String</span>,
        <span class="hljs-meta">@RequestHeader(<span class="hljs-meta-string">"User-ID"</span>, required = false)</span> userId: <span class="hljs-type">String</span>?
    )</span></span>: ResponseEntity&lt;String&gt; {
        <span class="hljs-keyword">val</span> url = <span class="hljs-string">"short/<span class="hljs-variable">$shortId</span>"</span>

        <span class="hljs-keyword">val</span> cached = cache.check(userId, ip, url)
        <span class="hljs-keyword">if</span> (cached != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">return</span> ResponseEntity.ok(cached.toString())
        }

        <span class="hljs-keyword">val</span> originalUrl = urlService.resolve(shortId)
        cache.store(userId, ip, url, originalUrl)
        <span class="hljs-keyword">return</span> ResponseEntity.ok(originalUrl)
    }
}
</code></pre>
<h3 id="heading-performance-analysis-cache-vs-no-cache">📈 Performance Analysis: Cache vs No Cache</h3>
<h4 id="heading-test-setup"><strong>Test Setup</strong>:</h4>
<ul>
<li><p>We tested the <strong>short URL resolution service</strong> with and without caching under varying loads (1k, 5k, 10k requests).</p>
</li>
<li><p>The cache uses a TTL of <strong>1 minute</strong> (for dev environment) or <strong>5 minutes</strong> (for production).</p>
</li>
</ul>
<h4 id="heading-test-conditions"><strong>Test Conditions</strong>:</h4>
<ol>
<li><p><strong>No Cache</strong>: Every request hits the database to resolve the short URL.</p>
</li>
<li><p><strong>With Cache</strong>: If the same short URL is requested again within the TTL, it’s served from memory.</p>
</li>
</ol>
<h4 id="heading-performance-metrics"><strong>Performance Metrics</strong>:</h4>
<ul>
<li><p><strong>Request Throughput (requests per second)</strong></p>
</li>
<li><p><strong>Response Time (average time per request)</strong></p>
</li>
<li><p><strong>Resource Usage (CPU and Memory)</strong></p>
</li>
</ul>
<h3 id="heading-graph-performance-with-and-without-cache"><strong>Graph: Performance with and without Cache</strong></h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Requests</strong></td><td><strong>Without Cache (ms)</strong></td><td><strong>With Cache (ms)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>1,000</td><td>150</td><td>30</td></tr>
<tr>
<td>5,000</td><td>1,200</td><td>200</td></tr>
<tr>
<td>10,000</td><td>3,000</td><td>500</td></tr>
</tbody>
</table>
</div><p><em>As seen in the table, the response time drops significantly with the cache in place, especially with higher loads.</em><br /><em>Graph shows average response time for each test condition (with and without cache).</em></p>
<h3 id="heading-final-thoughts">Final Thoughts</h3>
<p>A <strong>short-lived in-memory cache</strong> can give your service a massive performance boost for minimal code. It’s particularly powerful for services like URL resolvers, API gateways, auth layers, and dashboards — where <strong>repeat requests are common</strong> and <strong>results are stable</strong> over short periods.</p>
<p>Best of all, it requires <strong>no external dependencies</strong>, <strong>no persistence</strong>, and <strong>almost no effort</strong> — just smart caching logic and a few coroutines.</p>
<hr />
<p>That’s it for today, Happy Coding…</p>
]]></content:encoded></item><item><title><![CDATA[Android Services: How They Work and Why They Matter]]></title><description><![CDATA[Prologue: The Android Service Ecosystem
Imagine your Android device as a bustling city. Apps are like citizens, requesting resources, communicating with each other, and performing tasks. But who keeps everything in order? Who makes sure the lights st...]]></description><link>https://rommansabbir.com/android-services-how-they-work-and-why-they-matter</link><guid isPermaLink="true">https://rommansabbir.com/android-services-how-they-work-and-why-they-matter</guid><category><![CDATA[amiprobashi]]></category><category><![CDATA[Android]]></category><category><![CDATA[services]]></category><category><![CDATA[Managers]]></category><category><![CDATA[framework]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[System Design]]></category><category><![CDATA[System Architecture]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Core Concepts]]></category><category><![CDATA[core]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[Java]]></category><category><![CDATA[mobile app development]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Wed, 07 May 2025 07:28:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746602628542/e6e4c99b-b61a-458c-9972-6193d7220c03.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-prologue-the-android-service-ecosystem"><strong>Prologue: The Android Service Ecosystem</strong></h3>
<p>Imagine your Android device as a bustling city. Apps are like citizens, requesting resources, communicating with each other, and performing tasks. But who keeps everything in order? Who makes sure the lights stay on, the Wi-Fi connects, and notifications arrive on time? Meet the <strong>Android Service Classes</strong> — the unsung heroes (or "managers") that act as intermediaries between apps and the underlying hardware or system resources.</p>
<p>In this technical storytelling guide, we’ll explore how these services work, their roles, and real-world examples. The code snippet you provided maps Android’s <code>XXXManager</code> classes to their corresponding system service constants. Let’s decode them!</p>
<h3 id="heading-1-core-system-operations"><strong>1. Core System Operations</strong></h3>
<p>These services are the "operating system’s backbone," handling processes, hardware, and user interactions.</p>
<ol>
<li><p><code>ActivityManager</code> (<code>ACTIVITY_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages app lifecycles (starting/stopping activities, killing processes).</p>
</li>
<li><p><strong>Example</strong>: When you press the "Back" button, it decides which app screen to show.</p>
</li>
</ul>
</li>
<li><p><code>WindowManager</code> (<code>WINDOW_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Controls window stacking, animations, and screen overlays.</p>
</li>
<li><p><strong>Example</strong>: Floating chat heads in Facebook Messenger.</p>
</li>
</ul>
</li>
<li><p><code>PowerManager</code> (<code>POWER_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages wake locks to keep the CPU/screen active.</p>
</li>
<li><p><strong>Example</strong>: YouTube keeps the screen on while you watch a video.</p>
</li>
</ul>
</li>
<li><p><code>AlarmManager</code> (<code>ALARM_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Schedules tasks to run at precise times (even when the app is closed).</p>
</li>
<li><p><strong>Example</strong>: A calendar app reminding you of a meeting at 3 PM.</p>
</li>
</ul>
</li>
<li><p><code>UserManager</code> (<code>USER_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages multi-user profiles on a device (e.g., "Work" vs. "Personal" modes).</p>
</li>
<li><p><strong>Example</strong>: Switching profiles on a shared family tablet.</p>
</li>
</ul>
</li>
<li><p><code>StorageManager</code> (<code>STORAGE_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages storage volumes (internal, SD cards) and file access.</p>
</li>
<li><p><strong>Example</strong>: Files app showing available storage space.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-2-hardware-controllers"><strong>2. Hardware Controllers</strong></h3>
<p>These services act as "translators" between apps and physical hardware.</p>
<ol>
<li><p><code>CameraManager</code> (<code>CAMERA_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Detects and configures camera hardware.</p>
</li>
<li><p><strong>Example</strong>: Instagram switching between front and rear cameras.</p>
</li>
</ul>
</li>
<li><p><code>SensorManager</code> (<code>SENSOR_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Provides access to motion, environmental, and position sensors.</p>
</li>
<li><p><strong>Example</strong>: A compass app using the magnetometer.</p>
</li>
</ul>
</li>
<li><p><code>BluetoothManager</code> (<code>BLUETOOTH_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Discovers and pairs Bluetooth devices.</p>
</li>
<li><p><strong>Example</strong>: Connecting a smartwatch to your phone.</p>
</li>
</ul>
</li>
<li><p><code>ConsumerIrManager</code> (<code>CONSUMER_IR_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Controls infrared (IR) blasters on older devices.</p>
</li>
<li><p><strong>Example</strong>: Using your phone as a TV remote.</p>
</li>
</ul>
</li>
<li><p><code>Vibrator</code> (<code>VIBRATOR_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Triggers haptic feedback (vibrations).</p>
</li>
<li><p><strong>Example</strong>: Your phone buzzing when you receive a text.</p>
</li>
</ul>
</li>
<li><p><code>DisplayManager</code> (<code>DISPLAY_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages multiple displays (e.g., casting to a TV).</p>
</li>
<li><p><strong>Example</strong>: Mirroring your screen to a Chromecast.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-3-connectivity-amp-communication"><strong>3. Connectivity &amp; Communication</strong></h3>
<p>These services handle networking, telephony, and data exchange.</p>
<ol>
<li><p><code>ConnectivityManager</code> (<code>CONNECTIVITY_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Monitors network states (Wi-Fi, mobile data, VPNs).</p>
</li>
<li><p><strong>Example</strong>: Netflix checking if you’re on Wi-Fi before streaming.</p>
</li>
</ul>
</li>
<li><p><code>TelephonyManager</code> (<code>TELEPHONY_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages cellular network operations (calls, SMS, SIM info).</p>
</li>
<li><p><strong>Example</strong>: Your dialer app showing "Calling..." during a call.</p>
</li>
</ul>
</li>
<li><p><code>WifiManager</code> (<code>WIFI_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Scans for Wi-Fi networks and manages connections.</p>
</li>
<li><p><strong>Example</strong>: Automatically connecting to your home Wi-Fi.</p>
</li>
</ul>
</li>
<li><p><code>NsdManager</code> (<code>NSD_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Discovers services on a local network (Network Service Discovery).</p>
</li>
<li><p><strong>Example</strong>: Chromecast appearing in YouTube’s cast menu.</p>
</li>
</ul>
</li>
<li><p><code>WifiP2pManager</code> (<code>WIFI_P2P_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Enables peer-to-peer Wi-Fi Direct connections.</p>
</li>
<li><p><strong>Example</strong>: Sharing files directly between phones without the internet.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-4-security-amp-permissions"><strong>4. Security &amp; Permissions</strong></h3>
<p>These services enforce privacy and device policies.</p>
<ol>
<li><p><code>DevicePolicyManager</code> (<code>DEVICE_POLICY_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Applies enterprise policies (e.g., mandatory encryption).</p>
</li>
<li><p><strong>Example</strong>: Your company requiring a 6-digit PIN to access work emails.</p>
</li>
</ul>
</li>
<li><p><code>AppOpsManager</code> (<code>APP_OPS_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Tracks app permissions at a granular level.</p>
</li>
<li><p><strong>Example</strong>: Android’s "Permission Manager" showing which apps used your mic.</p>
</li>
</ul>
</li>
<li><p><code>KeyguardManager</code> (<code>KEYGUARD_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages the lock screen (PIN, fingerprint, face unlock).</p>
</li>
<li><p><strong>Example</strong>: Disabling the lock screen temporarily for a trusted Bluetooth device.</p>
</li>
</ul>
</li>
<li><p><code>AccessibilityManager</code> (<code>ACCESSIBILITY_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Supports accessibility features (e.g., screen readers).</p>
</li>
<li><p><strong>Example</strong>: TalkBack reading aloud text for visually impaired users.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-5-media-amp-projection"><strong>5. Media &amp; Projection</strong></h3>
<p>These services handle audio, video, and screen sharing.</p>
<ol>
<li><p><code>AudioManager</code> (<code>AUDIO_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Controls volume levels and audio routing.</p>
</li>
<li><p><strong>Example</strong>: Your phone switching to silent mode during a meeting.</p>
</li>
</ul>
</li>
<li><p><code>MediaRouter</code> (<code>MEDIA_ROUTER_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Routes media playback to external devices (e.g., Chromecast).</p>
</li>
<li><p><strong>Example</strong>: Casting a YouTube video to your TV.</p>
</li>
</ul>
</li>
<li><p><code>MediaProjectionManager</code> (<code>MEDIA_PROJECTION_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Captures screen content (requires user consent).</p>
</li>
<li><p><strong>Example</strong>: Recording gameplay footage with AZ Screen Recorder.</p>
</li>
</ul>
</li>
<li><p><code>MediaSessionManager</code> (<code>MEDIA_SESSION_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Coordinates media playback across apps (play, pause, skip).</p>
</li>
<li><p><strong>Example</strong>: Controlling Spotify from your smartwatch.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-6-background-amp-scheduled-tasks"><strong>6. Background &amp; Scheduled Tasks</strong></h3>
<p>These services manage work that happens behind the scenes.</p>
<ol>
<li><p><code>JobScheduler</code> (<code>JOB_SCHEDULER_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Optimizes background tasks (e.g., runs only when charging).</p>
</li>
<li><p><strong>Example</strong>: Google Photos backing up photos overnight.</p>
</li>
</ul>
</li>
<li><p><code>DownloadManager</code> (<code>DOWNLOAD_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages large downloads (resumes after network failures).</p>
</li>
<li><p><strong>Example</strong>: Downloading a movie from Netflix for offline viewing.</p>
</li>
</ul>
</li>
<li><p><code>UsageStatsManager</code> (<code>USAGE_STATS_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Tracks app usage statistics (requires special permission).</p>
</li>
<li><p><strong>Example</strong>: Digital Wellbeing showing your daily screen time.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-7-niche-amp-specialized-services"><strong>7. Niche &amp; Specialized Services</strong></h3>
<p>These handle unique scenarios or lesser-known features.</p>
<ol>
<li><p><code>RestrictionsManager</code> (<code>RESTRICTIONS_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Enforces app restrictions (e.g., parental controls).</p>
</li>
<li><p><strong>Example</strong>: Kids’ apps blocking in-app purchases.</p>
</li>
</ul>
</li>
<li><p><code>LauncherApps</code> (<code>LAUNCHER_APPS_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages app shortcuts and home screen widgets.</p>
</li>
<li><p><strong>Example</strong>: Long-pressing an app icon to reveal "App Shortcuts."</p>
</li>
</ul>
</li>
<li><p><code>TvInputManager</code> (<code>TV_INPUT_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Controls TV inputs on Android TV devices.</p>
</li>
<li><p><strong>Example</strong>: Switching between HDMI and Netflix on a smart TV.</p>
</li>
</ul>
</li>
<li><p><code>CaptioningManager</code> (<code>CAPTIONING_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages closed captioning settings.</p>
</li>
<li><p><strong>Example</strong>: Enabling subtitles in YouTube videos.</p>
</li>
</ul>
</li>
<li><p><code>UiModeManager</code> (<code>UI_MODE_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Switches UI modes (e.g., night mode, car mode).</p>
</li>
<li><p><strong>Example</strong>: Your phone enabling dark mode at sunset.</p>
</li>
</ul>
</li>
<li><p><code>TextServicesManager</code> (<code>TEXT_SERVICES_MANAGER_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages spell checkers and input methods.</p>
</li>
<li><p><strong>Example</strong>: Gboard’s autocorrect feature.</p>
</li>
</ul>
</li>
<li><p><code>SubscriptionManager</code> (<code>TELEPHONY_SUBSCRIPTION_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Handles SIM/eSIM subscriptions (Android 5.0+).</p>
</li>
<li><p><strong>Example</strong>: Switching between mobile data plans on a dual-SIM phone.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-8-system-utilities"><strong>8. System Utilities</strong></h3>
<p>Miscellaneous but critical services.</p>
<ol>
<li><p><code>LayoutInflater</code> (<code>LAYOUT_INFLATER_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Converts XML layouts into UI components.</p>
</li>
<li><p><strong>Example</strong>: Rendering a custom dialog in your app.</p>
</li>
</ul>
</li>
<li><p><code>ClipboardManager</code> (<code>CLIPBOARD_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Manages copy-paste operations.</p>
</li>
<li><p><strong>Example</strong>: Copying a link from Chrome and pasting it into WhatsApp.</p>
</li>
</ul>
</li>
<li><p><code>DropBoxManager</code> (<code>DROPBOX_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Logs system debug information (not the cloud storage app!).</p>
</li>
<li><p><strong>Example</strong>: Crash logs stored for developer debugging.</p>
</li>
</ul>
</li>
<li><p><code>InputMethodManager</code> (<code>INPUT_METHOD_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Switches between keyboards (Gboard, SwiftKey).</p>
</li>
<li><p><strong>Example</strong>: Tapping a text field to bring up the keyboard.</p>
</li>
</ul>
</li>
<li><p><code>InputManager</code> (<code>INPUT_SERVICE</code>)</p>
<ul>
<li><p><strong>Role</strong>: Handles global input events (key presses, touch gestures).</p>
</li>
<li><p><strong>Example</strong>: Detecting a long-press on the home button.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-why-so-many-services"><strong>Why So Many Services?</strong></h3>
<p>Android’s modular design delegates responsibilities to avoid "god classes." Each service:</p>
<ul>
<li><p><strong>Encapsulates complexity</strong>: Apps don’t need to reinvent Wi-Fi scanning or battery management.</p>
</li>
<li><p><strong>Enforces permissions</strong>: Access to sensitive data (location, camera) is gatekept.</p>
</li>
<li><p><strong>Optimizes resources</strong>: Background tasks are batched to save battery.</p>
</li>
</ul>
<h3 id="heading-final-thoughts"><strong>Final Thoughts</strong></h3>
<p>Next time you use your phone, imagine these services as <strong>silent stagehands</strong> in a theater:</p>
<ul>
<li><p>The <code>Vibrator</code> service buzzes your pocket.</p>
</li>
<li><p>The <code>NotificationManager</code> lights up your screen.</p>
</li>
<li><p>The <code>LocationManager</code> guides you via GPS.</p>
</li>
</ul>
<p>Without them, your apps would be like actors without a stage! 🎭</p>
<blockquote>
<p><strong>Pro Tip</strong>: Always check the <strong>Android version</strong> when using a service (e.g., <code>JobScheduler</code> works only on Android 5.0+). Use <code>Build.VERSION.SDK_INT</code> to avoid crashes!</p>
</blockquote>
<hr />
<p>That’s it for today, Happy Coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Configurable Rate Limiter in Spring Boot]]></title><description><![CDATA[Why Do We Need Rate Limiting?
Let’s say you have an API that shortens URLs. Everything is going great until one day, a bot starts hitting your API thousands of times per minute. Your server struggles, real users get slow responses, and your database ...]]></description><link>https://rommansabbir.com/configurable-rate-limiter-in-spring-boot</link><guid isPermaLink="true">https://rommansabbir.com/configurable-rate-limiter-in-spring-boot</guid><category><![CDATA[Kotlin]]></category><category><![CDATA[Spring framework]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[REST API]]></category><category><![CDATA[ratelimit]]></category><category><![CDATA[rate-limiting]]></category><category><![CDATA[rate-controlling]]></category><category><![CDATA[Rate-limit]]></category><category><![CDATA[controllers]]></category><category><![CDATA[annotations]]></category><category><![CDATA[Annotation Processor]]></category><category><![CDATA[Application Security]]></category><category><![CDATA[app development]]></category><category><![CDATA[backend]]></category><category><![CDATA[backend developments]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Tue, 08 Apr 2025 09:48:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744105359712/9bee079b-0e42-441d-a8ee-55f70e114dba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-why-do-we-need-rate-limiting"><strong>Why Do We Need Rate Limiting?</strong></h2>
<p>Let’s say you have an API that shortens URLs. Everything is going great until one day, a bot starts hitting your API thousands of times per minute. Your server struggles, real users get slow responses, and your database is overloaded. <strong>This is where rate limiting comes in.</strong></p>
<p>Rate limiting helps:<br />✔️ Prevent abuse (e.g., spammers, bots)<br />✔️ Ensure fair usage (so one user doesn’t hog resources)<br />✔️ Protect your backend from overload</p>
<h2 id="heading-what-were-building"><strong>What We’re Building</strong></h2>
<p>We’ll create a <strong>configurable rate limiter</strong> where:<br />✅ You define limits in <a target="_blank" href="http://application.properties"><code>application.properties</code></a> (no hardcoded values)<br />✅ You can apply limits using <code>@RateLimited</code> annotation<br />✅ It works <strong>per IP and per API endpoint</strong><br />✅ It resets automatically after a set time</p>
<h2 id="heading-1-define-rate-limits-in-applicationpropertieshttpapplicationproperties"><strong>1. Define Rate Limits in</strong> <a target="_blank" href="http://application.properties"><code>application.properties</code></a></h2>
<p>Instead of hardcoding limits in the code, we’ll define them in <a target="_blank" href="http://application.properties"><code>application.properties</code></a>:</p>
<pre><code class="lang-plaintext">rate-limiter.enabled=true

# Limits for different API endpoints
rate-limiter.limits.SHORTEN_URL.limit=50
rate-limiter.limits.SHORTEN_URL.timeFrameMinutes=1

rate-limiter.limits.ADVANCED_SHORTEN_URL.limit=30
rate-limiter.limits.ADVANCED_SHORTEN_URL.timeFrameMinutes=2

rate-limiter.limits.LINK_FOLIO.limit=20
rate-limiter.limits.LINK_FOLIO.timeFrameMinutes=5
</code></pre>
<p><strong>What’s Happening Here?</strong></p>
<ul>
<li><p>The <strong>shorten URL API</strong> (<code>/shorten</code>) allows 50 requests per <strong>minute</strong>.</p>
</li>
<li><p>The <strong>advanced shorten URL API</strong> allows 30 requests per <strong>2 minutes</strong>.</p>
</li>
<li><p>The <strong>Link Folio API</strong> allows 20 requests per <strong>5 minutes</strong>.</p>
</li>
<li><p>We can change these values anytime without redeploying the app.</p>
</li>
</ul>
<h2 id="heading-2-load-configurations-in-a-kotlin-class"><strong>2. Load Configurations in a Kotlin Class</strong></h2>
<p>Spring Boot provides a way to read these values using <code>@ConfigurationProperties</code>:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> org.springframework.boot.context.properties.ConfigurationProperties
<span class="hljs-keyword">import</span> org.springframework.context.<span class="hljs-keyword">annotation</span>.Configuration

<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@ConfigurationProperties(prefix = <span class="hljs-meta-string">"rate-limiter"</span>)</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RateLimiterConfig</span> </span>{
    <span class="hljs-keyword">var</span> enabled: <span class="hljs-built_in">Boolean</span> = <span class="hljs-literal">true</span>
    <span class="hljs-keyword">var</span> limits: Map&lt;String, RateLimitProperties&gt; = emptyMap()

    <span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RateLimitProperties</span></span>(<span class="hljs-keyword">var</span> limit: <span class="hljs-built_in">Int</span> = <span class="hljs-number">0</span>, <span class="hljs-keyword">var</span> timeFrameMinutes: <span class="hljs-built_in">Long</span> = <span class="hljs-number">0</span>)
}
</code></pre>
<p><strong>What’s Happening Here?</strong></p>
<ul>
<li><p><code>enabled</code>: Turns rate limiting <strong>on/off</strong> dynamically.</p>
</li>
<li><p><code>limits</code>: A map of <strong>API names to their rate limits</strong>.</p>
</li>
<li><p>Now, we can inject this <code>RateLimiterConfig</code> anywhere in the app.</p>
</li>
</ul>
<h2 id="heading-3-create-a-ratelimited-annotation"><strong>3. Create a</strong> <code>@RateLimited</code> Annotation</h2>
<p>To make things easy, let’s create an annotation that we can apply to API methods:</p>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Target(AnnotationTarget.FUNCTION)</span>
<span class="hljs-meta">@Retention(AnnotationRetention.RUNTIME)</span>
<span class="hljs-keyword">annotation</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RateLimited</span></span>(<span class="hljs-keyword">val</span> service: String)
</code></pre>
<p>This allows us to do things like:</p>
<pre><code class="lang-kotlin"><span class="hljs-meta">@RateLimited(service = <span class="hljs-meta-string">"SHORTEN_URL"</span>)</span>
<span class="hljs-meta">@PostMapping(<span class="hljs-meta-string">"/shorten"</span>)</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">shortenUrl</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> request: <span class="hljs-type">UrlShortenRequest</span>)</span></span>: ResponseEntity&lt;String&gt; {
    <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"Shortened URL"</span>)
}
</code></pre>
<p>Now, our rate limiter will know this API should be limited based on the <strong>SHORTEN_URL</strong> settings.</p>
<h2 id="heading-4-build-the-rate-limiter-logic"><strong>4. Build the Rate Limiter Logic</strong></h2>
<p>We need a service that will track API requests <strong>per IP address and per service type</strong>.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> org.springframework.stereotype.Service
<span class="hljs-keyword">import</span> java.time.LocalDateTime
<span class="hljs-keyword">import</span> java.util.*
<span class="hljs-keyword">import</span> java.util.concurrent.*

<span class="hljs-meta">@Service</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RateLimiterService</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> config: RateLimiterConfig) {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> requestMap = ConcurrentHashMap&lt;String, ConcurrentHashMap&lt;String, Pair&lt;<span class="hljs-built_in">Int</span>, LocalDateTime&gt;&gt;&gt;()

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">isRateLimited</span><span class="hljs-params">(identifier: <span class="hljs-type">String</span>, service: <span class="hljs-type">String</span>)</span></span>: <span class="hljs-built_in">Boolean</span> {
        <span class="hljs-keyword">val</span> limitConfig = config.limits[service] ?: <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
        <span class="hljs-keyword">val</span> currentTime = LocalDateTime.now()

        synchronized(requestMap) {
            <span class="hljs-keyword">val</span> serviceMap = requestMap.getOrPut(identifier) { ConcurrentHashMap() }
            <span class="hljs-keyword">val</span> (requestCount, lastRequestTime) = serviceMap.getOrDefault(service, Pair(<span class="hljs-number">0</span>, currentTime))

            <span class="hljs-keyword">if</span> (lastRequestTime.plusMinutes(limitConfig.timeFrameMinutes).isBefore(currentTime)) {
                serviceMap[service] = Pair(<span class="hljs-number">0</span>, currentTime)
                <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
            }

            <span class="hljs-keyword">return</span> requestCount &gt;= limitConfig.limit
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">registerRequest</span><span class="hljs-params">(identifier: <span class="hljs-type">String</span>, service: <span class="hljs-type">String</span>)</span></span> {
        <span class="hljs-keyword">val</span> limitConfig = config.limits[service] ?: <span class="hljs-keyword">return</span>

        <span class="hljs-keyword">if</span> (isRateLimited(identifier, service)) {
            <span class="hljs-keyword">throw</span> RateLimitExceededException(identifier, limitConfig.limit)
        }

        <span class="hljs-keyword">val</span> currentTime = LocalDateTime.now()

        synchronized(requestMap) {
            <span class="hljs-keyword">val</span> serviceMap = requestMap.getOrPut(identifier) { ConcurrentHashMap() }
            <span class="hljs-keyword">val</span> (requestCount, _) = serviceMap.getOrDefault(service, Pair(<span class="hljs-number">0</span>, currentTime))
            serviceMap[service] = Pair(requestCount + <span class="hljs-number">1</span>, currentTime)

            Timer().schedule(<span class="hljs-keyword">object</span> : TimerTask() {
                <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span> {
                    synchronized(requestMap) {
                        requestMap[identifier]?.remove(service)
                        <span class="hljs-keyword">if</span> (requestMap[identifier]?.isEmpty() == <span class="hljs-literal">true</span>) {
                            requestMap.remove(identifier)
                        }
                    }
                }
            }, TimeUnit.MINUTES.toMillis(limitConfig.timeFrameMinutes))
        }
    }
}
</code></pre>
<p><strong>What’s Happening Here?</strong></p>
<ul>
<li><p>Tracks requests in <code>ConcurrentHashMap</code> (thread-safe).</p>
</li>
<li><p>If the <strong>last request is older than the time limit</strong>, it <strong>resets</strong> the count.</p>
</li>
<li><p>If the limit is <strong>exceeded</strong>, it <strong>throws an exception</strong>.</p>
</li>
<li><p>Uses a <strong>timer</strong> to <strong>automatically remove expired entries</strong>.</p>
</li>
</ul>
<h2 id="heading-5-enforce-rate-limits-with-spring-aop"><strong>5. Enforce Rate Limits with Spring AOP</strong></h2>
<p>Now, we’ll use <strong>Spring AOP</strong> to intercept methods with <code>@RateLimited</code>.</p>
<p><strong>First, Add the AOP Dependency</strong></p>
<p>If you haven’t already, add this to <code>build.gradle.kts</code>:</p>
<pre><code class="lang-kotlin">dependencies {
    implementation(<span class="hljs-string">"org.springframework.boot:spring-boot-starter-aop"</span>)
}
</code></pre>
<h3 id="heading-now-create-the-aop-aspect"><strong>Now, Create the AOP Aspect</strong></h3>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> org.aspectj.lang.ProceedingJoinPoint
<span class="hljs-keyword">import</span> org.aspectj.lang.<span class="hljs-keyword">annotation</span>.Around
<span class="hljs-keyword">import</span> org.aspectj.lang.<span class="hljs-keyword">annotation</span>.Aspect
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component
<span class="hljs-keyword">import</span> org.springframework.web.context.request.RequestContextHolder
<span class="hljs-keyword">import</span> org.springframework.web.context.request.ServletRequestAttributes

<span class="hljs-meta">@Aspect</span>
<span class="hljs-meta">@Component</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RateLimiterAspect</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> rateLimiterService: RateLimiterService, <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> config: RateLimiterConfig) {

    <span class="hljs-meta">@Around(<span class="hljs-meta-string">"@annotation(rateLimited)"</span>)</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">enforceRateLimit</span><span class="hljs-params">(joinPoint: <span class="hljs-type">ProceedingJoinPoint</span>, rateLimited: <span class="hljs-type">RateLimited</span>)</span></span>: Any? {
        <span class="hljs-keyword">if</span> (!config.enabled) <span class="hljs-keyword">return</span> joinPoint.proceed()  <span class="hljs-comment">// Skip if disabled</span>

        <span class="hljs-keyword">val</span> request = (RequestContextHolder.getRequestAttributes() <span class="hljs-keyword">as</span>? ServletRequestAttributes)?.request
        <span class="hljs-keyword">val</span> ipAddress = request?.remoteAddr ?: <span class="hljs-string">"UNKNOWN"</span>

        rateLimiterService.registerRequest(ipAddress, rateLimited.service)

        <span class="hljs-keyword">return</span> joinPoint.proceed()
    }
}
</code></pre>
<h2 id="heading-6-handle-errors-gracefully"><strong>6. Handle Errors Gracefully</strong></h2>
<p>If a user exceeds the limit, we should return a <strong>HTTP 429 Too Many Requests</strong> error.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> org.springframework.http.HttpStatus
<span class="hljs-keyword">import</span> org.springframework.web.bind.<span class="hljs-keyword">annotation</span>.ExceptionHandler
<span class="hljs-keyword">import</span> org.springframework.web.bind.<span class="hljs-keyword">annotation</span>.RestControllerAdvice

<span class="hljs-meta">@RestControllerAdvice</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GlobalExceptionHandler</span> </span>{
    <span class="hljs-meta">@ExceptionHandler(RateLimitExceededException::class)</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">handleRateLimitExceeded</span><span class="hljs-params">(ex: <span class="hljs-type">RateLimitExceededException</span>)</span></span> =
        ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(ex.message)
}
</code></pre>
<h3 id="heading-real-world-example"><strong>Real-World Example</strong></h3>
<p>Let’s say you have a public <strong>link shortener</strong> service. Without rate limiting, users can:</p>
<ul>
<li><p>Flood your API with <strong>thousands of shorten requests per second</strong>.</p>
</li>
<li><p>Use <strong>bots</strong> to create spam links.</p>
</li>
<li><p><strong>Crush your database</strong> with unlimited writes.</p>
</li>
</ul>
<p>By adding <code>@RateLimited(service = "SHORTEN_URL")</code>, you <strong>prevent spam, improve security, and ensure fair access.</strong></p>
<h3 id="heading-learning"><strong>Learning</strong></h3>
<p>🔹 <strong>Now your APIs are protected!</strong><br />🔹 <strong>No more hardcoded limits</strong> – just update <a target="_blank" href="http://application.properties"><code>application.properties</code></a>.<br />🔹 <strong>Easily apply rate limits with</strong> <code>@RateLimited</code> annotation.</p>
<hr />
<p>That’s it for today. Happy coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div><p> </p>
<div class="hn-embed-widget" id="ylnk"></div>]]></content:encoded></item><item><title><![CDATA[Kotlin : Singleton with Memory Efficiency]]></title><description><![CDATA[Singletons are a fundamental design pattern in software development, ensuring that a class has only one instance and provides a global point of access to it. In Kotlin, implementing a singleton is straightforward using the object keyword, but what if...]]></description><link>https://rommansabbir.com/kotlin-singleton-with-memory-efficiency</link><guid isPermaLink="true">https://rommansabbir.com/kotlin-singleton-with-memory-efficiency</guid><category><![CDATA[Android]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[Kotlin Multiplatform]]></category><category><![CDATA[kotlin beginner]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[backend]]></category><category><![CDATA[backend developments]]></category><category><![CDATA[memory-management]]></category><category><![CDATA[memory]]></category><category><![CDATA[efficiency]]></category><category><![CDATA[Singleton Design Pattern]]></category><category><![CDATA[singleton]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[memory allocation ]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Thu, 27 Feb 2025 16:42:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740674294925/1e4817b7-09a4-45e9-b5bd-3746b721a514.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Singletons are a fundamental design pattern in software development, ensuring that a class has only one instance and provides a global point of access to it. In Kotlin, implementing a singleton is straightforward using the <code>object</code> keyword, but what if we need a <strong>memory-efficient, lazy-loaded, and thread-safe singleton</strong>?</p>
<p>In this article, we'll explore different ways to implement a singleton in Kotlin while optimizing <strong>memory usage</strong> and <strong>lazy initialization</strong>. We'll compare eager vs. lazy instantiation, discuss potential pitfalls like unnecessary memory consumption, and implement a <strong>double-checked locking singleton</strong>, ensuring both efficiency and performance. Plus, we'll introduce a way to <strong>destroy the singleton instance</strong>, giving you more control over resource management.</p>
<p>By the end, you'll know which approach best suits your needs, whether you're building an Android app, a back-end service, or a high-performance Kotlin application.</p>
<p>Let's dive into the world of <strong>memory-efficient singleton design in Kotlin</strong> with some practical examples!</p>
<hr />
<h2 id="heading-using-lazy-delegation">Using Lazy Delegation</h2>
<p>If we want a <strong>lazy-loaded singleton</strong>, Kotlin’s <code>lazy</code> delegation makes it incredibly easy:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Singleton</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constructor</span></span>() {
    <span class="hljs-keyword">init</span> {
        println(<span class="hljs-string">"Singleton instance created"</span>)
    }

    <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-keyword">val</span> instance: Singleton <span class="hljs-keyword">by</span> lazy { Singleton() }
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">doSomething</span><span class="hljs-params">()</span></span> {
        println(<span class="hljs-string">"Doing something..."</span>)
    }
}
</code></pre>
<p>✅ <strong>Why use this?</strong></p>
<ul>
<li><p>The instance is created only when accessed for the first time.</p>
</li>
<li><p>Thread-safe by default.</p>
</li>
</ul>
<hr />
<h2 id="heading-thread-safe-lazy-singleton-synchronized">Thread-Safe Lazy Singleton (Synchronized)</h2>
<p>If we need a <strong>thread-safe</strong> singleton with explicit control, we can use <code>synchronized</code> to ensure only one instance is created, even in multi-threaded environments.</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SafeSingleton</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constructor</span></span>() {
    <span class="hljs-keyword">init</span> {
        println(<span class="hljs-string">"SafeSingleton instance created"</span>)
    }

    <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-meta">@Volatile</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> instance: SafeSingleton? = <span class="hljs-literal">null</span>

        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span>: SafeSingleton {
            <span class="hljs-keyword">return</span> instance ?: synchronized(<span class="hljs-keyword">this</span>) {
                instance ?: SafeSingleton().also { instance = it }
            }
        }
    }
}
</code></pre>
<p>✅ <strong>Why use this?</strong></p>
<ul>
<li><p>Thread-safe.</p>
</li>
<li><p>Lazy initialization.</p>
</li>
<li><p>Prevents multiple instances from being created in multi-threaded scenarios.</p>
</li>
</ul>
<p>🔹 <strong>Note:</strong> <code>@Volatile</code> ensures that updates to <code>instance</code> are visible across threads. However, in some cases, <code>@Volatile</code> <strong>might cause the object to load on the main thread</strong> if accessed from the UI. While this is usually not an issue, we can manually handle initialization in a background thread if needed.</p>
<hr />
<h2 id="heading-kotlin-object-singleton-best-for-simplicity">Kotlin <code>object</code> Singleton (Best for Simplicity)</h2>
<p>If we don’t need lazy initialization or additional control, Kotlin provides a built-in way to create singletons using the <code>object</code> keyword:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">object</span> SimpleSingleton {
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">doSomething</span><span class="hljs-params">()</span></span> {
        println(<span class="hljs-string">"Doing something in SimpleSingleton"</span>)
    }
}
</code></pre>
<p>✅ <strong>Why use this?</strong></p>
<ul>
<li><p>Short and simple.</p>
</li>
<li><p>Thread-safe by default.</p>
</li>
<li><p>Easy to use for lightweight singletons.</p>
</li>
</ul>
<p>❌ <strong>Downside?</strong></p>
<ul>
<li><strong>Eager initialization</strong> (created at class load time, even if never used).</li>
</ul>
<hr />
<h2 id="heading-simple-lazy-singleton-without-synchronized">Simple Lazy Singleton Without <code>synchronized</code></h2>
<p>If thread safety isn’t a concern, a <strong>basic lazy singleton</strong> without synchronization can be used:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SimpleSingleton</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constructor</span></span>() {
    <span class="hljs-keyword">init</span> {
        println(<span class="hljs-string">"SimpleSingleton instance created"</span>)
    }

    <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> instance: SimpleSingleton? = <span class="hljs-literal">null</span>

        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span>: SimpleSingleton {
            <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">null</span>) {
                instance = SimpleSingleton()
            }
            <span class="hljs-keyword">return</span> instance!!
        }
    }
}
</code></pre>
<p>✅ <strong>Why use this?</strong></p>
<ul>
<li><p>Works fine in a single-threaded environment.</p>
</li>
<li><p>Saves memory compared to an eager singleton.</p>
</li>
</ul>
<p>❌ <strong>Downside?</strong></p>
<ul>
<li>Not thread-safe.</li>
</ul>
<hr />
<h2 id="heading-optimized-singleton-with-memory-efficiency-amp-manual-destruction">Optimized Singleton with Memory Efficiency &amp; Manual Destruction</h2>
<p>If we need a <strong>fully optimized, thread-safe, and lazy-loaded singleton</strong>, while also allowing <strong>manual destruction</strong>, the <strong>double-checked locking singleton</strong> is the best approach:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OptimizedSingleton</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">constructor</span></span>() {
    <span class="hljs-keyword">init</span> {
        println(<span class="hljs-string">"OptimizedSingleton instance created"</span>)
    }

    <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-meta">@Volatile</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> instance: OptimizedSingleton? = <span class="hljs-literal">null</span>

        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span>: OptimizedSingleton {
            <span class="hljs-keyword">return</span> instance ?: synchronized(<span class="hljs-keyword">this</span>) {
                instance ?: OptimizedSingleton().also { instance = it }
            }
        }

        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">destroyInstance</span><span class="hljs-params">()</span></span> {
            synchronized(<span class="hljs-keyword">this</span>) {
                instance = <span class="hljs-literal">null</span>
                println(<span class="hljs-string">"OptimizedSingleton instance destroyed"</span>)
            }
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">doSomething</span><span class="hljs-params">()</span></span> {
        println(<span class="hljs-string">"Doing something in OptimizedSingleton"</span>)
    }
}
</code></pre>
<p>✅ <strong>Why use this?</strong></p>
<ul>
<li><p><strong>Lazy initialization</strong> (created only when needed).</p>
</li>
<li><p><strong>Thread-safe</strong> (using <code>synchronized</code>).</p>
</li>
<li><p><strong>Efficient memory usage</strong> (not pre-loaded).</p>
</li>
<li><p><strong>Manual destruction</strong> (<code>destroyInstance()</code>) allows explicit cleanup if needed.</p>
</li>
</ul>
<hr />
<h2 id="heading-comparing-singleton-approaches">Comparing Singleton Approaches</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Approach</td><td>Lazy Initialization</td><td>Thread Safety</td><td>Memory Efficient</td><td>Manual Destruction</td><td>Performance</td></tr>
</thead>
<tbody>
<tr>
<td><code>object</code> Singleton</td><td>❌ (Eager)</td><td>✅ Yes</td><td>❌ (Always Loaded)</td><td>❌ No</td><td>✅ Fast</td></tr>
<tr>
<td>Simple Companion Object</td><td>✅ Yes (On Demand)</td><td>❌ No</td><td>✅ Yes</td><td>❌ No</td><td>✅ Fast</td></tr>
<tr>
<td><code>Double-Checked Locking</code></td><td>✅ Yes (On Demand)</td><td>✅ Yes</td><td>✅ Best</td><td>✅ Yes</td><td>✅ Best</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-when-to-use-which-singleton">When to Use Which Singleton?</h2>
<ul>
<li><p><strong>Use</strong> <code>object</code> Singleton → When simplicity and quick access are preferred.</p>
</li>
<li><p><strong>Use Simple Lazy Singleton</strong> → If running in a single-threaded environment.</p>
</li>
<li><p><strong>Use</strong> <code>Double-Checked Locking</code> → When <strong>memory efficiency, lazy initialization, and thread safety</strong> are critical.</p>
</li>
<li><p><strong>Use</strong> <code>OptimizedSingleton</code> → If we need all the benefits of <code>Double-Checked Locking</code> <strong>plus manual destruction</strong>.</p>
</li>
</ul>
<p>By choosing the right approach, we can optimize both memory usage and performance while keeping our singleton <strong>efficient and scalable</strong>.</p>
<hr />
<p>That’s it for today. Happy Coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Android : LiveData vs Flow]]></title><description><![CDATA[FeatureLiveDataFlow



TypeObservable data holder classCold stream of data

ReactivityEmits only when observedCollects only when needed

ThreadingRuns on the main thread by defaultRuns on the background thread by default

Backpressure HandlingNot sup...]]></description><link>https://rommansabbir.com/android-livedata-vs-flow</link><guid isPermaLink="true">https://rommansabbir.com/android-livedata-vs-flow</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Android Studio]]></category><category><![CDATA[android apps]]></category><category><![CDATA[livedata]]></category><category><![CDATA[flow]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[lifecycle]]></category><category><![CDATA[Reactive Programming]]></category><category><![CDATA[kotlin coroutines]]></category><category><![CDATA[kotlin-flow]]></category><category><![CDATA[LifecycleManagement]]></category><category><![CDATA[fragment]]></category><category><![CDATA[Activity]]></category><category><![CDATA[rommansabbir]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Wed, 26 Feb 2025 06:22:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740550815870/6e97c813-a971-4196-a4e5-c4410a28f647.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="hn-table">
<table>
<thead>
<tr>
<td>Feature</td><td>LiveData</td><td>Flow</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Type</strong></td><td>Observable data holder class</td><td>Cold stream of data</td></tr>
<tr>
<td><strong>Reactivity</strong></td><td>Emits only when observed</td><td>Collects only when needed</td></tr>
<tr>
<td><strong>Threading</strong></td><td>Runs on the <strong>main thread</strong> by default</td><td>Runs on the <strong>background thread</strong> by default</td></tr>
<tr>
<td><strong>Backpressure Handling</strong></td><td>Not supported (always runs on the main thread)</td><td>Handles backpressure efficiently</td></tr>
<tr>
<td><strong>Lifecycle Awareness</strong></td><td><strong>Yes</strong>, automatically stops when the observer’s lifecycle is destroyed</td><td><strong>No</strong>, needs manual lifecycle handling (<code>lifecycleScope.launch</code>)</td></tr>
<tr>
<td><strong>Data Emission</strong></td><td><strong>Retains</strong> last emitted value</td><td>Does <strong>not retain</strong> values by default (stateless)</td></tr>
<tr>
<td><strong>Multiple Subscribers</strong></td><td>Supports <strong>multiple</strong> active observers</td><td><strong>Cold stream</strong>, each collector gets a new stream</td></tr>
<tr>
<td><strong>Cold vs Hot</strong></td><td><strong>Hot</strong> (always active, even without observers)</td><td><strong>Cold</strong> (starts emitting only when collected)</td></tr>
<tr>
<td><strong>Use Case</strong></td><td>UI state management, database, observing changes</td><td>One-time API calls, event streams, complex data transformations</td></tr>
<tr>
<td><strong>Cancellation</strong></td><td>Automatically stops when the lifecycle is destroyed</td><td>Needs manual cancellation using coroutine scope</td></tr>
<tr>
<td><strong>Memory Efficiency</strong></td><td>Can retain memory if not properly cleared</td><td>More memory-efficient, does not store unnecessary data</td></tr>
<tr>
<td><strong>Error Handling</strong></td><td>Uses <code>observeForever</code> but no built-in try/catch</td><td>Supports <code>catch {}</code> and <code>onEach {}</code> for error handling</td></tr>
<tr>
<td><strong>Best Used For</strong></td><td>UI-related state observation, database updates (Room)</td><td>API calls, event-based operations, and continuous data streams</td></tr>
</tbody>
</table>
</div><h3 id="heading-when-to-use-livedata"><strong>When to Use LiveData?</strong></h3>
<p>✅ Lifecycle-aware UI updates<br />✅ Simple UI state management<br />✅ Works well with XML-based views</p>
<h3 id="heading-when-to-use-flow"><strong>When to Use Flow?</strong></h3>
<p>✅ One-time API calls<br />✅ Handling large data streams efficiently<br />✅ Best suited for <strong>Jetpack Compose</strong><br />✅ Background operations without UI binding</p>
<p>👉 <strong>Best Practice:</strong> Use <strong>Flow</strong> for <strong>data processing and transformations</strong>, then convert it to <strong>LiveData</strong> if UI needs to observe it (<code>asLiveData()</code>). 🚀</p>
<hr />
<p>That’s it for today. Happy Coding….</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Secure Storage in Android: A Comprehensive Guide [PART 5]]]></title><description><![CDATA[When developing Android apps, ensuring secure data storage is essential to protect sensitive information like user credentials, tokens, and other private data from being accessed by unauthorized entities. This article covers essential techniques for ...]]></description><link>https://rommansabbir.com/secure-storage-in-android-a-comprehensive-guide-part-5</link><guid isPermaLink="true">https://rommansabbir.com/secure-storage-in-android-a-comprehensive-guide-part-5</guid><category><![CDATA[sqlcipher]]></category><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Secure]]></category><category><![CDATA[storage]]></category><category><![CDATA[Android]]></category><category><![CDATA[Shared Preferences]]></category><category><![CDATA[SQLite]]></category><category><![CDATA[crypto]]></category><category><![CDATA[encryption]]></category><category><![CDATA[decryption]]></category><category><![CDATA[Security]]></category><category><![CDATA[best practices]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[file encryption]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Sat, 15 Feb 2025 08:10:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730046708259/728726ad-fe58-4e6e-aee2-a0335de3f021.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When developing Android apps, ensuring secure data storage is essential to protect sensitive information like user credentials, tokens, and other private data from being accessed by unauthorized entities. This article covers essential techniques for secure storage in Android, including <strong>SharedPreferences Encryption</strong>, <strong>SQLite Database Encryption</strong>, and <strong>External Storage Encryption</strong>. Each section includes real-life examples and Kotlin code snippets to help you implement secure storage practices in your Android apps.</p>
<hr />
<h3 id="heading-sharedpreferences-encryption-securing-small-data"><strong>SharedPreferences Encryption: Securing Small Data</strong></h3>
<p><strong>SharedPreferences</strong> in Android is a commonly used API for storing small amounts of key-value pair data, such as user preferences, session tokens, or flags. However, storing sensitive data in plain text using SharedPreferences can expose it to security risks like rooting or unauthorized app access. To address this, Android provides <strong>EncryptedSharedPreferences</strong>, which encrypts the data stored in SharedPreferences, ensuring that sensitive information is stored securely.</p>
<h4 id="heading-use-case-storing-session-tokens-securely"><strong>Use Case: Storing Session Tokens Securely</strong></h4>
<p>You may use SharedPreferences to store a session token or other small sensitive data. Using EncryptedSharedPreferences ensures that this data is encrypted and cannot be accessed by unauthorized apps or users.</p>
<h4 id="heading-kotlin-example-implementing-encryptedsharedpreferences"><strong>Kotlin Example: Implementing EncryptedSharedPreferences</strong></h4>
<ol>
<li>Add the necessary dependency to your <code>build.gradle</code> file:</li>
</ol>
<pre><code class="lang-kotlin">implementation <span class="hljs-string">"androidx.security:security-crypto:1.1.0-alpha03"</span>
</code></pre>
<ol start="2">
<li>Set up <strong>EncryptedSharedPreferences</strong> in your app:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> androidx.security.crypto.EncryptedSharedPreferences
<span class="hljs-keyword">import</span> androidx.security.crypto.MasterKeys

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setupEncryptedSharedPreferences</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>)</span></span> {
    <span class="hljs-comment">// Generate or retrieve the master key</span>
    <span class="hljs-keyword">val</span> masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

    <span class="hljs-comment">// Create an instance of EncryptedSharedPreferences</span>
    <span class="hljs-keyword">val</span> sharedPreferences = EncryptedSharedPreferences.create(
        <span class="hljs-string">"secure_prefs"</span>,
        masterKeyAlias,
        context,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

    <span class="hljs-comment">// Store and retrieve encrypted data</span>
    <span class="hljs-keyword">val</span> editor = sharedPreferences.edit()
    editor.putString(<span class="hljs-string">"auth_token"</span>, <span class="hljs-string">"1234567890"</span>)
    editor.apply()

    <span class="hljs-keyword">val</span> authToken = sharedPreferences.getString(<span class="hljs-string">"auth_token"</span>, <span class="hljs-literal">null</span>)
    println(<span class="hljs-string">"Retrieved encrypted token: <span class="hljs-variable">$authToken</span>"</span>)
}
</code></pre>
<p>In this example, the <strong>EncryptedSharedPreferences</strong> API encrypts both the keys and values of the SharedPreferences, ensuring that sensitive data (like an authentication token) is stored securely.</p>
<h4 id="heading-real-life-example-securing-user-preferences"><strong>Real-Life Example: Securing User Preferences</strong></h4>
<p>An e-commerce app might store user settings, such as login session tokens or payment preferences, using SharedPreferences. Storing this data using EncryptedSharedPreferences ensures that attackers cannot easily access or modify the data.</p>
<hr />
<h3 id="heading-sqlite-database-encryption-securing-local-databases"><strong>SQLite Database Encryption: Securing Local Databases</strong></h3>
<p>Android apps often use SQLite databases for local storage of structured data. However, storing sensitive information such as user data or application configurations in plain text databases can expose it to security risks, especially if the device is compromised. To mitigate this, you can use encryption libraries like <strong>SQLCipher</strong> to encrypt the contents of your SQLite database.</p>
<h4 id="heading-use-case-encrypting-user-data-in-local-databases"><strong>Use Case: Encrypting User Data in Local Databases</strong></h4>
<p>If your app stores sensitive user data such as personally identifiable information (PII), you need to encrypt the local SQLite database to protect it from unauthorized access. This is especially important if the device is rooted or the database file is accessed directly.</p>
<h4 id="heading-kotlin-example-implementing-sqlite-database-encryption-with-sqlcipher"><strong>Kotlin Example: Implementing SQLite Database Encryption with SQLCipher</strong></h4>
<ol>
<li>Add the SQLCipher dependency to your <code>build.gradle</code> file:</li>
</ol>
<pre><code class="lang-kotlin">implementation <span class="hljs-string">'net.zetetic:android-database-sqlcipher:4.5.0'</span>
</code></pre>
<ol start="2">
<li>Create or open an encrypted SQLite database:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> net.sqlcipher.database.SQLiteDatabase
<span class="hljs-keyword">import</span> net.sqlcipher.database.SQLiteOpenHelper

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecureDatabaseHelper</span></span>(context: Context) : SQLiteOpenHelper(context, <span class="hljs-string">"secure_db"</span>, <span class="hljs-literal">null</span>, <span class="hljs-number">1</span>) {

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(db: <span class="hljs-type">SQLiteDatabase</span>)</span></span> {
        db.execSQL(<span class="hljs-string">"CREATE TABLE User (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onUpgrade</span><span class="hljs-params">(db: <span class="hljs-type">SQLiteDatabase</span>, oldVersion: <span class="hljs-type">Int</span>, newVersion: <span class="hljs-type">Int</span>)</span></span> {
        db.execSQL(<span class="hljs-string">"DROP TABLE IF EXISTS User"</span>)
        onCreate(db)
    }
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getEncryptedDatabase</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, password: <span class="hljs-type">String</span>)</span></span>: SQLiteDatabase {
    SQLiteDatabase.loadLibs(context) <span class="hljs-comment">// Load SQLCipher libraries</span>
    <span class="hljs-keyword">val</span> dbHelper = SecureDatabaseHelper(context)
    <span class="hljs-keyword">return</span> dbHelper.getWritableDatabase(password) <span class="hljs-comment">// Open encrypted database</span>
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">insertEncryptedData</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, password: <span class="hljs-type">String</span>)</span></span> {
    <span class="hljs-keyword">val</span> db = getEncryptedDatabase(context, password)
    <span class="hljs-keyword">val</span> contentValues = ContentValues().apply {
        put(<span class="hljs-string">"name"</span>, <span class="hljs-string">"John Doe"</span>)
        put(<span class="hljs-string">"email"</span>, <span class="hljs-string">"johndoe@example.com"</span>)
    }
    db.insert(<span class="hljs-string">"User"</span>, <span class="hljs-literal">null</span>, contentValues)
    db.close()
}
</code></pre>
<p>In this example, <strong>SQLCipher</strong> is used to create and manage an encrypted SQLite database. The password provided is used to encrypt and decrypt the database, ensuring that sensitive information remains protected even if the database file is accessed directly.</p>
<h4 id="heading-real-life-example-storing-medical-records"><strong>Real-Life Example: Storing Medical Records</strong></h4>
<p>A health app that stores medical records or user health data locally should use an encrypted SQLite database to ensure that sensitive health information is protected from unauthorized access, even if the device is compromised or rooted.</p>
<hr />
<h3 id="heading-external-storage-encryption-securing-files-on-external-storage"><strong>External Storage Encryption: Securing Files on External Storage</strong></h3>
<p>Android allows apps to store files on external storage (e.g., SD cards or shared storage). However, files stored in external storage are generally accessible to other apps, and can be read or modified by malicious apps. To secure sensitive files, such as documents or media files, it is crucial to encrypt them before saving to external storage.</p>
<h4 id="heading-use-case-encrypting-files-before-saving-to-external-storage"><strong>Use Case: Encrypting Files Before Saving to External Storage</strong></h4>
<p>If your app needs to store sensitive files like user-generated content, personal documents, or media files, encrypting these files ensures that they cannot be accessed or modified by other apps or attackers with access to the external storage.</p>
<h4 id="heading-kotlin-example-encrypting-and-saving-files-to-external-storage"><strong>Kotlin Example: Encrypting and Saving Files to External Storage</strong></h4>
<ol>
<li>Add the necessary dependency for encryption:</li>
</ol>
<pre><code class="lang-kotlin">implementation <span class="hljs-string">'androidx.security:security-crypto:1.1.0-alpha03'</span>
</code></pre>
<ol start="2">
<li>Encrypt a file before saving it to external storage:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> android.content.Context
<span class="hljs-keyword">import</span> android.os.Environment
<span class="hljs-keyword">import</span> androidx.security.crypto.EncryptedFile
<span class="hljs-keyword">import</span> androidx.security.crypto.MasterKeys
<span class="hljs-keyword">import</span> java.io.File

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">saveEncryptedFile</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, fileName: <span class="hljs-type">String</span>, fileContent: <span class="hljs-type">String</span>)</span></span> {
    <span class="hljs-comment">// Create a master key</span>
    <span class="hljs-keyword">val</span> masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

    <span class="hljs-comment">// Create a file object for the external storage directory</span>
    <span class="hljs-keyword">val</span> externalFile = File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), fileName)

    <span class="hljs-comment">// Create an EncryptedFile object</span>
    <span class="hljs-keyword">val</span> encryptedFile = EncryptedFile.Builder(
        externalFile,
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()

    <span class="hljs-comment">// Write encrypted content to the file</span>
    encryptedFile.openFileOutput().use { outputStream -&gt;
        outputStream.write(fileContent.toByteArray())
    }

    println(<span class="hljs-string">"File saved securely in external storage."</span>)
}
</code></pre>
<ol start="3">
<li>To read the encrypted file, use the corresponding <code>openFileInput</code> method:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">readEncryptedFile</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, fileName: <span class="hljs-type">String</span>)</span></span>: String {
    <span class="hljs-keyword">val</span> masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
    <span class="hljs-keyword">val</span> externalFile = File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), fileName)

    <span class="hljs-keyword">val</span> encryptedFile = EncryptedFile.Builder(
        externalFile,
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()

    <span class="hljs-keyword">return</span> encryptedFile.openFileInput().use { inputStream -&gt;
        inputStream.bufferedReader().readText()
    }
}
</code></pre>
<p>In this example, <strong>EncryptedFile</strong> is used to encrypt a file before saving it to external storage. This ensures that even if other apps access the file on external storage, they cannot read its contents without the proper decryption key.</p>
<h4 id="heading-real-life-example-encrypting-media-files"><strong>Real-Life Example: Encrypting Media Files</strong></h4>
<p>A photo-sharing app that allows users to upload sensitive images might need to store these images locally before uploading. By encrypting the images before saving them to external storage, the app ensures that other apps or malicious actors cannot access or modify the images.</p>
<hr />
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Securing data storage in Android is crucial for protecting sensitive user information from unauthorized access. By using <strong>EncryptedSharedPreferences</strong>, you can securely store small key-value pairs such as tokens or flags. For apps that store larger amounts of structured data, libraries like <strong>SQLCipher</strong> can encrypt the contents of SQLite databases. Finally, when storing sensitive files on external storage, <strong>EncryptedFile</strong> ensures that files are encrypted before saving, preventing unauthorized apps from accessing them.</p>
<p>By implementing these secure storage techniques, you can ensure that your Android app remains compliant with security best practices and that sensitive user data is protected from potential threats.</p>
<hr />
<p>That’s it for today. Happy Coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Android : Fix URI Restrictions 🔥]]></title><description><![CDATA[When working with files in Android, we often come across content:// URIs from file pickers, downloads, or external storage. However, WebView, third-party libraries, or some APIs might not accept content:// URIs directly, which can cause errors such a...]]></description><link>https://rommansabbir.com/android-fix-uri-restrictions</link><guid isPermaLink="true">https://rommansabbir.com/android-fix-uri-restrictions</guid><category><![CDATA[file provider]]></category><category><![CDATA[how to fix uri]]></category><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[files]]></category><category><![CDATA[uri]]></category><category><![CDATA[Security]]></category><category><![CDATA[Android Studio]]></category><category><![CDATA[android apps]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[file-permission]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[Java]]></category><category><![CDATA[Provider]]></category><category><![CDATA[fix]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Thu, 06 Feb 2025 09:24:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738833652235/3cb0c8f1-8140-4e88-808d-d6be44680971.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When working with files in Android, we often come across <code>content://</code> URIs from file pickers, downloads, or external storage. However, <strong>WebView, third-party libraries, or some APIs might not accept</strong> <code>content://</code> URIs directly, which can cause errors such as:</p>
<pre><code class="lang-plaintext">java.lang.IllegalArgumentException: Uri lacks 'file' scheme
</code></pre>
<p>Android enforces strict <strong>scoped storage policies</strong>, so directly converting <code>content://</code> to [<code>file://</code>](file://) is no longer allowed. Instead, we <strong>use a secure method</strong> to create a <strong>temporary file</strong> and provide access through <code>FileProvider</code>.</p>
<h2 id="heading-the-problem-why-cant-we-use-content-directly"><strong>The Problem: Why Can't We Use</strong> <code>content://</code> Directly?</h2>
<p>Modern Android security policies prevent apps from accessing another app's files <strong>directly</strong>. If we try to use a <code>content://</code> URI in WebView or share it externally, we'll often run into:</p>
<ul>
<li><p>SecurityException (Permission Denied)</p>
</li>
<li><p>IllegalArgumentException (URI Lacks 'File' Scheme)</p>
</li>
<li><p>File Not Found Exception</p>
</li>
</ul>
<p>To <strong>safely</strong> access and use <code>content://</code> URIs, we <strong>convert them into a secure</strong> [<code>file://</code>](file://) URI using a <code>FileProvider</code>.</p>
<h2 id="heading-the-solution-convert-content-to-a-secure-file-uri"><strong>The Solution: Convert</strong> <code>content://</code> to a Secure File URI</h2>
<p><strong>→ Step 1: Add</strong> <code>FileProvider</code> to AndroidManifest.xml</p>
<p>First, register <code>FileProvider</code> inside <code>&lt;application&gt;</code>:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">provider</span>
    <span class="hljs-attr">android:name</span>=<span class="hljs-string">"androidx.core.content.FileProvider"</span>
    <span class="hljs-attr">android:authorities</span>=<span class="hljs-string">"${applicationId}.fileProvider"</span>
    <span class="hljs-attr">android:exported</span>=<span class="hljs-string">"false"</span>
    <span class="hljs-attr">android:grantUriPermissions</span>=<span class="hljs-string">"true"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta-data</span>
        <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.support.FILE_PROVIDER_PATHS"</span>
        <span class="hljs-attr">android:resource</span>=<span class="hljs-string">"@xml/provider_paths"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">provider</span>&gt;</span>
</code></pre>
<blockquote>
<p>The <code>${applicationId}.fileProvider</code> should match our app's package.</p>
</blockquote>
<p><strong>→ Step 2: Define Secure File Paths</strong></p>
<p>Create a new XML file <code>res/xml/provider_paths.xml</code> to specify <strong>which directories can be accessed</strong>:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">paths</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">cache-path</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"cache"</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"."</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">external-files-path</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"external_files"</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"."</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">paths</span>&gt;</span>
</code></pre>
<blockquote>
<p>This ensures <strong>only files in cache or external storage</strong> can be shared securely.</p>
</blockquote>
<p><strong>→ Step 3: Convert</strong> <code>content://</code> to a Secure URI</p>
<p>Now, use this Kotlin function to safely access any <code>Uri</code>:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FailedToEnableAccessForURI</span></span>(<span class="hljs-keyword">override</span> <span class="hljs-keyword">val</span> message: String = <span class="hljs-string">"Failed to provide access."</span>) : Exception()

<span class="hljs-function"><span class="hljs-keyword">fun</span> Uri.<span class="hljs-title">grantAppAccess</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>)</span></span>: Uri {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Get the file extension from the original Uri</span>
        <span class="hljs-keyword">val</span> fileExtension = context.contentResolver.getType(<span class="hljs-keyword">this</span>)?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
            ?: <span class="hljs-string">"tmp"</span> <span class="hljs-comment">// Default to "tmp" if the extension cannot be determined</span>

        <span class="hljs-comment">// Open an input stream for the URI (reads the content of the file)</span>
        <span class="hljs-keyword">val</span> inputStream = context.contentResolver.openInputStream(<span class="hljs-keyword">this</span>)
            ?: <span class="hljs-keyword">throw</span> FailedToEnableAccessForURI(<span class="hljs-string">"Input stream is null."</span>)

        <span class="hljs-comment">// Create a temporary file in the app's cache directory with the correct extension</span>
        <span class="hljs-keyword">val</span> tempFile = File(context.cacheDir, <span class="hljs-string">"upload_<span class="hljs-subst">${System.currentTimeMillis()}</span>.<span class="hljs-variable">$fileExtension</span>"</span>)

        <span class="hljs-comment">// Write the input stream's data to the temporary file</span>
        FileOutputStream(tempFile).use { output -&gt;
            inputStream.copyTo(output)
        }

        <span class="hljs-comment">// Close the input stream after usage</span>
        inputStream.close()

        <span class="hljs-comment">// Generate a URI for the temp file using FileProvider</span>
        FileProvider.getUriForFile(context, <span class="hljs-string">"<span class="hljs-subst">${context.packageName}</span>.fileProvider"</span>, tempFile)

    } <span class="hljs-keyword">catch</span> (e: Exception) {
        <span class="hljs-keyword">throw</span> FailedToEnableAccessForURI().apply {
            <span class="hljs-keyword">this</span>.stackTrace = e.stackTrace
        }
    }
}
</code></pre>
<p><strong>→ Step 4: How to Use It?</strong></p>
<p>Use this function whenever you need a <strong>secure file URI</strong>:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> secureUri = selectedUri.grantAppAccess(context)
webView.loadUrl(secureUri.toString()) <span class="hljs-comment">// ✅ No more URI access issues!</span>
</code></pre>
<h2 id="heading-why-this-works"><strong>Why This Works?</strong></h2>
<ul>
<li><p><strong>Bypasses restrictions</strong> on <code>content://</code> URIs</p>
</li>
<li><p><strong>Creates a temporary file</strong> for easy access</p>
</li>
<li><p><strong>Works with WebView, File Uploads, and Third-party APIs</strong></p>
</li>
<li><p><strong>Follows Android security policies</strong> (Scoped Storage, FileProvider)</p>
</li>
</ul>
<h2 id="heading-what-to-keep-in-mind-if-the-app-is-multi-modular-or-each-module-has-its-own-fileprovider"><strong>What to Keep in Mind if the App is Multi-Modular or Each Module Has Its Own FileProvider</strong></h2>
<p>If our app is <strong>multi-modular</strong>, or each module <strong>has its own FileProvider</strong>, we need to be careful about <strong>URI authority conflicts</strong>. Here’s what we need to consider:</p>
<ol>
<li><strong><em>Each Module Should Have a Unique Authority</em></strong></li>
</ol>
<p>If each module registers its own <code>FileProvider</code>, the <strong>authority must be unique</strong>.<br />For example:</p>
<ul>
<li><p><strong>Main app (</strong><code>com.myapp.main</code>) → <code>"com.myapp.main.fileprovider"</code></p>
</li>
<li><p><strong>Module A (</strong><code>com.myapp.modulea</code>) → <code>"com.myapp.modulea.fileprovider"</code></p>
</li>
<li><p><strong>Module B (</strong><code>com.myapp.moduleb</code>) → <code>"com.myapp.moduleb.fileprovider"</code></p>
</li>
</ul>
<blockquote>
<p>If two modules use the <strong>same authority</strong>, the app might <strong>crash</strong> or <strong>fail to resolve URIs</strong>.</p>
</blockquote>
<ol start="2">
<li><strong><em>Use the Correct Authority When Generating URIs</em></strong></li>
</ol>
<p>If we are calling <code>FileProvider.getUriForFile()</code>, we must use the correct authority for the module handling the file:</p>
<pre><code class="lang-kotlin">FileProvider.getUriForFile(context, <span class="hljs-string">"com.myapp.modulea.fileprovider"</span>, file)
</code></pre>
<blockquote>
<p><strong>Do not hardcode the main app’s authority</strong> unless the module explicitly shares its FileProvider.</p>
</blockquote>
<ol start="3">
<li><strong><em>Grant URI Permissions Correctly</em></strong></li>
</ol>
<p>When sharing a file URI between modules, we <strong>must grant temporary access permissions</strong>:</p>
<pre><code class="lang-kotlin">intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
</code></pre>
<p>Otherwise, the receiving module <strong>won’t be able to read the file</strong>.</p>
<ol start="4">
<li><strong>Consider a Single Centralized FileProvider</strong></li>
</ol>
<p>Instead of multiple <code>FileProviders</code>, we can define <strong>one</strong> <code>FileProvider</code> in the main app and let all modules use it:</p>
<ul>
<li><p><strong>Declare FileProvider in the Main App (</strong><code>com.myapp.main.fileprovider</code>)</p>
</li>
<li><p><strong>All modules use</strong> <code>com.myapp.main.fileprovider</code> instead of their own</p>
</li>
</ul>
<blockquote>
<p>This avoids confusion, duplicate authorities, and makes URI access easier across the app.</p>
</blockquote>
<ol start="5">
<li><strong>Debugging Authority Issues</strong></li>
</ol>
<p>If we get an error like <strong>"Couldn't find meta-data for provider"</strong>, check:</p>
<ul>
<li><p><strong>Does the module have its own FileProvider?</strong></p>
</li>
<li><p><strong>Are we using the correct authority?</strong></p>
</li>
<li><p><strong>Does</strong> <code>provider_paths.xml</code> exist in the correct module?</p>
</li>
</ul>
<h3 id="heading-tldr-best-practices-for-multi-modular-apps"><strong>TL;DR - Best Practices for Multi-Modular Apps</strong></h3>
<ul>
<li><p><strong>Use unique authorities for each module’s FileProvider</strong></p>
</li>
<li><p><strong>Use the correct authority when generating URIs</strong></p>
</li>
<li><p><strong>Grant read/write permissions when sharing URIs</strong></p>
</li>
<li><p><strong>Consider a single centralized FileProvider to simplify access</strong></p>
</li>
</ul>
<p>With these best practices, we can safely access <code>Uri</code> files in Android <strong>without security restrictions</strong>—even in multi-modular apps!</p>
<hr />
<p>That’s for today. Happy Coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Kotlin : Sequences for Efficient Data Processing]]></title><description><![CDATA[In Kotlin, efficiently handling collections is important when working with large datasets or performing multiple transformations. One tool Kotlin offers for these situations is sequences, which allow lazy evaluation to reduce memory usage and improve...]]></description><link>https://rommansabbir.com/kotlin-sequences-for-efficient-data-processing</link><guid isPermaLink="true">https://rommansabbir.com/kotlin-sequences-for-efficient-data-processing</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[collection]]></category><category><![CDATA[sequence]]></category><category><![CDATA[lazyload]]></category><category><![CDATA[memory-management]]></category><category><![CDATA[Performance Optimization]]></category><category><![CDATA[Filter]]></category><category><![CDATA[Mapping]]></category><category><![CDATA[dataset]]></category><category><![CDATA[Android Studio]]></category><category><![CDATA[android apps]]></category><category><![CDATA[complex-filtering]]></category><category><![CDATA[#transformations]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Tue, 07 Jan 2025 12:07:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736250227801/bedccd11-6162-48db-bc71-a86110a48aa8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In Kotlin, efficiently handling collections is important when working with large datasets or performing multiple transformations. One tool Kotlin offers for these situations is <strong>sequences</strong>, which allow lazy evaluation to reduce memory usage and improve performance.</p>
<p>In this article, we'll look at how to use sequences with multiple filtering criteria, focusing on situations where we want to process a list efficiently.</p>
<h3 id="heading-what-are-sequences-in-kotlin">What Are Sequences in Kotlin?</h3>
<p>A <strong>sequence</strong> in Kotlin is a type of collection that uses <strong>lazy evaluation</strong>. Unlike regular collections like <code>List</code> or <code>Set</code>, sequences don't create intermediate results. Instead, transformations like <code>map</code> or <code>filter</code> are only applied when a final operation like <code>toList</code> or <code>toSet</code> is called.</p>
<blockquote>
<h3 id="heading-this-lazy-approach-makes-sequences-great-for-handling-large-datasets-or-when-you-need-to-perform-several-transformations-as-they-use-less-memory-and-run-faster">This lazy approach makes sequences great for handling large datasets or when you need to perform several transformations, as they use less memory and run faster.</h3>
</blockquote>
<h3 id="heading-example-use-case-complex-filtering-with-sequences">Example Use Case: Complex Filtering with Sequences</h3>
<p>Let's consider a scenario where we have a list of skills, and we need to:</p>
<ol>
<li><p>Extract the <code>id</code> of each skill.</p>
</li>
<li><p>Apply multiple filtering criteria.</p>
</li>
<li><p>Convert the filtered IDs into a <code>Set</code> for quick lookup.</p>
</li>
</ol>
<p>Here's how we can accomplish this using sequences:</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Sample data class and input list</span>
<span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Skill</span></span>(<span class="hljs-keyword">val</span> id: <span class="hljs-built_in">Int</span>, <span class="hljs-keyword">val</span> name: String, <span class="hljs-keyword">val</span> isActive: <span class="hljs-built_in">Boolean</span>, <span class="hljs-keyword">val</span> proficiency: <span class="hljs-built_in">Int</span>, <span class="hljs-keyword">val</span> category: String)

<span class="hljs-keyword">val</span> skillsList = listOf(
    Skill(<span class="hljs-number">1</span>, <span class="hljs-string">"Kotlin"</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"Programming"</span>),
    Skill(<span class="hljs-number">2</span>, <span class="hljs-string">"Java"</span>, <span class="hljs-literal">false</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Programming"</span>),
    Skill(<span class="hljs-number">3</span>, <span class="hljs-string">"Python"</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">3</span>, <span class="hljs-string">"Programming"</span>),
    Skill(<span class="hljs-number">4</span>, <span class="hljs-string">"JavaScript"</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Web Development"</span>),
    Skill(<span class="hljs-number">5</span>, <span class="hljs-string">"HTML"</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">2</span>, <span class="hljs-string">"Web Development"</span>),
    Skill(<span class="hljs-number">6</span>, <span class="hljs-string">"CSS"</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">3</span>, <span class="hljs-string">"Web Development"</span>),
    Skill(<span class="hljs-number">7</span>, <span class="hljs-string">"SQL"</span>, <span class="hljs-literal">false</span>, <span class="hljs-number">4</span>, <span class="hljs-string">"Database"</span>),
    Skill(<span class="hljs-number">8</span>, <span class="hljs-string">"MongoDB"</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">3</span>, <span class="hljs-string">"Database"</span>)
)

<span class="hljs-comment">// Processing the list with sequences</span>
<span class="hljs-keyword">val</span> filteredIds = skillsList
    .asSequence() <span class="hljs-comment">// Convert to a sequence for lazy processing</span>
    .filter { it.isActive } <span class="hljs-comment">// Filter active skills</span>
    .filter { it.proficiency &gt;= <span class="hljs-number">4</span> } <span class="hljs-comment">// Filter by proficiency level (e.g., 4 or higher)</span>
    .filter { it.category == <span class="hljs-string">"Programming"</span> } <span class="hljs-comment">// Additional filter for the "Programming" category</span>
    .map { it.id } <span class="hljs-comment">// Extract the IDs</span>
    .toSet() <span class="hljs-comment">// Terminal operation to produce a Set</span>

println(filteredIds) <span class="hljs-comment">// Output: [1]</span>
</code></pre>
<h3 id="heading-step-by-step-explanation">Step-by-Step Explanation</h3>
<ul>
<li><p><code>asSequence()</code>: Turns the <code>skillsList</code> into a sequence, allowing lazy evaluation for the next steps. This prevents creating extra collections during transformations.</p>
</li>
<li><p><code>filter { it.isActive }</code>: Keeps only the active skills (<code>isActive == true</code>) in the sequence.</p>
</li>
<li><p><code>filter { it.proficiency &gt;= 4 }</code>: Adds another filter to keep only skills with a proficiency level of 4 or higher.</p>
</li>
<li><p><code>filter { it.category == "Programming" }</code>: Further limits the results to skills in the "Programming" category.</p>
</li>
<li><p><code>map { it.id }</code>: Changes the filtered sequence by pulling out the <code>id</code> of each skill.</p>
</li>
<li><p><code>toSet()</code>: Gathers the resulting <code>id</code>s into a <code>Set</code>, ensuring they are unique and easy to look up.</p>
</li>
</ul>
<h3 id="heading-why-use-sequences">Why Use Sequences?</h3>
<p>Using sequences in this scenario is beneficial for several reasons:</p>
<ul>
<li><p><strong>Memory Efficiency</strong>: Without <code>asSequence()</code>, each transformation (like <code>filter</code> or <code>map</code>) creates an intermediate collection, using more memory. Sequences avoid this by applying transformations lazily.</p>
</li>
<li><p><strong>Performance Optimization</strong>: For large datasets, sequences reduce the number of iterations by combining transformations and applying them only when needed.</p>
</li>
<li><p><strong>Flexibility with Complex Pipelines</strong>: Sequences are perfect for pipelines with multiple transformations, as they make it easy to chain operations without worrying about intermediate collections.</p>
</li>
</ul>
<h3 id="heading-when-not-to-use-sequences">When Not to Use Sequences</h3>
<p>While sequences are powerful, they are not always the best choice. Avoid using sequences when:</p>
<ul>
<li><p>The dataset is small, as the overhead of creating a sequence might outweigh the benefits of lazy evaluation.</p>
</li>
<li><p>You need to access elements multiple times, as sequences process elements only once.</p>
</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<blockquote>
<h3 id="heading-kotlin-sequences-are-a-useful-tool-for-processing-collections-efficiently-especially-with-large-datasets-or-complex-transformation-pipelines-by-using-lazy-evaluation-sequences-help-lower-memory-use-and-boost-performance">Kotlin sequences are a useful tool for processing collections efficiently, especially with large datasets or complex transformation pipelines. By using lazy evaluation, sequences help lower memory use and boost performance.</h3>
</blockquote>
<p>In our example, we showed how to filter and process a list of skills using sequences and multiple criteria, leading to a compact and efficient solution. Use sequences in your Kotlin projects to manage complex data operations easily!</p>
<hr />
<p>That’s it for today. Happy Coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Network Security in Android: A Comprehensive Guide [PART 4]]]></title><description><![CDATA[Network security is critical for protecting the communication between your Android app and remote servers. Without proper security measures, sensitive data like user credentials, personal information, or financial details can be intercepted, altered,...]]></description><link>https://rommansabbir.com/network-security-in-android-a-comprehensive-guide-part-4</link><guid isPermaLink="true">https://rommansabbir.com/network-security-in-android-a-comprehensive-guide-part-4</guid><category><![CDATA[certificatepinning]]></category><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Android Studio]]></category><category><![CDATA[android apps]]></category><category><![CDATA[networking]]></category><category><![CDATA[network]]></category><category><![CDATA[TLS]]></category><category><![CDATA[SSL/TLS]]></category><category><![CDATA[okhttp]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[vpn]]></category><category><![CDATA[encryption]]></category><category><![CDATA[communication]]></category><category><![CDATA[server]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Mon, 11 Nov 2024 15:20:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730046527685/d96ed152-959d-477a-bc5b-286796bc00c8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Network security is critical for protecting the communication between your Android app and remote servers. Without proper security measures, sensitive data like user credentials, personal information, or financial details can be intercepted, altered, or stolen. This article covers key strategies for securing network communications, including <strong>Transport Layer Security (TLS)</strong>, <strong>Certificate Pinning</strong>, <strong>VPN Support</strong>, and <strong>Firewall &amp; Intrusion Detection System (IDS) Integration</strong>. Each section includes explanations, real-life use cases, and Kotlin examples to help you implement these practices in your Android applications.</p>
<hr />
<h3 id="heading-tls-transport-layer-security-encrypted-communication-over-the-network"><strong>TLS (Transport Layer Security): Encrypted Communication Over the Network</strong></h3>
<p><strong>TLS</strong> (formerly known as SSL) is a cryptographic protocol that ensures secure data transmission over the internet. It encrypts the data being transferred, preventing unauthorized access or tampering by third parties. TLS is a standard security protocol that every Android app should implement to secure communication between the client (app) and the server.</p>
<h4 id="heading-use-case-encrypted-data-transmission"><strong>Use Case: Encrypted Data Transmission</strong></h4>
<p>When an Android app sends sensitive data, such as login credentials or user information, over the network, using TLS ensures that the data is encrypted and secure. This prevents attackers from reading or tampering with the information as it travels across the network.</p>
<h4 id="heading-kotlin-example-enforcing-tlsssl-for-network-requests"><strong>Kotlin Example: Enforcing TLS/SSL for Network Requests</strong></h4>
<p>Android’s <strong>OkHttp</strong> library supports TLS out of the box. You can configure it to enforce secure communication by ensuring that the connection uses HTTPS (which runs on top of TLS).</p>
<ol>
<li>Add the OkHttp dependency to your <code>build.gradle</code> file:</li>
</ol>
<pre><code class="lang-kotlin">implementation(<span class="hljs-string">"com.squareup.okhttp3:okhttp:4.9.1"</span>)
</code></pre>
<ol start="2">
<li>Configure OkHttp to make a secure request:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> okhttp3.OkHttpClient
<span class="hljs-keyword">import</span> okhttp3.Request
<span class="hljs-keyword">import</span> java.io.IOException

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">makeSecureRequest</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> client = OkHttpClient()

    <span class="hljs-keyword">val</span> request = Request.Builder()
        .url(<span class="hljs-string">"https://yourserver.com/api"</span>)
        .build()

    client.newCall(request).execute().use { response -&gt;
        <span class="hljs-keyword">if</span> (!response.isSuccessful) <span class="hljs-keyword">throw</span> IOException(<span class="hljs-string">"Unexpected code <span class="hljs-variable">$response</span>"</span>)

        <span class="hljs-comment">// Handle the secure response</span>
    }
}
</code></pre>
<p>In this example, OkHttp automatically negotiates the TLS handshake when connecting to the server via HTTPS. If the server doesn’t support TLS, the request will fail, ensuring that the communication is secure.</p>
<h4 id="heading-real-life-example-secure-api-communication"><strong>Real-Life Example: Secure API Communication</strong></h4>
<p>Most mobile apps that communicate with a backend API use TLS to encrypt data. For example, a health app that transmits medical records or a banking app transferring financial data must use TLS to ensure that sensitive information is not intercepted or altered during transit.</p>
<hr />
<h3 id="heading-certificate-pinning-preventing-man-in-the-middle-attacks"><strong>Certificate Pinning: Preventing Man-in-the-Middle Attacks</strong></h3>
<p><strong>Certificate Pinning</strong> is a security technique that helps prevent <strong>man-in-the-middle (MITM) attacks</strong> by ensuring that the app communicates only with trusted servers using a specific SSL certificate. Instead of trusting any certificate issued by a valid certificate authority (CA), certificate pinning allows you to pin your app to a specific certificate or public key, ensuring that the communication is with a legitimate server and has not been tampered with.</p>
<h4 id="heading-use-case-securing-server-communication"><strong>Use Case: Securing Server Communication</strong></h4>
<p>An app that handles sensitive data, such as financial transactions, must ensure that it is communicating with the intended server. Certificate pinning prevents attackers from intercepting traffic and spoofing the server by using fraudulent certificates.</p>
<h4 id="heading-kotlin-example-implementing-certificate-pinning-with-okhttp"><strong>Kotlin Example: Implementing Certificate Pinning with OkHttp</strong></h4>
<ol>
<li><p>First, get the public key or certificate that you want to pin. In this example, we’ll pin the public key of the server’s SSL certificate.</p>
</li>
<li><p>Configure OkHttp with certificate pinning:</p>
</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> okhttp3.CertificatePinner
<span class="hljs-keyword">import</span> okhttp3.OkHttpClient
<span class="hljs-keyword">import</span> okhttp3.Request

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setupCertificatePinning</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> certificatePinner = CertificatePinner.Builder()
        .add(<span class="hljs-string">"yourserver.com"</span>, <span class="hljs-string">"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="</span>)
        .build()

    <span class="hljs-keyword">val</span> client = OkHttpClient.Builder()
        .certificatePinner(certificatePinner)
        .build()

    <span class="hljs-keyword">val</span> request = Request.Builder()
        .url(<span class="hljs-string">"https://yourserver.com/api"</span>)
        .build()

    client.newCall(request).execute().use { response -&gt;
        <span class="hljs-keyword">if</span> (!response.isSuccessful) <span class="hljs-keyword">throw</span> IOException(<span class="hljs-string">"Unexpected code <span class="hljs-variable">$response</span>"</span>)

        <span class="hljs-comment">// Handle the response</span>
    }
}
</code></pre>
<p>In this example, <strong>CertificatePinner</strong> is used to enforce that only a specific certificate with the provided SHA-256 public key hash is accepted when connecting to the server.</p>
<h4 id="heading-real-life-example-secure-banking-app"><strong>Real-Life Example: Secure Banking App</strong></h4>
<p>A banking app that communicates with a remote server to handle user transactions should implement certificate pinning to ensure that the connection cannot be intercepted by an attacker using a fraudulent certificate. This adds an extra layer of security to the communication between the app and the server.</p>
<hr />
<h3 id="heading-vpn-support-secure-network-communication"><strong>VPN Support: Secure Network Communication</strong></h3>
<p><strong>VPNs (Virtual Private Networks)</strong> provide a secure and encrypted connection over a less secure network, such as the internet. VPNs are often used to protect sensitive data and prevent unauthorized access to network traffic. Implementing VPN support in your app or working with VPN providers can ensure that all network communication is encrypted and secure.</p>
<h4 id="heading-use-case-enhancing-security-in-public-networks"><strong>Use Case: Enhancing Security in Public Networks</strong></h4>
<p>Users who connect to your app over public Wi-Fi networks are vulnerable to attacks like packet sniffing or man-in-the-middle attacks. VPNs create a secure tunnel for communication, ensuring that data remains private even on insecure networks.</p>
<h4 id="heading-kotlin-example-launching-a-vpn-service-in-android"><strong>Kotlin Example: Launching a VPN Service in Android</strong></h4>
<p>Android provides built-in support for creating VPN connections via the <strong>VpnService</strong> class. Below is a basic example of how to start a VPN service in your Android app.</p>
<ol>
<li>Create a VPN Service by extending <code>VpnService</code>:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> android.app.Service
<span class="hljs-keyword">import</span> android.content.Intent
<span class="hljs-keyword">import</span> android.net.VpnService

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyVpnService</span> : <span class="hljs-type">VpnService</span></span>() {
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onStartCommand</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>?, flags: <span class="hljs-type">Int</span>, startId: <span class="hljs-type">Int</span>)</span></span>: <span class="hljs-built_in">Int</span> {
        <span class="hljs-comment">// Setup VPN connection here</span>
        <span class="hljs-keyword">return</span> Service.START_STICKY
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onDestroy</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onDestroy()
        <span class="hljs-comment">// Clean up VPN connection</span>
    }
}
</code></pre>
<ol start="2">
<li>Request VPN permissions in your <code>AndroidManifest.xml</code>:</li>
</ol>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">service</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">".MyVpnService"</span>
    <span class="hljs-attr">android:permission</span>=<span class="hljs-string">"android.permission.BIND_VPN_SERVICE"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">intent-filter</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">action</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.net.VpnService"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">intent-filter</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">service</span>&gt;</span>
</code></pre>
<ol start="3">
<li>Launch the VPN service from your app:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> vpnIntent = VpnService.prepare(<span class="hljs-keyword">this</span>)
<span class="hljs-keyword">if</span> (vpnIntent != <span class="hljs-literal">null</span>) {
    startActivityForResult(vpnIntent, VPN_REQUEST_CODE)
} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Already prepared, start VPN service directly</span>
    startService(Intent(<span class="hljs-keyword">this</span>, MyVpnService::<span class="hljs-keyword">class</span>.java))
}
</code></pre>
<p>In this example, <strong>VpnService</strong> is used to create a secure VPN connection. The VPN service can be configured to tunnel all network traffic securely.</p>
<h4 id="heading-real-life-example-privacy-focused-apps"><strong>Real-Life Example: Privacy-Focused Apps</strong></h4>
<p>Apps focused on privacy, like secure messaging or financial apps, can benefit from integrating VPN support to ensure that user data remains private, even when users are connected to insecure public networks.</p>
<hr />
<h3 id="heading-firewall-amp-ids-integration-traffic-filtering-and-intrusion-detection"><strong>Firewall &amp; IDS Integration: Traffic Filtering and Intrusion Detection</strong></h3>
<p>A <strong>Firewall</strong> is a network security system that monitors and controls incoming and outgoing traffic based on predefined security rules. An <strong>Intrusion Detection System (IDS)</strong> helps detect potential malicious activities or policy violations within a network. Combining firewall rules and IDS can significantly enhance the security of your app by filtering out unwanted traffic and detecting suspicious network activities.</p>
<h4 id="heading-use-case-blocking-malicious-traffic"><strong>Use Case: Blocking Malicious Traffic</strong></h4>
<p>By using firewall rules, your app can restrict access to certain IP addresses or domains, preventing malicious traffic from reaching your app. Additionally, integrating an IDS can help detect and alert suspicious activities, such as DDoS attacks or unauthorized access attempts.</p>
<h4 id="heading-firewall-example-creating-traffic-filtering-rules"><strong>Firewall Example: Creating Traffic Filtering Rules</strong></h4>
<p>While Android does not provide built-in APIs for configuring firewalls directly, you can create custom network policies in your backend or use a third-party service to filter network traffic. Here is an example of creating firewall-like rules at the application level:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> okhttp3.Interceptor
<span class="hljs-keyword">import</span> okhttp3.OkHttpClient
<span class="hljs-keyword">import</span> okhttp3.Request

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setupNetworkFiltering</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> networkInterceptor = Interceptor { chain -&gt;
        <span class="hljs-keyword">val</span> request: Request = chain.request()

        <span class="hljs-comment">// Example: Block requests to a specific domain</span>
        <span class="hljs-keyword">if</span> (request.url.host == <span class="hljs-string">"malicious.com"</span>) {
            <span class="hljs-keyword">throw</span> IOException(<span class="hljs-string">"Blocked by firewall"</span>)
        }

        <span class="hljs-keyword">return</span><span class="hljs-symbol">@Interceptor</span> chain.proceed(request)
    }

    <span class="hljs-keyword">val</span> client = OkHttpClient.Builder()
        .addInterceptor(networkInterceptor)
        .build()
}
</code></pre>
<p>This code snippet demonstrates how to block network requests to a specific domain at the app level using OkHttp’s <strong>Interceptor</strong>.</p>
<h4 id="heading-real-life-example-securing-apis"><strong>Real-Life Example: Securing APIs</strong></h4>
<p>An enterprise app that accesses sensitive data might have firewall rules in place to restrict access to only known IP addresses or domains. For example, an internal business app might restrict access to only trusted company networks, while blocking external traffic.</p>
<hr />
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Network security is a critical component of any Android application, especially those that handle sensitive user data or perform financial transactions. <strong>TLS</strong> ensures encrypted communication between the app and the server, while <strong>Certificate Pinning</strong> prevents man-in-the-middle attacks. <strong>VPN Support</strong> can help secure network communication on public networks, and integrating <strong>Firewall &amp; IDS</strong> provides an additional layer of protection by filtering traffic and detecting malicious activities.</p>
<p>By implementing these network security measures, you can ensure that your Android app remains secure and that sensitive user data is protected from potential threats.</p>
<hr />
<p>That’s it for today. Happy coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Application Security in Android: A Comprehensive Guide [PART 3]]]></title><description><![CDATA[Application security is essential for preventing unauthorized access, reverse engineering, and tampering with your Android apps. There are several strategies and tools that developers can employ to protect their applications from these threats. In th...]]></description><link>https://rommansabbir.com/application-security-in-android-a-comprehensive-guide-part-3</link><guid isPermaLink="true">https://rommansabbir.com/application-security-in-android-a-comprehensive-guide-part-3</guid><category><![CDATA[rooted]]></category><category><![CDATA[app signing]]></category><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[android apps]]></category><category><![CDATA[Android Studio]]></category><category><![CDATA[proguard]]></category><category><![CDATA[r8]]></category><category><![CDATA[code shrinking]]></category><category><![CDATA[obfuscation]]></category><category><![CDATA[apk]]></category><category><![CDATA[authentication]]></category><category><![CDATA[safety-net]]></category><category><![CDATA[google play]]></category><category><![CDATA[compromised]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Fri, 08 Nov 2024 11:46:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730046762878/1503b00b-61ba-4233-8161-6095b35212fe.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Application security is essential for preventing unauthorized access, reverse engineering, and tampering with your Android apps. There are several strategies and tools that developers can employ to protect their applications from these threats. In this article, we will explore <strong>ProGuard/R8</strong> for code obfuscation, <strong>App Signing</strong> for validating authenticity, the <strong>SafetyNet Integrity Check</strong> to detect compromised devices, and <strong>Google Play App Signing</strong> for managing signing keys. Each section provides detailed explanations, real-life examples, and Kotlin code snippets to help you implement these security practices.</p>
<hr />
<h3 id="heading-proguardr8-code-obfuscation-and-shrinking"><strong>ProGuard/R8: Code Obfuscation and Shrinking</strong></h3>
<p><strong>ProGuard</strong> and <strong>R8</strong> are tools that help reduce the size of your APK and obscure your code to prevent reverse engineering. These tools minify, optimize, and obfuscate the code, making it harder for attackers to analyze the logic of your app.</p>
<ul>
<li><p><strong>ProGuard</strong>: Originally, ProGuard was used to shrink and obfuscate the app's bytecode. It also removes unused code and resources, optimizing the app size.</p>
</li>
<li><p><strong>R8</strong>: As of Android Gradle Plugin 3.4.0, R8 replaces ProGuard by default. It combines shrinking, obfuscation, and optimization in a single step, with better performance than ProGuard.</p>
</li>
</ul>
<h4 id="heading-use-case-preventing-reverse-engineering"><strong>Use Case: Preventing Reverse Engineering</strong></h4>
<p>When your Android app contains sensitive code, such as proprietary algorithms, encrypting logic, or API keys, it is crucial to obscure that code to prevent attackers from reverse-engineering it.</p>
<h4 id="heading-kotlin-example-configuring-r8proguard"><strong>Kotlin Example: Configuring R8/ProGuard</strong></h4>
<ol>
<li>Enable R8 in your project (this is the default in newer versions of Android Studio). You can customize your R8 rules by editing the <a target="_blank" href="http://proguard-rules.pro"><code>proguard-rules.pro</code></a> file.</li>
</ol>
<pre><code class="lang-kotlin"># Preserve <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">names</span> <span class="hljs-title">for</span> <span class="hljs-title">debugging</span> <span class="hljs-title">purposes</span></span>
-keep <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">com</span>.<span class="hljs-title">example</span>.<span class="hljs-title">myapp</span>.** </span>{ *; }

# Remove logging
-assumenosideeffects <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">android</span>.<span class="hljs-title">util</span>.<span class="hljs-title">Log</span> </span>{
    <span class="hljs-keyword">public</span> static *** d(...);
    <span class="hljs-keyword">public</span> static *** v(...);
}
</code></pre>
<ol start="2">
<li>To enable code shrinking and obfuscation, add the following to your <code>build.gradle</code> file:</li>
</ol>
<pre><code class="lang-kotlin">android {
    buildTypes {
        release {
            minifyEnabled <span class="hljs-literal">true</span> <span class="hljs-comment">// Enable shrinking and obfuscation</span>
            proguardFiles getDefaultProguardFile(<span class="hljs-string">'proguard-android-optimize.txt'</span>), <span class="hljs-string">'proguard-rules.pro'</span>
        }
    }
}
</code></pre>
<h4 id="heading-real-life-example-banking-apps"><strong>Real-Life Example: Banking Apps</strong></h4>
<p>Banking apps often contain sensitive logic for handling transactions, encryption algorithms, and user data. Obfuscating the code using ProGuard or R8 makes it much harder for attackers to decompile the APK and understand how these processes work.</p>
<hr />
<h3 id="heading-app-signing-validating-the-authenticity-of-your-app"><strong>App Signing: Validating the Authenticity of Your App</strong></h3>
<p><strong>App Signing</strong> is the process of using a cryptographic key to sign your APK or AAB (Android App Bundle) before distributing it. Signing the app ensures its authenticity and integrity, as the signature is used by the system to verify that the APK has not been tampered with.</p>
<h4 id="heading-use-case-securing-app-distribution"><strong>Use Case: Securing App Distribution</strong></h4>
<p>When you release an Android app, signing it is required to publish it on the Google Play Store. This signature verifies the source of the APK, ensuring users are downloading a legitimate version of the app. If the app isn’t signed, the Android operating system won’t install it.</p>
<h4 id="heading-steps-for-app-signing-in-android-studio"><strong>Steps for App Signing in Android Studio</strong></h4>
<ol>
<li><p><strong>Generate a Signing Key</strong>: In Android Studio, go to <strong>Build &gt; Generate Signed Bundle / APK</strong> and follow the steps to create a keystore file and generate a private key.</p>
</li>
<li><p><strong>Configure App Signing in</strong> <code>build.gradle</code>:</p>
</li>
</ol>
<pre><code class="lang-kotlin">android {
    signingConfigs {
        release {
            storeFile file(<span class="hljs-string">"keystore.jks"</span>)
            storePassword <span class="hljs-string">"your-store-password"</span>
            keyAlias <span class="hljs-string">"your-key-alias"</span>
            keyPassword <span class="hljs-string">"your-key-password"</span>
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
</code></pre>
<ol start="3">
<li><strong>Sign and Publish</strong>: After signing your APK, you can publish it to Google Play or distribute it directly. The system will verify the signature upon installation.</li>
</ol>
<h4 id="heading-real-life-example-app-stores"><strong>Real-Life Example: App Stores</strong></h4>
<p>Every Android app published to the Google Play Store is required to be signed. This prevents malicious actors from modifying apps and re-distributing them without the developer’s consent.</p>
<hr />
<h3 id="heading-integrity-check-safetynet-api-detecting-rooted-or-compromised-devices"><strong>Integrity Check (SafetyNet API): Detecting Rooted or Compromised Devices</strong></h3>
<p>Google’s <strong>SafetyNet API</strong> is a security feature that helps detect whether the device running your app has been compromised, such as through rooting or other tampering methods. SafetyNet provides an <strong>attestation API</strong>, which you can use to determine whether the device passes security checks. This is especially important for apps dealing with sensitive data, like financial apps or secure messaging apps.</p>
<h4 id="heading-use-case-blocking-access-on-compromised-devices"><strong>Use Case: Blocking Access on Compromised Devices</strong></h4>
<p>You might want to block or limit access to certain features if the device is rooted or compromised. For example, a banking app might not allow a user to initiate transactions if the device is not secure.</p>
<h4 id="heading-kotlin-example-implementing-safetynet-attestation"><strong>Kotlin Example: Implementing SafetyNet Attestation</strong></h4>
<ol>
<li>Add the necessary dependencies to your <code>build.gradle</code> file:</li>
</ol>
<pre><code class="lang-kotlin">implementation <span class="hljs-string">'com.google.android.gms:play-services-safetynet:18.0.1'</span>
</code></pre>
<ol start="2">
<li>Use the SafetyNet API to check the device’s integrity:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> com.google.android.gms.safetynet.SafetyNet
<span class="hljs-keyword">import</span> com.google.android.gms.tasks.OnSuccessListener
<span class="hljs-keyword">import</span> com.google.android.gms.tasks.OnFailureListener

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">checkDeviceIntegrity</span><span class="hljs-params">()</span></span> {
    SafetyNet.getClient(<span class="hljs-keyword">this</span>).attest(nonce, getApiKey())
        .addOnSuccessListener(OnSuccessListener { response -&gt;
            <span class="hljs-comment">// Process the attestation result</span>
            <span class="hljs-keyword">val</span> jwtToken = response.jwsResult
            <span class="hljs-comment">// Verify the JWT response on your server to determine the integrity of the device</span>
        })
        .addOnFailureListener(OnFailureListener { e -&gt;
            <span class="hljs-comment">// Handle error</span>
        })
}
</code></pre>
<p>In this example, <strong>nonce</strong> is a random value generated to ensure that the attestation request is fresh, and <strong>getApiKey()</strong> returns your SafetyNet API key. The response contains a <strong>JWT token</strong> that you can verify on your server to determine the integrity of the device.</p>
<h4 id="heading-real-life-example-financial-services"><strong>Real-Life Example: Financial Services</strong></h4>
<p>A financial app can use the SafetyNet attestation API to block access to payment features if the device fails the integrity check, ensuring that users cannot perform transactions from compromised devices.</p>
<hr />
<h3 id="heading-google-play-app-signing-secure-key-management"><strong>Google Play App Signing: Secure Key Management</strong></h3>
<p><strong>Google Play App Signing</strong> is a service provided by Google Play that helps manage and secure your app signing keys. Instead of managing your signing keys manually, you can opt into Google Play App Signing, where Google securely stores your signing key and signs your APKs on your behalf when you upload them to the Play Store.</p>
<h4 id="heading-use-case-protecting-your-signing-key"><strong>Use Case: Protecting Your Signing Key</strong></h4>
<p>Managing your own app signing keys can be risky, especially if they are lost or compromised. With Google Play App Signing, Google manages your signing keys securely, ensuring that even if you lose your local copy of the key, your app can still be updated and maintained.</p>
<h4 id="heading-steps-to-enable-google-play-app-signing"><strong>Steps to Enable Google Play App Signing</strong></h4>
<ol>
<li><p>When publishing your app to Google Play for the first time, you will be given the option to enroll in Google Play App Signing.</p>
</li>
<li><p>If you opt in, you will upload an unsigned APK or AAB, and Google will take care of signing it with the stored key.</p>
</li>
<li><p>Once enrolled, you don’t need to worry about key storage, and Google provides a way to securely manage keys for updates.</p>
</li>
</ol>
<h4 id="heading-real-life-example-app-development-companies"><strong>Real-Life Example: App Development Companies</strong></h4>
<p>Many app development companies with large app portfolios rely on Google Play App Signing to handle key management securely, especially when multiple teams are working on the same app. This also ensures that the signing key remains safe even if there are changes in the development team or processes.</p>
<hr />
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Securing your Android applications is essential to protect users’ data, ensure the integrity of your app, and prevent tampering. <strong>ProGuard/R8</strong> helps to obfuscate your code, making it harder for attackers to reverse-engineer your app. <strong>App Signing</strong> guarantees the authenticity of your app, while <strong>SafetyNet Integrity Check</strong> detects if the app is running on a compromised device. Finally, <strong>Google Play App Signing</strong> simplifies key management by securely storing and managing signing keys.</p>
<p>By implementing these techniques, you can enhance the security of your app and provide a safe experience for your users, ensuring that their data and your app remain protected from malicious actors.</p>
<hr />
<p>That’s it today. Happy coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Secure User Authentication in Android: A Comprehensive Guide [PART 2]]]></title><description><![CDATA[User authentication is one of the most critical security aspects of any mobile application. Implementing secure authentication methods ensures that users’ data and accounts are protected from unauthorized access. In this article, we will dive deep in...]]></description><link>https://rommansabbir.com/secure-user-authentication-in-android-a-comprehensive-guide-part-2</link><guid isPermaLink="true">https://rommansabbir.com/secure-user-authentication-in-android-a-comprehensive-guide-part-2</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Security]]></category><category><![CDATA[user]]></category><category><![CDATA[authentication]]></category><category><![CDATA[OAuth 2.0]]></category><category><![CDATA[encryption algorithms]]></category><category><![CDATA[encryption]]></category><category><![CDATA[biometrics]]></category><category><![CDATA[biometric authentication]]></category><category><![CDATA[OpenID Connect]]></category><category><![CDATA[openid]]></category><category><![CDATA[token]]></category><category><![CDATA[TokenBasedAuthentication]]></category><category><![CDATA[Google]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Sat, 02 Nov 2024 11:21:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730046620546/0c354b05-fa92-4c44-a42f-fd2ec9566df9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>User authentication is one of the most critical security aspects of any mobile application. Implementing secure authentication methods ensures that users’ data and accounts are protected from unauthorized access. In this article, we will dive deep into several techniques for implementing secure user authentication in Android, including <strong>Biometric Authentication (Fingerprint and Face)</strong>, <strong>OAuth 2.0 &amp; OpenID Connect</strong>, and <strong>Secure Password Storage</strong>. We’ll provide real-life examples and Kotlin code snippets for each method to help you integrate them into your Android apps.</p>
<hr />
<h3 id="heading-biometric-api-secure-authentication-with-fingerprint-and-face-recognition"><strong>Biometric API: Secure Authentication with Fingerprint and Face Recognition</strong></h3>
<p>Biometric authentication uses physical traits like fingerprints or facial recognition to authenticate users. This provides a more secure and convenient login experience compared to traditional password-based authentication, as biometrics are unique to each individual.</p>
<h4 id="heading-use-case-implementing-fingerprint-or-face-authentication"><strong>Use Case: Implementing Fingerprint or Face Authentication</strong></h4>
<p>You can integrate the <strong>BiometricPrompt</strong> API in your Android app to allow users to authenticate using their fingerprint or face. This is particularly useful for apps where convenience and security are essential, such as banking apps, medical records, or any app handling sensitive data.</p>
<h4 id="heading-kotlin-example-using-biometric-authentication"><strong>Kotlin Example: Using Biometric Authentication</strong></h4>
<ol>
<li>Add the biometric dependency to your app’s <code>build.gradle</code> file:</li>
</ol>
<pre><code class="lang-kotlin">implementation <span class="hljs-string">'androidx.biometric:biometric:1.2.0-alpha05'</span>
</code></pre>
<ol start="2">
<li>Implement biometric authentication in your app:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> androidx.biometric.BiometricManager
<span class="hljs-keyword">import</span> androidx.biometric.BiometricPrompt
<span class="hljs-keyword">import</span> androidx.core.content.ContextCompat

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showBiometricPrompt</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> executor = ContextCompat.getMainExecutor(<span class="hljs-keyword">this</span>)
    <span class="hljs-keyword">val</span> biometricPrompt = BiometricPrompt(<span class="hljs-keyword">this</span>, executor, <span class="hljs-keyword">object</span> : BiometricPrompt.AuthenticationCallback() {
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAuthenticationSucceeded</span><span class="hljs-params">(result: <span class="hljs-type">BiometricPrompt</span>.<span class="hljs-type">AuthenticationResult</span>)</span></span> {
            <span class="hljs-comment">// Authentication succeeded, proceed with login</span>
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAuthenticationError</span><span class="hljs-params">(errorCode: <span class="hljs-type">Int</span>, errString: <span class="hljs-type">CharSequence</span>)</span></span> {
            <span class="hljs-comment">// Handle error</span>
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAuthenticationFailed</span><span class="hljs-params">()</span></span> {
            <span class="hljs-comment">// Handle failure</span>
        }
    })

    <span class="hljs-keyword">val</span> promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle(<span class="hljs-string">"Biometric Authentication"</span>)
        .setSubtitle(<span class="hljs-string">"Use your fingerprint or face to login"</span>)
        .setNegativeButtonText(<span class="hljs-string">"Use password"</span>)
        .build()

    biometricPrompt.authenticate(promptInfo)
}
</code></pre>
<p>In this example, we use <strong>BiometricPrompt</strong> to prompt the user to authenticate using a fingerprint or facial recognition. If the biometric data matches, the user is authenticated successfully.</p>
<h4 id="heading-real-life-example-banking-app"><strong>Real-Life Example: Banking App</strong></h4>
<p>In a banking app, users can log in using their fingerprint or face for quicker access to their accounts, without needing to type a password each time. This not only enhances security but also improves user experience.</p>
<hr />
<h3 id="heading-oauth-20-amp-openid-connect-secure-token-based-authentication"><strong>OAuth 2.0 &amp; OpenID Connect: Secure Token-Based Authentication</strong></h3>
<p><strong>OAuth 2.0</strong> and <strong>OpenID Connect</strong> are widely used frameworks for authentication and authorization, especially when an app needs to interact with external services like Google, Facebook, or custom APIs. OAuth 2.0 allows users to grant access to their data on one service without exposing their credentials, while OpenID Connect adds an identity layer on top of OAuth 2.0 for authentication.</p>
<h4 id="heading-use-case-logging-in-with-google-or-facebook"><strong>Use Case: Logging in with Google or Facebook</strong></h4>
<p>Many apps use OAuth 2.0 to allow users to log in using their Google or Facebook accounts, which not only simplifies the login process but also improves security by avoiding the need for password management.</p>
<h4 id="heading-kotlin-example-google-sign-in-using-oauth-20"><strong>Kotlin Example: Google Sign-In Using OAuth 2.0</strong></h4>
<ol>
<li>Add the Google Sign-In dependency to your <code>build.gradle</code> file:</li>
</ol>
<pre><code class="lang-kotlin">implementation <span class="hljs-string">'com.google.android.gms:play-services-auth:20.2.0'</span>
</code></pre>
<ol start="2">
<li>Set up Google Sign-In in your app:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> com.google.android.gms.auth.api.signin.GoogleSignIn
<span class="hljs-keyword">import</span> com.google.android.gms.auth.api.signin.GoogleSignInAccount
<span class="hljs-keyword">import</span> com.google.android.gms.auth.api.signin.GoogleSignInClient
<span class="hljs-keyword">import</span> com.google.android.gms.auth.api.signin.GoogleSignInOptions
<span class="hljs-keyword">import</span> com.google.android.gms.tasks.Task
<span class="hljs-keyword">import</span> android.content.Intent

<span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> googleSignInClient: GoogleSignInClient

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setupGoogleSignIn</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestEmail()
        .requestIdToken(getString(R.string.server_client_id)) <span class="hljs-comment">// For backend verification</span>
        .build()

    googleSignInClient = GoogleSignIn.getClient(<span class="hljs-keyword">this</span>, gso)
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">signInWithGoogle</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> signInIntent = googleSignInClient.signInIntent
    startActivityForResult(signInIntent, RC_SIGN_IN)
}

<span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onActivityResult</span><span class="hljs-params">(requestCode: <span class="hljs-type">Int</span>, resultCode: <span class="hljs-type">Int</span>, <span class="hljs-keyword">data</span>: <span class="hljs-type">Intent</span>?)</span></span> {
    <span class="hljs-keyword">super</span>.onActivityResult(requestCode, resultCode, <span class="hljs-keyword">data</span>)
    <span class="hljs-keyword">if</span> (requestCode == RC_SIGN_IN) {
        <span class="hljs-keyword">val</span> task: Task&lt;GoogleSignInAccount&gt; = GoogleSignIn.getSignedInAccountFromIntent(<span class="hljs-keyword">data</span>)
        handleSignInResult(task)
    }
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">handleSignInResult</span><span class="hljs-params">(completedTask: <span class="hljs-type">Task</span>&lt;<span class="hljs-type">GoogleSignInAccount</span>&gt;)</span></span> {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">val</span> account = completedTask.getResult(ApiException::<span class="hljs-keyword">class</span>.java)
        <span class="hljs-comment">// Signed in successfully, handle account data here</span>
    } <span class="hljs-keyword">catch</span> (e: ApiException) {
        <span class="hljs-comment">// Sign-in failed, handle the error</span>
    }
}
</code></pre>
<p>In this example, Google Sign-In is implemented using <strong>OAuth 2.0</strong>, where the user can log in using their Google account. The Google ID token can be passed to your server for authentication.</p>
<h4 id="heading-real-life-example-social-media-login"><strong>Real-Life Example: Social Media Login</strong></h4>
<p>In apps like Instagram, users can log in using their Facebook account via OAuth 2.0. This provides a seamless authentication process and enhances security by offloading password management to a trusted provider.</p>
<hr />
<h3 id="heading-secure-password-storage-hashing-and-salting-passwords"><strong>Secure Password Storage: Hashing and Salting Passwords</strong></h3>
<p>Storing passwords securely is essential to protect user credentials from being exposed in case of a data breach. Instead of storing plain-text passwords, they should be <strong>hashed</strong> and <strong>salted</strong>. Hashing transforms the password into a fixed-length string, while salting adds a random string to each password before hashing it, making it more resistant to attacks like rainbow table attacks.</p>
<h4 id="heading-use-case-storing-user-passwords-securely"><strong>Use Case: Storing User Passwords Securely</strong></h4>
<p>When a user creates an account in your app, their password should be securely hashed and salted before storing it in the database. This ensures that even if the database is compromised, attackers cannot easily recover the original passwords.</p>
<h4 id="heading-kotlin-example-password-hashing-using-pbkdf2"><strong>Kotlin Example: Password Hashing Using PBKDF2</strong></h4>
<ol>
<li>Hash and salt a password:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> java.security.SecureRandom
<span class="hljs-keyword">import</span> javax.crypto.SecretKeyFactory
<span class="hljs-keyword">import</span> javax.crypto.spec.PBEKeySpec
<span class="hljs-keyword">import</span> java.util.Base64

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">hashPassword</span><span class="hljs-params">(password: <span class="hljs-type">String</span>, salt: <span class="hljs-type">ByteArray</span>)</span></span>: String {
    <span class="hljs-keyword">val</span> spec = PBEKeySpec(password.toCharArray(), salt, <span class="hljs-number">10000</span>, <span class="hljs-number">256</span>) <span class="hljs-comment">// 10000 iterations</span>
    <span class="hljs-keyword">val</span> factory = SecretKeyFactory.getInstance(<span class="hljs-string">"PBKDF2WithHmacSHA256"</span>)
    <span class="hljs-keyword">val</span> hash = factory.generateSecret(spec).encoded
    <span class="hljs-keyword">return</span> Base64.getEncoder().encodeToString(hash)
}

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateSalt</span><span class="hljs-params">()</span></span>: ByteArray {
    <span class="hljs-keyword">val</span> random = SecureRandom()
    <span class="hljs-keyword">val</span> salt = ByteArray(<span class="hljs-number">16</span>)
    random.nextBytes(salt)
    <span class="hljs-keyword">return</span> salt
}
</code></pre>
<p>In this example, <strong>PBKDF2</strong> (Password-Based Key Derivation Function 2) is used to securely hash and salt the password. You can also use alternatives like <strong>bcrypt</strong> or <strong>Argon2</strong> for even better security.</p>
<ol start="2">
<li>Verify the password:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">verifyPassword</span><span class="hljs-params">(inputPassword: <span class="hljs-type">String</span>, storedHash: <span class="hljs-type">String</span>, salt: <span class="hljs-type">ByteArray</span>)</span></span>: <span class="hljs-built_in">Boolean</span> {
    <span class="hljs-keyword">val</span> inputHash = hashPassword(inputPassword, salt)
    <span class="hljs-keyword">return</span> inputHash == storedHash
}
</code></pre>
<p>Here, the input password is hashed again with the same salt, and the resulting hash is compared with the stored hash to verify if the password is correct.</p>
<h4 id="heading-real-life-example-user-account-in-e-commerce-app"><strong>Real-Life Example: User Account in E-commerce App</strong></h4>
<p>In an e-commerce app, when users create accounts, their passwords should be securely hashed and stored in the database. During login, the app verifies the password by hashing the input again and comparing it with the stored hash, ensuring that user credentials are protected even if the database is compromised.</p>
<hr />
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Implementing secure user authentication is a crucial step in building safe Android applications. The <strong>Biometric API</strong> enables seamless and secure login experiences using fingerprint or facial recognition. <strong>OAuth 2.0 &amp; OpenID Connect</strong> simplify user authentication with external services like Google and Facebook while enhancing security with token-based authentication. Finally, securely storing passwords using hashing and salting ensures that even if an attacker gains access to your database, user credentials remain protected.</p>
<p>By following these techniques, you can enhance the security of your Android app and ensure that users' data is kept safe from unauthorized access.</p>
<hr />
<p>That’s it for today. Happy coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Data Encryption in Android: A Comprehensive Guide [PART 1]]]></title><description><![CDATA[Data encryption is a fundamental part of securing mobile applications, particularly those handling sensitive information like user credentials, tokens, or files. Android provides several encryption techniques and APIs that developers can implement to...]]></description><link>https://rommansabbir.com/data-encryption-in-android-a-comprehensive-guide-part-1</link><guid isPermaLink="true">https://rommansabbir.com/data-encryption-in-android-a-comprehensive-guide-part-1</guid><category><![CDATA[file-based encryption]]></category><category><![CDATA[Android]]></category><category><![CDATA[aes]]></category><category><![CDATA[RSA]]></category><category><![CDATA[RSA Encryption]]></category><category><![CDATA[Credentials]]></category><category><![CDATA[keystore]]></category><category><![CDATA[network]]></category><category><![CDATA[Security]]></category><category><![CDATA[configuration]]></category><category><![CDATA[data encryption]]></category><category><![CDATA[cache]]></category><category><![CDATA[caching]]></category><category><![CDATA[Key exchange]]></category><category><![CDATA[asymmetric key encryption]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Mon, 28 Oct 2024 15:18:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729953069685/792b6c4b-5965-4e5c-9572-85c275f21d31.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Data encryption is a fundamental part of securing mobile applications, particularly those handling sensitive information like user credentials, tokens, or files. Android provides several encryption techniques and APIs that developers can implement to ensure the security of data both at rest and in transit. In this article, we will explore different encryption methods available in Android, including <strong>AES</strong>, <strong>RSA</strong>, the <strong>KeyStore API</strong>, <strong>File-Based Encryption (FBE)</strong>, and <strong>Network Security Configuration</strong>. We will provide explanations, real-world use cases, and Kotlin code snippets to help you implement these techniques in your Android applications.</p>
<hr />
<h3 id="heading-aes-advanced-encryption-standard"><strong>AES (Advanced Encryption Standard)</strong></h3>
<p><strong>AES</strong> is a symmetric encryption algorithm widely used to encrypt sensitive data such as user credentials, tokens, or files. Being a symmetric encryption method, it uses the same key for both encryption and decryption.</p>
<h4 id="heading-use-case-encrypting-user-credentials"><strong>Use Case: Encrypting User Credentials</strong></h4>
<p>When your app needs to store sensitive information, such as a user's password or API token, AES is a strong choice for encrypting this data before storing it locally.</p>
<h4 id="heading-kotlin-example-encrypting-data-using-aes"><strong>Kotlin Example: Encrypting Data Using AES</strong></h4>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> java.security.SecureRandom
<span class="hljs-keyword">import</span> javax.crypto.Cipher
<span class="hljs-keyword">import</span> javax.crypto.KeyGenerator
<span class="hljs-keyword">import</span> javax.crypto.SecretKey
<span class="hljs-keyword">import</span> javax.crypto.spec.GCMParameterSpec

<span class="hljs-comment">// Generate AES key</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateAESKey</span><span class="hljs-params">()</span></span>: SecretKey {
    <span class="hljs-keyword">val</span> keyGen = KeyGenerator.getInstance(<span class="hljs-string">"AES"</span>)
    keyGen.<span class="hljs-keyword">init</span>(<span class="hljs-number">256</span>) <span class="hljs-comment">// 256-bit AES key</span>
    <span class="hljs-keyword">return</span> keyGen.generateKey()
}

<span class="hljs-comment">// Encrypt data using AES</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">encryptData</span><span class="hljs-params">(<span class="hljs-keyword">data</span>: <span class="hljs-type">ByteArray</span>, secretKey: <span class="hljs-type">SecretKey</span>)</span></span>: ByteArray {
    <span class="hljs-keyword">val</span> cipher = Cipher.getInstance(<span class="hljs-string">"AES/GCM/NoPadding"</span>)
    <span class="hljs-keyword">val</span> iv = ByteArray(<span class="hljs-number">12</span>) <span class="hljs-comment">// GCM recommended IV length is 12 bytes</span>
    SecureRandom().nextBytes(iv) <span class="hljs-comment">// Generate random IV</span>
    <span class="hljs-keyword">val</span> gcmSpec = GCMParameterSpec(<span class="hljs-number">128</span>, iv)
    cipher.<span class="hljs-keyword">init</span>(Cipher.ENCRYPT_MODE, secretKey, gcmSpec)
    <span class="hljs-keyword">return</span> iv + cipher.doFinal(<span class="hljs-keyword">data</span>)
}

<span class="hljs-comment">// Decrypt data using AES</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">decryptData</span><span class="hljs-params">(encryptedData: <span class="hljs-type">ByteArray</span>, secretKey: <span class="hljs-type">SecretKey</span>)</span></span>: ByteArray {
    <span class="hljs-keyword">val</span> iv = encryptedData.copyOfRange(<span class="hljs-number">0</span>, <span class="hljs-number">12</span>)
    <span class="hljs-keyword">val</span> cipherData = encryptedData.copyOfRange(<span class="hljs-number">12</span>, encryptedData.size)
    <span class="hljs-keyword">val</span> cipher = Cipher.getInstance(<span class="hljs-string">"AES/GCM/NoPadding"</span>)
    <span class="hljs-keyword">val</span> gcmSpec = GCMParameterSpec(<span class="hljs-number">128</span>, iv)
    cipher.<span class="hljs-keyword">init</span>(Cipher.DECRYPT_MODE, secretKey, gcmSpec)
    <span class="hljs-keyword">return</span> cipher.doFinal(cipherData)
}
</code></pre>
<p>In this example, <strong>GCM mode</strong> (Galois/Counter Mode) is used, which is a secure mode for AES encryption that also provides integrity by generating an authentication tag.</p>
<hr />
<h3 id="heading-rsa-rivest-shamir-adleman"><strong>RSA (Rivest-Shamir-Adleman)</strong></h3>
<p><strong>RSA</strong> is an asymmetric encryption algorithm commonly used for secure data transmission, such as key exchange or signing sensitive information. Unlike AES, RSA uses a pair of keys: a public key for encryption and a private key for decryption.</p>
<h4 id="heading-use-case-secure-key-exchange"><strong>Use Case: Secure Key Exchange</strong></h4>
<p>In Android applications, RSA is often used in combination with AES. RSA can encrypt the AES key itself, which is then securely exchanged between the client and server, while the data is encrypted using the faster AES algorithm.</p>
<h4 id="heading-kotlin-example-rsa-encryption-and-decryption"><strong>Kotlin Example: RSA Encryption and Decryption</strong></h4>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> java.security.KeyPairGenerator
<span class="hljs-keyword">import</span> java.security.PrivateKey
<span class="hljs-keyword">import</span> java.security.PublicKey
<span class="hljs-keyword">import</span> javax.crypto.Cipher

<span class="hljs-comment">// Generate RSA key pair</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateRSAKeyPair</span><span class="hljs-params">()</span></span>: Pair&lt;PublicKey, PrivateKey&gt; {
    <span class="hljs-keyword">val</span> keyPairGenerator = KeyPairGenerator.getInstance(<span class="hljs-string">"RSA"</span>)
    keyPairGenerator.initialize(<span class="hljs-number">2048</span>) <span class="hljs-comment">// 2048-bit RSA key</span>
    <span class="hljs-keyword">val</span> keyPair = keyPairGenerator.generateKeyPair()
    <span class="hljs-keyword">return</span> Pair(keyPair.<span class="hljs-keyword">public</span>, keyPair.<span class="hljs-keyword">private</span>)
}

<span class="hljs-comment">// Encrypt data using RSA public key</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">encryptDataWithRSA</span><span class="hljs-params">(<span class="hljs-keyword">data</span>: <span class="hljs-type">ByteArray</span>, publicKey: <span class="hljs-type">PublicKey</span>)</span></span>: ByteArray {
    <span class="hljs-keyword">val</span> cipher = Cipher.getInstance(<span class="hljs-string">"RSA/ECB/OAEPWithSHA-256AndMGF1Padding"</span>)
    cipher.<span class="hljs-keyword">init</span>(Cipher.ENCRYPT_MODE, publicKey)
    <span class="hljs-keyword">return</span> cipher.doFinal(<span class="hljs-keyword">data</span>)
}

<span class="hljs-comment">// Decrypt data using RSA private key</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">decryptDataWithRSA</span><span class="hljs-params">(encryptedData: <span class="hljs-type">ByteArray</span>, privateKey: <span class="hljs-type">PrivateKey</span>)</span></span>: ByteArray {
    <span class="hljs-keyword">val</span> cipher = Cipher.getInstance(<span class="hljs-string">"RSA/ECB/OAEPWithSHA-256AndMGF1Padding"</span>)
    cipher.<span class="hljs-keyword">init</span>(Cipher.DECRYPT_MODE, privateKey)
    <span class="hljs-keyword">return</span> cipher.doFinal(encryptedData)
}
</code></pre>
<p>Here, <strong>OAEP (Optimal Asymmetric Encryption Padding)</strong> is used for RSA encryption, which is recommended for preventing attacks such as padding oracle attacks.</p>
<hr />
<h3 id="heading-keystore-api"><strong>KeyStore API</strong></h3>
<p>The <strong>Android KeyStore</strong> system allows you to securely generate and store cryptographic keys. The keys are stored in a hardware-backed or software-only keystore, depending on the device. This API ensures that the keys are not accessible by any unauthorized process or application.</p>
<h4 id="heading-use-case-storing-encryption-keys-securely"><strong>Use Case: Storing Encryption Keys Securely</strong></h4>
<p>You can use the KeyStore to store AES or RSA keys, ensuring that even if the device is compromised, the keys remain protected.</p>
<h4 id="heading-kotlin-example-using-android-keystore"><strong>Kotlin Example: Using Android KeyStore</strong></h4>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> android.security.keystore.KeyGenParameterSpec
<span class="hljs-keyword">import</span> android.security.keystore.KeyProperties
<span class="hljs-keyword">import</span> java.security.KeyStore
<span class="hljs-keyword">import</span> javax.crypto.KeyGenerator
<span class="hljs-keyword">import</span> javax.crypto.SecretKey

<span class="hljs-comment">// Generate and store AES key in KeyStore</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateAndStoreKey</span><span class="hljs-params">()</span></span>: SecretKey {
    <span class="hljs-keyword">val</span> keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, <span class="hljs-string">"AndroidKeyStore"</span>)
    <span class="hljs-keyword">val</span> keyGenParameterSpec = KeyGenParameterSpec.Builder(
        <span class="hljs-string">"MyKeyAlias"</span>, 
        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
    )
    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    .build()

    keyGenerator.<span class="hljs-keyword">init</span>(keyGenParameterSpec)
    <span class="hljs-keyword">return</span> keyGenerator.generateKey()
}

<span class="hljs-comment">// Retrieve the AES key from KeyStore</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getKeyFromKeyStore</span><span class="hljs-params">()</span></span>: SecretKey? {
    <span class="hljs-keyword">val</span> keyStore = KeyStore.getInstance(<span class="hljs-string">"AndroidKeyStore"</span>)
    keyStore.load(<span class="hljs-literal">null</span>)
    <span class="hljs-keyword">return</span> keyStore.getKey(<span class="hljs-string">"MyKeyAlias"</span>, <span class="hljs-literal">null</span>) <span class="hljs-keyword">as</span> SecretKey?
}
</code></pre>
<p>By storing keys in the <strong>Android KeyStore</strong>, you ensure that they are isolated from the application’s memory and more secure from external threats.</p>
<hr />
<h3 id="heading-file-based-encryption-fbe"><strong>File-Based Encryption (FBE)</strong></h3>
<p><strong>File-Based Encryption (FBE)</strong> is an Android feature that encrypts files on a per-user basis. This means that individual files are encrypted with different keys, adding an extra layer of security. FBE ensures that files are inaccessible until the user is authenticated.</p>
<h4 id="heading-use-case-protecting-user-files"><strong>Use Case: Protecting User Files</strong></h4>
<p>If your app deals with sensitive files like medical records, documents, or images, using FBE ensures that files remain encrypted even when the device is locked or not in use.</p>
<h4 id="heading-implementation-in-android"><strong>Implementation in Android</strong></h4>
<p>File-based encryption is automatically enabled in newer Android devices, and developers only need to ensure their apps support FBE by using standard storage APIs.</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Example of writing encrypted data to storage using Android Storage APIs</span>
<span class="hljs-keyword">val</span> encryptedData = encryptData(<span class="hljs-string">"Sensitive File Data"</span>.toByteArray(), secretKey)
applicationContext.openFileOutput(<span class="hljs-string">"encrypted_file"</span>, Context.MODE_PRIVATE).use {
    it.write(encryptedData)
}
</code></pre>
<p>With FBE, you don’t have to manage encryption and decryption directly. Android handles it based on user authentication states.</p>
<hr />
<h3 id="heading-network-security-configuration"><strong>Network Security Configuration</strong></h3>
<p>The <strong>Network Security Configuration</strong> in Android allows you to customize your app’s network security settings, such as enforcing <strong>HTTPS connections</strong> and defining policies for certificate pinning. This ensures that your app communicates over secure channels.</p>
<h4 id="heading-use-case-enforcing-secure-network-communication"><strong>Use Case: Enforcing Secure Network Communication</strong></h4>
<p>Many Android apps communicate with backend servers. Using HTTPS ensures that data transmitted between the app and server is encrypted, preventing eavesdropping or data tampering.</p>
<h4 id="heading-xml-configuration-for-https-enforcement"><strong>XML Configuration for HTTPS Enforcement</strong></h4>
<p>To enforce HTTPS in your app, you can use a <strong>network security configuration</strong> file:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- res/xml/network_security_config.xml --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">network-security-config</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">domain-config</span> <span class="hljs-attr">cleartextTrafficPermitted</span>=<span class="hljs-string">"false"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">domain</span> <span class="hljs-attr">includeSubdomains</span>=<span class="hljs-string">"true"</span>&gt;</span>example.com<span class="hljs-tag">&lt;/<span class="hljs-name">domain</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">domain-config</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">network-security-config</span>&gt;</span>
</code></pre>
<p>Then, specify this configuration in your AndroidManifest.xml:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">application</span>
    <span class="hljs-attr">android:networkSecurityConfig</span>=<span class="hljs-string">"@xml/network_security_config"</span>
    <span class="hljs-attr">...</span> &gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
</code></pre>
<p>By setting <code>cleartextTrafficPermitted="false"</code>, you prevent your app from sending data over insecure HTTP.</p>
<hr />
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Encrypting data is essential for building secure Android applications. Whether it’s encrypting sensitive data with <strong>AES</strong>, securely exchanging keys with <strong>RSA</strong>, or using the <strong>KeyStore API</strong> to store cryptographic keys, these encryption methods protect your app from various security threats. Implementing <strong>File-Based Encryption (FBE)</strong> ensures that files are encrypted at rest, and enforcing secure network communication with <strong>Network Security Configuration</strong> protects data in transit.</p>
<p>By leveraging these encryption techniques and tools, you can build Android apps that not only meet security best practices but also safeguard user data against potential attacks.</p>
<hr />
<p>That's it for today. Happy Coding...</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Android Security Approaches: Encryption and Secure Practices]]></title><description><![CDATA[In this article, we explore essential security techniques and encryption methods to protect Android applications. Covering a broad spectrum of security approaches, we highlight the use of data encryption (AES, RSA, and Android KeyStore), secure user ...]]></description><link>https://rommansabbir.com/android-security-approaches-encryption-and-secure-practices</link><guid isPermaLink="true">https://rommansabbir.com/android-security-approaches-encryption-and-secure-practices</guid><category><![CDATA[approaches]]></category><category><![CDATA[Android]]></category><category><![CDATA[Security]]></category><category><![CDATA[encryption]]></category><category><![CDATA[Secure]]></category><category><![CDATA[best practices]]></category><category><![CDATA[data]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Applications]]></category><category><![CDATA[Application Security]]></category><category><![CDATA[network]]></category><category><![CDATA[networking]]></category><category><![CDATA[storage]]></category><category><![CDATA[APIs]]></category><category><![CDATA[api]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Sun, 27 Oct 2024 16:38:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729953058128/f89bea7a-06ce-468f-a262-a77f95beaba7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we explore essential security techniques and encryption methods to protect Android applications. Covering a broad spectrum of security approaches, we highlight the use of <strong>data encryption</strong> (AES, RSA, and Android KeyStore), <strong>secure user authentication</strong> (biometrics, OAuth 2.0), and <strong>network security</strong> (TLS, certificate pinning). We also focus on securing <strong>application code</strong> through obfuscation, <strong>protecting local storage</strong> using encrypted databases and files, and ensuring <strong>device integrity</strong> with SafetyNet and SELinux policies. By implementing these practices, developers can safeguard sensitive user data, prevent attacks, and maintain secure app environments.</p>
<hr />
<p><strong>Contents are:</strong></p>
<h3 id="heading-1-data-encryptionhttpsrommansabbircomdata-encryption-in-android-a-comprehensive-guide-part-1">1. <a target="_blank" href="https://rommansabbir.com/data-encryption-in-android-a-comprehensive-guide-part-1"><strong>Data Encryption</strong></a></h3>
<ul>
<li><p><strong>AES (Advanced Encryption Standard)</strong>: Encrypt sensitive data such as user credentials, tokens, or files.</p>
</li>
<li><p><strong>RSA (Rivest-Shamir-Adleman)</strong>: Use for secure data transmission, such as key exchange or signing sensitive information.</p>
</li>
<li><p><strong>KeyStore API</strong>: Securely generate and store cryptographic keys in a hardware-backed keystore.</p>
</li>
<li><p><strong>File-based Encryption (FBE)</strong>: Encrypt files individually to ensure better security on file access.</p>
</li>
<li><p><strong>Network Security Configuration</strong>: Define policies to enforce HTTPS connections and avoid insecure communication.</p>
</li>
</ul>
<h3 id="heading-2-secure-user-authenticationhttpsrommansabbircomsecure-user-authentication-in-android-a-comprehensive-guide-part-2">2. <a target="_blank" href="https://rommansabbir.com/secure-user-authentication-in-android-a-comprehensive-guide-part-2"><strong>Secure User Authentication</strong></a></h3>
<ul>
<li><p><strong>Biometric API</strong>: Integrate fingerprint or face authentication for a more secure login experience.</p>
</li>
<li><p><strong>OAuth 2.0 &amp; OpenID Connect</strong>: Secure authorization framework for token-based authentication with external services.</p>
</li>
<li><p><strong>Secure Password Storage</strong>: Hash and salt passwords using PBKDF2, bcrypt, or Argon2 to ensure password security.</p>
</li>
</ul>
<h3 id="heading-3-application-security">3. <strong>Application Security</strong></h3>
<ul>
<li><p><strong>ProGuard/R8</strong>: Minimize and obfuscate code to prevent reverse engineering and tampering.</p>
</li>
<li><p><strong>App Signing</strong>: Sign your APK with Android's signing mechanism to validate the authenticity of the app.</p>
</li>
<li><p><strong>Integrity Check (SafetyNet)</strong>: Detect whether the device running your app is rooted or compromised using Google's SafetyNet API.</p>
</li>
<li><p><strong>Google Play App Signing</strong>: Use Google’s key management for securing the signing keys.</p>
</li>
</ul>
<h3 id="heading-4-network-security">4. <strong>Network Security</strong></h3>
<ul>
<li><p><strong>TLS (Transport Layer Security)</strong>: Ensure encrypted communication over the network by enforcing TLS/SSL for data transfer.</p>
</li>
<li><p><strong>Certificate Pinning</strong>: Prevent man-in-the-middle attacks by ensuring the server’s SSL certificate is valid and hasn’t been tampered with.</p>
</li>
<li><p><strong>VPN Support</strong>: Implement VPN capabilities or work with VPN providers for secure network communication.</p>
</li>
<li><p><strong>Firewall &amp; IDS Integration</strong>: Create rules for traffic filtering and detect intrusions in network communication.</p>
</li>
</ul>
<h3 id="heading-5-secure-storage">5. <strong>Secure Storage</strong></h3>
<ul>
<li><p><strong>SharedPreferences Encryption</strong>: Use Android's EncryptedSharedPreferences to securely store small data (e.g., tokens, flags).</p>
</li>
<li><p><strong>SQLite Database Encryption</strong>: Use libraries like SQLCipher for encrypting local databases.</p>
</li>
<li><p><strong>External Storage Encryption</strong>: Secure files stored on external storage by encrypting them before saving.</p>
</li>
</ul>
<h3 id="heading-6-app-security-features">6. <strong>App Security Features</strong></h3>
<ul>
<li><p><strong>Runtime Permissions</strong>: Use Android’s runtime permission model to request only the permissions your app needs, and do so at the point of use.</p>
</li>
<li><p><strong>Dynamic Security Configurations</strong>: Dynamically adjust security settings based on user roles or app environment.</p>
</li>
<li><p><strong>Tamper Detection</strong>: Implement checks to detect any unauthorized app modifications (e.g., code tampering, re-signing).</p>
</li>
</ul>
<h3 id="heading-7-api-security">7. <strong>API Security</strong></h3>
<ul>
<li><p><strong>Token-based Authentication (JWT)</strong>: Use secure token mechanisms (e.g., JSON Web Tokens) for API authentication and session management.</p>
</li>
<li><p><strong>Rate Limiting &amp; Throttling</strong>: Implement server-side rate limits to prevent abuse of your API.</p>
</li>
<li><p><strong>Input Validation &amp; Sanitization</strong>: Avoid injection attacks by validating and sanitizing all user inputs, particularly for server-side requests.</p>
</li>
</ul>
<h3 id="heading-8-device-security">8. <strong>Device Security</strong></h3>
<ul>
<li><p><strong>Secure Boot</strong>: Leverage Secure Boot mechanisms on devices to prevent booting from tampered software.</p>
</li>
<li><p><strong>SE Linux Policies</strong>: Enforce security-enhanced Linux policies to limit the actions that apps can perform on a device.</p>
</li>
<li><p><strong>Device Encryption</strong>: Encourage users to enable full-disk encryption for protecting data at rest.</p>
</li>
<li><p><strong>Enterprise Mobility Management (EMM)</strong>: Implement EMM policies to enforce security settings on corporate devices.</p>
</li>
</ul>
<h3 id="heading-9-backup-security">9. <strong>Backup Security</strong></h3>
<ul>
<li><p><strong>Encrypted Backups</strong>: Ensure app data backups are encrypted when stored in cloud services like Google Drive.</p>
</li>
<li><p><strong>Key Backup Management</strong>: Use Android’s Backup Manager to securely back up data while encrypting keys.</p>
</li>
</ul>
<p>We will explore each section in details in the next 9 part articles….</p>
<hr />
<p>That’s it for today. Happy coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item><item><title><![CDATA[Monitor Internet Connectivity in Jetpack Compose! 📶 ✨]]></title><description><![CDATA[Hello, and welcome to this article where we will delve into a Jetpack Compose function that is not only lifecycle-aware but also adept at checking internet connectivity using the most up-to-date APIs available. This function is designed to utilize th...]]></description><link>https://rommansabbir.com/monitor-internet-connectivity-in-jetpack-compose</link><guid isPermaLink="true">https://rommansabbir.com/monitor-internet-connectivity-in-jetpack-compose</guid><category><![CDATA[android app development]]></category><category><![CDATA[jetpack]]></category><category><![CDATA[Jetpack Compose]]></category><category><![CDATA[Android Studio]]></category><category><![CDATA[android apps]]></category><category><![CDATA[compose]]></category><category><![CDATA[internet]]></category><category><![CDATA[connectivity]]></category><category><![CDATA[logging]]></category><category><![CDATA[monitoring]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[Mobile apps]]></category><category><![CDATA[mobile app development]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Fri, 04 Oct 2024 19:07:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728067951747/56c15b67-fca3-42d0-a253-e64cc28acbaa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello, and welcome to this article where we will delve into a Jetpack Compose function that is not only lifecycle-aware but also adept at checking internet connectivity using the most up-to-date APIs available. This function is designed to utilize the <code>ConnectivityManager.NetworkCallback</code> class, which is a powerful tool for monitoring changes in internet status. By implementing this callback, the function can respond to various network events, such as when the device connects to or disconnects from the internet, or when the type of network connection changes, like switching from Wi-Fi to mobile data.</p>
<p>The code we will discuss is thoroughly documented, providing clear and comprehensive explanations for each part of the implementation. This detailed documentation is intended to guide you through the process, making it easier to understand the underlying mechanisms of internet connectivity monitoring. Additionally, the code includes extensive logging, which serves as a valuable resource for debugging. These logs will help you trace the flow of network status changes and identify any issues that may arise during the execution of the function.</p>
<p>By the end of this article, you will have a solid understanding of how to create a robust and efficient Jetpack Compose function that can reliably monitor internet connectivity, ensuring your application remains responsive and aware of network changes.</p>
<blockquote>
<p><strong><em>NOTE:</em></strong></p>
</blockquote>
<p>We aim to identify situations where a device is connected to a network, yet the internet is either inaccessible or not working properly. This can occur in cases where the network indicates a connected status, but users are unable to browse the web or access online services. Such scenarios might happen due to various network problems, including issues with the network infrastructure, the presence of captive portals requiring user authentication, or other types of restrictions imposed by the network provider. These issues can be frustrating for users, as they appear to have a connection but cannot perform any online activities. By detecting these conditions, we can provide better feedback to users and potentially guide them through resolving the problem.</p>
<p>To address this, we need to:</p>
<ol>
<li><p>Check if the network has internet capability using <a target="_blank" href="http://NetworkCapabilities.NET"><code>NetworkCapabilities.NET</code></a><code>_CAPABILITY_INTERNET</code>.</p>
</li>
<li><p>Use <a target="_blank" href="http://NetworkCapabilities.NET"><code>NetworkCapabilities.NET</code></a><code>_CAPABILITY_VALIDATED</code> to ensure that the internet connection is usable. This capability is a good indicator that the network is functional, as the system performs a network validation check when this capability is present.</p>
</li>
</ol>
<h3 id="heading-usage-example">Usage Example</h3>
<p>Incorporate this composable function into our app to actively monitor and receive updates on internet connectivity. This approach takes into account not only the presence of internet access but also the validation of the network connection. By doing so, we ensure that our application can detect when a device is connected to a network that truly provides internet access, as opposed to merely showing a connected status without actual usability. This functionality is crucial for enhancing user experience, as it allows us to inform users about the real status of their internet connection. Furthermore, it can help guide them in troubleshooting connectivity issues, ensuring they can access online services smoothly. By integrating this composable, we can maintain a robust and reliable connection status within our app, ultimately improving user satisfaction and reducing frustration caused by misleading network indicators.</p>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Composable</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">MyAppScreen</span><span class="hljs-params">()</span></span> {
    MonitorNetworkStatus { isNetworkFunctional -&gt;
        <span class="hljs-keyword">if</span> (isNetworkFunctional) {
            Log.d(<span class="hljs-string">"MyAppScreen"</span>, <span class="hljs-string">"Internet is functional and validated."</span>)
            <span class="hljs-comment">// Handle the functional network state</span>
        } <span class="hljs-keyword">else</span> {
            Log.d(<span class="hljs-string">"MyAppScreen"</span>, <span class="hljs-string">"Internet is not functional or validated."</span>)
            <span class="hljs-comment">// Handle the non-functional network state</span>
        }
    }

    <span class="hljs-comment">// Other UI content</span>
}
</code></pre>
<p>This updated implementation enhances the process of checking for a "functional" internet connection by incorporating a validation mechanism for the network. This approach offers a more dependable method for identifying situations where a device appears to be connected to a network but is unable to access the internet. Such scenarios can occur due to issues like a captive portal, which requires additional login steps, or other network-related problems that prevent internet access despite a connected status. By validating the network connection, this implementation ensures that our application can accurately determine the usability of the internet connection, providing a more robust solution for detecting and handling connectivity issues. This improvement is crucial for delivering a seamless user experience, as it allows the app to inform users about the true status of their internet connectivity and guide them in resolving any potential issues.</p>
<h3 id="heading-code-for-monitor-internet-connectivity-with-validation">Code for Monitor Internet Connectivity with Validation</h3>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> android.content.Context
<span class="hljs-keyword">import</span> android.net.ConnectivityManager
<span class="hljs-keyword">import</span> android.net.Network
<span class="hljs-keyword">import</span> android.net.NetworkCapabilities
<span class="hljs-keyword">import</span> android.net.NetworkRequest
<span class="hljs-keyword">import</span> android.util.Log
<span class="hljs-keyword">import</span> androidx.compose.runtime.*
<span class="hljs-keyword">import</span> androidx.compose.ui.platform.LocalContext
<span class="hljs-keyword">import</span> androidx.compose.ui.platform.LocalLifecycleOwner
<span class="hljs-keyword">import</span> androidx.lifecycle.Lifecycle
<span class="hljs-keyword">import</span> androidx.lifecycle.LifecycleEventObserver
<span class="hljs-keyword">import</span> androidx.lifecycle.LifecycleOwner

<span class="hljs-comment">/**
 * Checks if the current network is connected to the internet and validated.
 * Validation indicates the network is functional (e.g., it can be used for browsing).
 *
 * <span class="hljs-doctag">@return</span> True if the network is connected, has internet capability, and is validated; false otherwise.
 */</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> Context.<span class="hljs-title">isInternetFunctional</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Boolean</span> {
    <span class="hljs-keyword">val</span> connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) <span class="hljs-keyword">as</span> ConnectivityManager
    <span class="hljs-keyword">val</span> network = connectivityManager.activeNetwork
    <span class="hljs-keyword">val</span> networkCapabilities = connectivityManager.getNetworkCapabilities(network)
    <span class="hljs-keyword">return</span> networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == <span class="hljs-literal">true</span> &amp;&amp;
           networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}

<span class="hljs-comment">/**
 * A Composable function that monitors internet connectivity status in a lifecycle-aware manner.
 * It uses ConnectivityManager.NetworkCallback to listen for network changes, ensuring the network is validated.
 *
 * <span class="hljs-doctag">@param</span> lifecycleOwner The lifecycle owner to observe, typically the hosting activity or fragment.
 * <span class="hljs-doctag">@param</span> onNetworkStatusChanged A callback function that provides the current network status (true if the internet is functional).
 */</span>
<span class="hljs-meta">@Composable</span>
<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">MonitorNetworkStatus</span><span class="hljs-params">(
    lifecycleOwner: <span class="hljs-type">LifecycleOwner</span> = LocalLifecycleOwner.current,
    onNetworkStatusChanged: (<span class="hljs-type">Boolean</span>) -&gt; <span class="hljs-type">Unit</span>
)</span></span> {
    <span class="hljs-keyword">val</span> context = LocalContext.current
    <span class="hljs-keyword">var</span> isNetworkFunctional <span class="hljs-keyword">by</span> remember { mutableStateOf(context.isInternetFunctional()) }
    <span class="hljs-keyword">val</span> connectivityManager = remember {
        context.getSystemService(Context.CONNECTIVITY_SERVICE) <span class="hljs-keyword">as</span> ConnectivityManager
    }

    DisposableEffect(lifecycleOwner) {
        <span class="hljs-comment">// Lifecycle observer to handle lifecycle events</span>
        <span class="hljs-keyword">val</span> observer = LifecycleEventObserver { _, event -&gt;
            <span class="hljs-keyword">when</span> (event) {
                Lifecycle.Event.ON_RESUME -&gt; {
                    Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"ON_RESUME event triggered."</span>)
                    <span class="hljs-keyword">try</span> {
                        <span class="hljs-comment">// Update the network status on resume</span>
                        <span class="hljs-keyword">val</span> currentNetworkStatus = context.isInternetFunctional()
                        <span class="hljs-keyword">if</span> (isNetworkFunctional != currentNetworkStatus) {
                            isNetworkFunctional = currentNetworkStatus
                            Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Network validation state: <span class="hljs-variable">$isNetworkFunctional</span>"</span>)
                            onNetworkStatusChanged(isNetworkFunctional)
                        }
                    } <span class="hljs-keyword">catch</span> (e: Exception) {
                        Log.e(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Exception checking network status: <span class="hljs-subst">${e.localizedMessage}</span>"</span>, e)
                    }
                }
                <span class="hljs-keyword">else</span> -&gt; {
                    Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Unhandled lifecycle event: <span class="hljs-variable">$event</span>"</span>)
                }
            }
        }

        <span class="hljs-comment">// NetworkCallback to listen for network changes</span>
        <span class="hljs-keyword">val</span> networkCallback = <span class="hljs-keyword">object</span> : ConnectivityManager.NetworkCallback() {
            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAvailable</span><span class="hljs-params">(network: <span class="hljs-type">Network</span>)</span></span> {
                <span class="hljs-keyword">val</span> networkCapabilities = connectivityManager.getNetworkCapabilities(network)
                <span class="hljs-keyword">val</span> isFunctional = networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == <span class="hljs-literal">true</span> &amp;&amp;
                                   networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                <span class="hljs-keyword">if</span> (isFunctional != isNetworkFunctional) {
                    isNetworkFunctional = isFunctional
                    Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Network validation state changed: <span class="hljs-variable">$isNetworkFunctional</span>"</span>)
                    onNetworkStatusChanged(isNetworkFunctional)
                }
            }

            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onLost</span><span class="hljs-params">(network: <span class="hljs-type">Network</span>)</span></span> {
                <span class="hljs-keyword">if</span> (isNetworkFunctional) {
                    isNetworkFunctional = <span class="hljs-literal">false</span>
                    Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Network connection lost."</span>)
                    onNetworkStatusChanged(<span class="hljs-literal">false</span>)
                }
            }

            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCapabilitiesChanged</span><span class="hljs-params">(network: <span class="hljs-type">Network</span>, networkCapabilities: <span class="hljs-type">NetworkCapabilities</span>)</span></span> {
                <span class="hljs-keyword">val</span> isFunctional = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &amp;&amp;
                                   networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                <span class="hljs-keyword">if</span> (isFunctional != isNetworkFunctional) {
                    isNetworkFunctional = isFunctional
                    Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Network capabilities changed: <span class="hljs-variable">$isNetworkFunctional</span>"</span>)
                    onNetworkStatusChanged(isNetworkFunctional)
                }
            }
        }

        <span class="hljs-comment">// Register the network callback to listen for internet connectivity changes</span>
        <span class="hljs-keyword">val</span> networkRequest = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build()
        connectivityManager.registerNetworkCallback(networkRequest, networkCallback)

        <span class="hljs-comment">// Add the observer to the lifecycle</span>
        lifecycleOwner.lifecycle.addObserver(observer)
        Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Observer added to lifecycle."</span>)

        <span class="hljs-comment">// Cleanup on disposal</span>
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
            connectivityManager.unregisterNetworkCallback(networkCallback)
            Log.d(<span class="hljs-string">"MonitorNetworkStatus"</span>, <span class="hljs-string">"Observer and network callback removed."</span>)
        }
    }
}
</code></pre>
<h3 id="heading-detailed-explanation">Detailed Explanation</h3>
<ol>
<li><p><code>isInternetFunctional</code> Function:</p>
<ul>
<li>This function plays a crucial role in determining the current state of the network connection. It checks whether the network is both connected and validated. The validation process, indicated by <code>NET_CAPABILITY_VALIDATED</code>, ensures that the system has verified the internet connection is indeed usable. This means that the connection is not just present but is also capable of supporting activities like web browsing or data fetching.</li>
</ul>
</li>
<li><p><strong>Network Callback Enhancements:</strong></p>
<ul>
<li><p><code>onAvailable</code>: This callback method is triggered when a network becomes available. It performs a thorough check to confirm the network's functionality by verifying the presence of both <code>NET_CAPABILITY_INTERNET</code> and <code>NET_CAPABILITY_VALIDATED</code> capabilities. If there is a change in the network's status, it updates the internal state to reflect this change, ensuring that the application is always aware of the network's current condition.</p>
</li>
<li><p><code>onCapabilitiesChanged</code>: This method is responsible for continuously monitoring any alterations in the network's capabilities. By doing so, it can detect any modifications in the network's ability to provide internet functionality, allowing the application to respond appropriately to these changes.</p>
</li>
</ul>
</li>
<li><p><strong>Lifecycle Awareness:</strong></p>
<ul>
<li>The network status is updated during the <code>ON_RESUME</code> lifecycle event. This ensures that every time the app or composable component becomes active, the network status is checked and updated. This approach guarantees that the application always operates with the most current network information, providing a seamless user experience.</li>
</ul>
</li>
<li><p><strong>Logging:</strong></p>
<ul>
<li>Logging is implemented to offer comprehensive insights into the network's status and capability changes. These logs are invaluable for debugging purposes, as they provide a detailed record of network events and transitions. By examining these logs, developers can quickly identify and resolve issues related to network connectivity, ensuring the application remains reliable and efficient.</li>
</ul>
</li>
</ol>
<p>🔗 GIST : <a target="_blank" href="https://ylnk.cc/@gI3i">https://ylnk.cc/@gI3i</a>  </p>
<hr />
<p>That’s it for today, Happy coding…</p>
]]></content:encoded></item><item><title><![CDATA[How Slow Poisoning Destroys Workplace Culture and Productivity]]></title><description><![CDATA[In today's fast-paced corporate world, many organizations experience a gradual decline in their work environment quality. This "slow poisoning" happens when employee morale, productivity, and well-being slowly erode due to toxic behaviors, poor leade...]]></description><link>https://rommansabbir.com/how-slow-poisoning-destroys-workplace-culture-and-productivity</link><guid isPermaLink="true">https://rommansabbir.com/how-slow-poisoning-destroys-workplace-culture-and-productivity</guid><category><![CDATA[poormanagement]]></category><category><![CDATA[lackofcommunication]]></category><category><![CDATA[lackofrecognitio]]></category><category><![CDATA[inequlaity]]></category><category><![CDATA[biasness]]></category><category><![CDATA[slowpoisoning]]></category><category><![CDATA[workplace]]></category><category><![CDATA[Culture]]></category><category><![CDATA[toxic]]></category><category><![CDATA[leadership]]></category><category><![CDATA[micromanagement]]></category><category><![CDATA[ToxicWorkCulture]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Fri, 20 Sep 2024 08:07:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726729560830/d5d58c31-e1f5-4400-a514-62f384e27cda.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's fast-paced corporate world, many organizations experience a gradual decline in their work environment quality. This "<strong><em>slow poisoning</em></strong>" happens when employee morale, productivity, and well-being slowly erode due to toxic behaviors, poor leadership, or harmful policies.</p>
<blockquote>
<p><strong><em>Unlike sudden crises, this decline is hard to notice until it's too late</em></strong>.</p>
</blockquote>
<p>Understanding the causes of slow poisoning can help companies spot and fix these issues before they become serious problems.</p>
<hr />
<h3 id="heading-key-factors-contributing-to-slow-poisoning">Key Factors Contributing to Slow Poisoning</h3>
<p>Several subtle yet damaging factors can contribute to slow poisoning in the workplace. Below, we elaborate on some of the most common causes and their impact on both employees and the broader organization.</p>
<blockquote>
<h4 id="heading-1-poor-leadership">1. Poor Leadership</h4>
</blockquote>
<p>Leadership is the cornerstone of any organization’s success. However, when leaders are inconsistent, authoritarian, or disconnected from their teams, they foster an environment of uncertainty and distrust. Poor leadership can manifest in various ways, including unclear communication, lack of support, and ineffective decision-making. Employees often feel uninformed and uncertain about their roles and responsibilities. Over time, this leads to decreased morale, as employees lose confidence in both their leaders and the direction of the company.</p>
<p><strong><em>Impact:</em></strong> When employees deal with poor leadership, they start to check out mentally, which means lower productivity and more people quitting. Decision-making slows down because team members are afraid to take action, worried they might get in trouble or be misunderstood.</p>
<blockquote>
<h4 id="heading-2-lack-of-communication">2. Lack of Communication</h4>
</blockquote>
<p>Clear communication is essential for a functional work environment. When leadership or teams fail to communicate effectively, confusion and frustration arise. Employees may not fully understand their tasks, roles, or the company's goals, leading to a sense of isolation and disconnection. Miscommunication can occur at any level, from leadership down to individual teams, exacerbating the issue.</p>
<p><strong><em>Impact:</em></strong> When there's a lack of communication, misunderstandings happen all the time, and a lot of time gets wasted as employees try to guess what's expected of them. This frustration wears them down, leading to low engagement and killing the team spirit.</p>
<blockquote>
<h4 id="heading-3-micromanagement">3. Micromanagement</h4>
</blockquote>
<p>Micromanagement is one of the most effective ways to demotivate employees. When managers continuously oversee every minor task and provide little autonomy, employees feel they are not trusted to perform their work independently. This approach not only stifles creativity but also limits opportunities for employees to grow and develop their problem-solving skills.</p>
<p><strong><em>Impact:</em></strong> Over time, micromanagement makes employees check out because they feel undervalued and powerless. It ramps up stress and kills job satisfaction, which eventually drags down productivity and creativity in the team.</p>
<blockquote>
<h4 id="heading-4-unrealistic-expectations">4. Unrealistic Expectations</h4>
</blockquote>
<p>Setting ambitious goals can be motivating, but when expectations are consistently unattainable, it results in stress, frustration, and burnout. Unrealistic expectations often arise from poor planning, insufficient resources, or a misunderstanding of the work required. Employees may feel overwhelmed as they are continually asked to do more than is feasible, without the necessary support or tools.</p>
<p><strong><em>Impact:</em></strong> When employees are set up to fail, their self-esteem and confidence take a nosedive. Always chasing impossible goals leads to constant stress, burnout, and a lack of interest. Over time, this means more sick days, poor mental health, and lower productivity.</p>
<blockquote>
<h4 id="heading-5-lack-of-recognition">5. Lack of Recognition</h4>
</blockquote>
<p>Everyone desires to feel appreciated for their contributions, and when employees do not receive recognition for their hard work, they become disheartened. Whether it is a simple acknowledgment of a job well done or more formal rewards and incentives, recognition serves as a powerful motivator. In a culture where achievements are ignored or downplayed, employees may feel that their efforts are in vain.</p>
<p><strong><em>Impact:</em></strong> Over time, not getting recognized makes employees less motivated and more disengaged. They stop putting in extra effort because they know it won't be appreciated. This creates a work culture where people just do the bare minimum, leading to lower performance and morale.</p>
<blockquote>
<h4 id="heading-6-toxic-work-culture">6. Toxic Work Culture</h4>
</blockquote>
<p>A toxic work culture is characterized by negative behaviors such as gossip, favoritism, power struggles, or unethical practices. This type of environment fosters distrust, insecurity, and resentment among employees. When workers are more focused on office politics than on achieving common goals, the company's mission is adversely affected.</p>
<p><strong><em>Impact:</em></strong> In a toxic culture, people might get hostile or just check out completely. Teamwork falls apart, collaboration takes a hit, and overall productivity goes down. Eventually, this creates a nasty environment that kills creativity, innovation, and makes it hard to keep good employees around.</p>
<blockquote>
<h4 id="heading-7-work-overload">7. Work Overload</h4>
</blockquote>
<p>Chronic overwork is one of the most prevalent issues in modern workplaces. When employees are consistently assigned excessive workloads without adequate breaks or balance, it results in physical and mental exhaustion. This situation often arises when companies are understaffed, or management fails to delegate tasks appropriately, leaving employees to bear an undue amount of responsibility.</p>
<p><strong><em>Impact:</em></strong> Work overload leads to burnout, which is basically chronic stress that tanks productivity and engagement. Burnt-out employees might take more sick days, mess up more often, and even quit. Over time, this creates a vicious cycle of high turnover and an even more overworked team.</p>
<h4 id="heading-8-inequality-or-bias">8. Inequality or Bias</h4>
<p><strong><em>This issue is particularly hazardous.</em></strong> Discrimination or favoritism based on gender, race, age, or other factors significantly contributes to a toxic work environment. When certain employees are treated unfairly or overlooked for opportunities due to biases, it fosters resentment and division within the team. Bias also prevents a company from benefiting from diverse perspectives and talents.</p>
<p><strong><em>Impact:</em></strong> Inequality at work makes people feel unfairly treated, unmotivated, and disconnected. Those who feel left out might pull back, get less done, or start looking for new jobs. This hurts team spirit and teamwork, making it tough for the company to succeed.</p>
<hr />
<h3 id="heading-long-term-consequences-of-slow-poisoning">Long-Term Consequences of Slow Poisoning</h3>
<p>If ignored, the factors causing slow poisoning can severely harm an organization in the long run. Over time, low morale, burnout, and disengagement lead to:</p>
<ol>
<li><p><strong>High Employee Turnover</strong>: Unhappy employees will leave for better jobs, causing high recruitment and training costs.</p>
</li>
<li><p><strong>Reduced Productivity</strong>: Disengaged employees are less productive, leading to lower efficiency and poorer work quality.</p>
</li>
<li><p><strong>Damaged Reputation</strong>: A toxic workplace can hurt a company’s reputation, making it hard to attract and keep top talent.</p>
</li>
<li><p><strong>Lack of Innovation</strong>: When employees feel unappreciated, overworked, or micromanaged, their creativity and problem-solving skills suffer. This leads to stagnation and a lack of innovation.</p>
</li>
</ol>
<hr />
<h3 id="heading-preventing-slow-poisoning-in-the-workplace">Preventing Slow Poisoning in the Workplace</h3>
<p>To prevent slow poisoning, organizations must take proactive steps to create a healthy work environment. Here are some strategies for fostering a positive, supportive workplace:</p>
<ul>
<li><p><strong>Strong Leadership</strong>: Invest in leadership development to ensure managers lead with empathy, clarity, and support.</p>
</li>
<li><p><strong>Open Communication</strong>: Encourage transparent and open communication at all levels, making sure employees feel heard and understood.</p>
</li>
<li><p><strong>Autonomy</strong>: Trust employees to manage their own work and give them the freedom to make decisions within their roles.</p>
</li>
<li><p><strong>Realistic Expectations</strong>: Set achievable goals and provide the resources and support employees need to succeed.</p>
</li>
<li><p><strong>Recognition</strong>: Regularly acknowledge and celebrate employee achievements to foster a sense of belonging and motivation.</p>
</li>
<li><p><strong>Positive Culture</strong>: Cultivate an inclusive, fair, and supportive workplace culture that values diversity and teamwork.</p>
</li>
<li><p><strong>Balanced Workloads</strong>: Ensure employees have manageable workloads and enough time for rest and recovery.</p>
</li>
<li><p><strong>Address Inequality</strong>: Implement policies and practices that promote fairness and address bias, ensuring equal opportunities for all employees.</p>
</li>
</ul>
<hr />
<h3 id="heading-conclusion">Conclusion</h3>
<p>Slow poisoning in the workplace is a gradual yet destructive force that can erode an organization from within. By understanding the key factors contributing to this phenomenon—poor leadership, lack of communication, micromanagement, unrealistic expectations, lack of recognition, toxic culture, work overload, and inequality—companies can take steps to prevent these issues before they take root.</p>
<blockquote>
<p><strong><em>Creating a healthy, positive work environment isn’t just good for employees—it’s essential for the long-term success and sustainability of any organization</em></strong>.</p>
</blockquote>
<p>With dedication and proactive measures, we can build workplaces where everyone thrives and feels valued.</p>
]]></content:encoded></item><item><title><![CDATA[Kotlin : How to Flow?]]></title><description><![CDATA[Kotlin Flow is a powerful and easy-to-use tool for handling asynchronous data streams in Kotlin, especially useful for modern Android development. At first glance, Flow might seem a bit complex, but don’t worry! In this article, we’ll break it down i...]]></description><link>https://rommansabbir.com/kotlin-how-to-flow</link><guid isPermaLink="true">https://rommansabbir.com/kotlin-how-to-flow</guid><category><![CDATA[data stream]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[kotlin beginner]]></category><category><![CDATA[flow]]></category><category><![CDATA[kotlin-flow]]></category><category><![CDATA[asynchronous]]></category><category><![CDATA[stream]]></category><category><![CDATA[coroutines]]></category><category><![CDATA[kotlin coroutines]]></category><category><![CDATA[rommansabbir]]></category><category><![CDATA[#techarticle]]></category><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[iOS]]></category><category><![CDATA[Kotlin Multiplatform]]></category><dc:creator><![CDATA[Romman Sabbir]]></dc:creator><pubDate>Sat, 14 Sep 2024 07:31:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726298708823/3879c6f6-efdd-43c9-a217-289b2fb54697.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kotlin Flow is a powerful and easy-to-use tool for handling asynchronous data streams in Kotlin, especially useful for modern Android development. At first glance, Flow might seem a bit complex, but don’t worry! In this article, we’ll break it down into its core parts with simple examples. By the end of this guide, we'll understand how Flow works under the hood and how to replicate its basic functionality step by step.</p>
<h3 id="heading-what-well-cover">What We’ll Cover:</h3>
<ol>
<li><p><strong>Creating a Stream (Emission)</strong></p>
</li>
<li><p><strong>Introducing Suspension (Pausing Between Emissions)</strong></p>
</li>
<li><p><strong>Applying Operators (Transformation)</strong></p>
</li>
<li><p><strong>Collecting Values (Handling the Stream)</strong></p>
</li>
<li><p><strong>Handling Concurrency (Running Emission on a Different Thread)</strong></p>
</li>
</ol>
<p>Let’s get started!</p>
<hr />
<h3 id="heading-1-creating-a-simple-flow-like-class-emission">1. Creating a Simple Flow-like Class (Emission)</h3>
<p>In Kotlin Flow, values are emitted and processed over time. To replicate this behavior, we’ll create a simple <code>MyFlow</code> class that emits values when a consumer collects them.</p>
<p><strong>Breaking Down the Basics: Creating Our Own Flow:</strong></p>
<p>Let’s start by building a simple version of a flow using Kotlin. This will help us understand how Kotlin Flow works behind the scenes.</p>
<blockquote>
<p>We’ll create two classes:</p>
<ol>
<li><p><code>MyFlow</code> (to emit values) and</p>
</li>
<li><p><code>MyFlowCollector</code> (to handle the emitted values).</p>
</li>
</ol>
</blockquote>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFlow</span>&lt;<span class="hljs-type">T</span>&gt;</span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> block: <span class="hljs-keyword">suspend</span> MyFlowCollector&lt;T&gt;.() -&gt; <span class="hljs-built_in">Unit</span>) {

    <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">collect</span><span class="hljs-params">(collector: <span class="hljs-type">MyFlowCollector</span>&lt;<span class="hljs-type">T</span>&gt;)</span></span> {
        collector.block() <span class="hljs-comment">// Executes the block, emitting values</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFlowCollector</span>&lt;<span class="hljs-type">T</span>&gt; </span>{
    <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">emit</span><span class="hljs-params">(value: <span class="hljs-type">T</span>)</span></span> {
        println(<span class="hljs-string">"Emitting value: <span class="hljs-variable">$value</span>"</span>) <span class="hljs-comment">// Simulates emitting values</span>
    }
}
</code></pre>
<blockquote>
<h3 id="heading-whats-going-on-here">What's Going On Here?</h3>
<ul>
<li><p><code>MyFlow</code>: This class represents a stream of data, just like a real flow in Kotlin. It’s designed to emit values when someone collects them. Think of it as a machine that’s ready to send data but won’t start until you ask for it.</p>
</li>
<li><p><code>MyFlowCollector</code>: This class is the one that "catches" or handles the values emitted by <code>MyFlow</code>. In this case, we simply print out each value that gets emitted.</p>
</li>
<li><p><code>emit()</code>: This function is responsible for sending out values. Here, it prints each value to simulate data being "emitted" in a flow.</p>
</li>
</ul>
<h3 id="heading-putting-it-to-work">Putting It to Work</h3>
<p>Now, we’ll use this class to actually emit some values, just like a flow in Kotlin would.</p>
<p>In short: <code>MyFlow</code> is the data stream, and <code>MyFlowCollector</code> is how we handle the data when it’s ready.</p>
<p>Ready to see it in action? Let’s go!</p>
</blockquote>
<p><strong>Example:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> myFlow = MyFlow&lt;<span class="hljs-built_in">Int</span>&gt; {
    emit(<span class="hljs-number">1</span>)
    emit(<span class="hljs-number">2</span>)
    emit(<span class="hljs-number">3</span>)
}
</code></pre>
<p>This creates a <code>MyFlow</code> that will emit numbers <code>1</code>, <code>2</code>, and <code>3</code>. However, nothing happens until we collect these values.</p>
<hr />
<h3 id="heading-2-collecting-the-flow">2. Collecting the Flow</h3>
<p>In Kotlin Flow, values are not emitted until they are collected. So, let’s implement a method to collect the values:</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> myCollector = MyFlowCollector&lt;<span class="hljs-built_in">Int</span>&gt;()

    myFlow.collect(myCollector) <span class="hljs-comment">// Collect the flow</span>
}
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-kotlin">Emitting value: <span class="hljs-number">1</span>
Emitting value: <span class="hljs-number">2</span>
Emitting value: <span class="hljs-number">3</span>
</code></pre>
<blockquote>
<h3 id="heading-explanation">Explanation:</h3>
<ul>
<li>We create an instance of <code>MyFlowCollector</code> and call <code>collect()</code> on the <code>MyFlow</code> to start emitting the values. Each value is printed as it's emitted.</li>
</ul>
</blockquote>
<hr />
<h3 id="heading-3-adding-suspension-pausing-between-emissions">3. Adding Suspension (Pausing Between Emissions)</h3>
<p>Now, let’s make things a bit more realistic by adding <strong>suspension</strong> between emissions. This simulates how real-world asynchronous operations work, such as fetching data from a network.</p>
<p><strong>Example with Delay:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> myFlowWithDelay = MyFlow&lt;<span class="hljs-built_in">Int</span>&gt; {
    emit(<span class="hljs-number">1</span>)
    delay(<span class="hljs-number">1000</span>) <span class="hljs-comment">// Simulate suspension between emissions</span>
    emit(<span class="hljs-number">2</span>)
    delay(<span class="hljs-number">1000</span>)
    emit(<span class="hljs-number">3</span>)
}
</code></pre>
<p>When we collect this flow, it will emit each value with a 1-second pause.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> myCollector = MyFlowCollector&lt;<span class="hljs-built_in">Int</span>&gt;()

    myFlowWithDelay.collect(myCollector)
}
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-kotlin">Emitting value: <span class="hljs-number">1</span>
(<span class="hljs-number">1</span>-second delay)
Emitting value: <span class="hljs-number">2</span>
(<span class="hljs-number">1</span>-second delay)
Emitting value: <span class="hljs-number">3</span>
</code></pre>
<blockquote>
<h3 id="heading-explanation-1">Explanation:</h3>
<ul>
<li>We added <code>delay(1000)</code> to introduce a pause between each emission. This simulates real-world delays, such as waiting for data from a server, without blocking the main thread.</li>
</ul>
</blockquote>
<hr />
<h3 id="heading-4-applying-transformations-operators">4. Applying Transformations (Operators)</h3>
<p>One of the coolest features of Kotlin Flow is the ability to transform data using operators like <code>map</code>. Let’s replicate this functionality by creating a simple <code>map</code> operator that modifies each emitted value.</p>
<p><strong>Example of a</strong> <code>map</code> <strong>Operator:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type">&lt;T, R&gt;</span> MyFlow<span class="hljs-type">&lt;T&gt;</span>.<span class="hljs-title">map</span><span class="hljs-params">(transform: <span class="hljs-type">suspend</span> (<span class="hljs-type">T</span>) -&gt; <span class="hljs-type">R</span>)</span></span>: MyFlow&lt;R&gt; {
    <span class="hljs-keyword">return</span> MyFlow {
        collect(<span class="hljs-keyword">object</span> : MyFlowCollector&lt;T&gt;() {
            <span class="hljs-keyword">override</span> <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">emit</span><span class="hljs-params">(value: <span class="hljs-type">T</span>)</span></span> {
                <span class="hljs-keyword">val</span> newValue = transform(value) <span class="hljs-comment">// Apply the transformation</span>
                <span class="hljs-keyword">this</span><span class="hljs-symbol">@MyFlow</span>.emit(newValue <span class="hljs-keyword">as</span> R)
            }
        })
    }
}
</code></pre>
<blockquote>
<h3 id="heading-explanation-2">Explanation:</h3>
<ul>
<li><strong>map</strong>: This function takes a transformation function that modifies each emitted value (just like Kotlin Flow’s <code>map</code> operator).</li>
</ul>
</blockquote>
<p>Let’s apply this <code>map</code> operator to our flow:</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> transformedFlow = myFlowWithDelay.map { it * <span class="hljs-number">2</span> }

<span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> myCollector = MyFlowCollector&lt;<span class="hljs-built_in">Int</span>&gt;()

    transformedFlow.collect(myCollector)
}
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-kotlin">Emitting value: <span class="hljs-number">2</span>
(<span class="hljs-number">1</span>-second delay)
Emitting value: <span class="hljs-number">4</span>
(<span class="hljs-number">1</span>-second delay)
Emitting value: <span class="hljs-number">6</span>
</code></pre>
<blockquote>
<h3 id="heading-explanation-3">Explanation:</h3>
<ul>
<li>The <code>map</code> operator transforms each emitted value by multiplying it by 2. As a result, the collected values are <code>2</code>, <code>4</code>, and <code>6</code>.</li>
</ul>
</blockquote>
<hr />
<h3 id="heading-5-handling-concurrency-with-flowon">5. Handling Concurrency with <code>flowOn</code></h3>
<p>In real-world scenarios, you often want to emit values on a background thread (e.g., doing network requests) and collect them on the main thread (e.g., updating the UI). Kotlin Flow allows you to do this using <code>flowOn</code>. Let’s replicate this functionality using coroutines.</p>
<p><strong>Example with</strong> <code>flowOn</code><strong>:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> kotlinx.coroutines.Dispatchers
<span class="hljs-keyword">import</span> kotlinx.coroutines.withContext

<span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type">&lt;T&gt;</span> MyFlow<span class="hljs-type">&lt;T&gt;</span>.<span class="hljs-title">flowOn</span><span class="hljs-params">(dispatcher: <span class="hljs-type">CoroutineDispatcher</span>)</span></span>: MyFlow&lt;T&gt; {
    <span class="hljs-keyword">return</span> MyFlow {
        withContext(dispatcher) {
            collect(<span class="hljs-keyword">this</span><span class="hljs-symbol">@MyFlow</span>)
        }
    }
}
</code></pre>
<blockquote>
<h3 id="heading-explanation-4">Explanation:</h3>
<ul>
<li><strong>flowOn</strong>: This function changes the context of the emission to a specified dispatcher (e.g., <a target="_blank" href="http://Dispatchers.IO"><code>Dispatchers.IO</code></a> for background tasks).</li>
</ul>
</blockquote>
<p>Now, let’s use <code>flowOn</code> to run the emission on the IO dispatcher (a background thread):</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> flowOnBackground = myFlowWithDelay.flowOn(Dispatchers.IO)

<span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">val</span> myCollector = MyFlowCollector&lt;<span class="hljs-built_in">Int</span>&gt;()

    flowOnBackground.collect(myCollector)
}
</code></pre>
<blockquote>
<h3 id="heading-explanation-5">Explanation:</h3>
<ul>
<li>The emission now happens on the IO dispatcher, meaning that all emissions run in the background, while the collection can happen on the main thread (if needed).</li>
</ul>
</blockquote>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>By breaking down the core functionalities of Kotlin Flow, we've built a simple version that mimics how Flow works. We covered:</p>
<ol>
<li><p><strong>Emission</strong>: Emitting values using a <code>MyFlow</code> class.</p>
</li>
<li><p><strong>Suspension</strong>: Adding delays between emissions to simulate real-world async tasks.</p>
</li>
<li><p><strong>Transformation</strong>: Using operators like <code>map</code> to modify emitted values.</p>
</li>
<li><p><strong>Concurrency</strong>: Controlling where the emission happens using <code>flowOn</code> for better thread management.</p>
</li>
</ol>
<p>Kotlin Flow, while built on top of coroutines, offers powerful tools to handle asynchronous data streams. By understanding how it works internally, you’ll have a clearer idea of why it’s so useful and how to apply it effectively in your own projects.</p>
<hr />
<p>That’s it for today. Happy Coding…</p>
<div class="hn-embed-widget" id="buymeacoffee-donate"></div>]]></content:encoded></item></channel></rss>