<?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[Yashraj Singh Jadon]]></title><description><![CDATA[Yashraj Singh Jadon]]></description><link>https://blog.yashraj.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 05:20:41 GMT</lastBuildDate><atom:link href="https://blog.yashraj.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Implementing MVVM Architecture in Android]]></title><description><![CDATA[Model-View-ViewModel (MVVM) has become a popular architectural pattern in Android development. This blog post will dive deep into MVVM, exploring its components, benefits, and implementation in Android applications.
What is MVVM?
MVVM is an architect...]]></description><link>https://blog.yashraj.dev/implementing-mvvm-architecture-in-android</link><guid isPermaLink="true">https://blog.yashraj.dev/implementing-mvvm-architecture-in-android</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Android Studio]]></category><category><![CDATA[MVVM]]></category><category><![CDATA[MVVMArchitecture]]></category><category><![CDATA[repository]]></category><category><![CDATA[repository-pattern]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Fri, 02 Aug 2024 12:50:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722602679603/5541fd1d-00dd-4903-aa14-b3ba43d8036c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Model-View-ViewModel (MVVM) has become a popular architectural pattern in Android development. This blog post will dive deep into MVVM, exploring its components, benefits, and implementation in Android applications.</p>
<h1 id="heading-what-is-mvvm">What is MVVM?</h1>
<p>MVVM is an architectural pattern that separates an application into three main components:</p>
<ol>
<li><p>Model</p>
</li>
<li><p>View</p>
</li>
<li><p>ViewModel</p>
</li>
</ol>
<p>The purpose is to separate the user interface logic from the business logic, making the code more modular and easier to maintain.</p>
<h1 id="heading-components-of-mvvm">Components of MVVM</h1>
<h3 id="heading-model">Model</h3>
<ul>
<li><p>Represents the data structure and business logic of the application.</p>
</li>
<li><p>Responsible for managing data, performing calculations, and enforcing business rules.</p>
</li>
<li><p>Can include data classes, repositories, and data sources.</p>
</li>
<li><p>Should be independent of the UI and can be reused across different parts of the application.</p>
</li>
</ul>
<h3 id="heading-view">View</h3>
<ul>
<li><p>Represents the UI elements that the user interacts with.</p>
</li>
<li><p>This typically includes Activities, Fragments, and XML layout files.</p>
</li>
<li><p>Observes and reacts to data changes in the ViewModel.</p>
</li>
<li><p>Should be focusing only on displaying data and capturing user inputs.</p>
</li>
<li><p>Doesn't contain any business logic or data manipulation.</p>
</li>
</ul>
<h3 id="heading-viewmodel">ViewModel</h3>
<ul>
<li><p>Acts as an intermediary between the Model and View.</p>
</li>
<li><p>Holds and processes all the data needed for the View.</p>
</li>
<li><p>Exposes data to the View through observable properties (often using LiveData or StateFlow).</p>
</li>
<li><p>Handles user interactions passed from the View.</p>
</li>
<li><p>Contains the presentation logic but no direct reference to View components.</p>
</li>
<li><p>It is lifecycle aware, and survives configuration changes (like screen rotations or switching between light/dark themes).</p>
</li>
<li><p>Helps in separating UI logic from UI controllers, making the code more testable and maintainable.</p>
</li>
</ul>
<h1 id="heading-data-flow-in-mvvm">Data Flow in MVVM</h1>
<p><strong>a) View to ViewModel:</strong></p>
<ul>
<li><p>User interacts with the View (e.g., button click)</p>
</li>
<li><p>View calls a method in the ViewModel</p>
</li>
<li><p>ViewModel processes the request and updates its data if necessary</p>
</li>
</ul>
<p><strong>b) ViewModel to Model:</strong></p>
<ul>
<li><p>ViewModel requests data from the Model</p>
</li>
<li><p>Model fetches or updates data (e.g., from a database or network)</p>
</li>
<li><p>Model returns data to the ViewModel</p>
</li>
</ul>
<p><strong>c) ViewModel to View:</strong></p>
<ul>
<li><p>ViewModel updates its observable properties</p>
</li>
<li><p>View observes these changes and updates the UI accordingly</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721930347951/7545b91a-6746-4f67-b55b-033a092a536c.png" alt class="image--center mx-auto" /></p>
<p><strong>Example</strong>:</p>
<ol>
<li><strong>Model Layer</strong></li>
</ol>
<p>User.kt</p>
<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">User</span></span>(<span class="hljs-keyword">val</span> name: String, <span class="hljs-keyword">val</span> email: String)
</code></pre>
<p>UserApi.kt</p>
<pre><code class="lang-kotlin">
<span class="hljs-keyword">object</span> UserApi {
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getUser</span><span class="hljs-params">()</span></span>: User {
        <span class="hljs-comment">// Here you can write the code to fetch data from internet</span>
        <span class="hljs-comment">// For now, I am returning sample data</span>
        <span class="hljs-keyword">return</span> User(<span class="hljs-string">"Yashraj"</span>, <span class="hljs-string">"yash@mail.com"</span>)
    }
}
</code></pre>
<ol start="2">
<li><strong>ViewModel Layer</strong></li>
</ol>
<p>UserViewModel.kt</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserViewModel</span> : <span class="hljs-type">ViewModel</span></span>() {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> _user = MutableLiveData&lt;User&gt;()
    <span class="hljs-keyword">val</span> user: LiveData&lt;User&gt; = _user

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">loadUser</span><span class="hljs-params">()</span></span> {
        _user.value = UserApi.getUser()
    }
}
</code></pre>
<ol start="3">
<li><strong>View Layer</strong></li>
</ol>
<p>activity_main.xml</p>
<pre><code class="lang-kotlin">&lt;?xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"utf-8"</span>?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout xmlns:android=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
    xmlns:app=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span>
    xmlns:tools=<span class="hljs-string">"http://schemas.android.com/tools"</span>
    android:id=<span class="hljs-string">"@+id/main"</span>
    android:layout_width=<span class="hljs-string">"match_parent"</span>
    android:layout_height=<span class="hljs-string">"match_parent"</span>&gt;

    &lt;TextView
        android:id=<span class="hljs-string">"@+id/tv_data"</span>
        android:layout_width=<span class="hljs-string">"wrap_content"</span>
        android:layout_height=<span class="hljs-string">"wrap_content"</span>
        android:text=<span class="hljs-string">"Sample"</span>
        android:textSize=<span class="hljs-string">"34sp"</span>
        app:layout_constraintBottom_toBottomOf=<span class="hljs-string">"parent"</span>
        app:layout_constraintEnd_toEndOf=<span class="hljs-string">"parent"</span>
        app:layout_constraintStart_toStartOf=<span class="hljs-string">"parent"</span>
        app:layout_constraintTop_toTopOf=<span class="hljs-string">"parent"</span> /&gt;

    &lt;Button
        android:id=<span class="hljs-string">"@+id/btn_load"</span>
        android:layout_width=<span class="hljs-string">"wrap_content"</span>
        android:layout_height=<span class="hljs-string">"wrap_content"</span>
        android:layout_marginTop=<span class="hljs-string">"16dp"</span>
        android:text=<span class="hljs-string">"Load Data"</span>
        app:layout_constraintEnd_toEndOf=<span class="hljs-string">"parent"</span>
        app:layout_constraintStart_toStartOf=<span class="hljs-string">"parent"</span>
        app:layout_constraintTop_toBottomOf=<span class="hljs-string">"@+id/tv_data"</span> /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;
</code></pre>
<p>MainActivity.kt</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> viewModel: UserViewModel
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> tvData: TextView
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> btnLoadData: Button

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        tvData = findViewById(R.id.tv_data)

        <span class="hljs-comment">// ViewModelProvider(this) initializes the provider</span>
        <span class="hljs-comment">// [UserViewModel::class.java] gets the UserViewModel instance from the provider.</span>
        viewModel = ViewModelProvider(<span class="hljs-keyword">this</span>)[UserViewModel::<span class="hljs-keyword">class</span>.java]

        viewModel.user.observe(this) { user -&gt;
            tvData.text = <span class="hljs-string">"<span class="hljs-subst">${user.name}</span> \n <span class="hljs-subst">${user.email}</span>"</span>
        }

        btnLoadData.setOnClickListener {
            viewModel.loadUser()
        }
    }
}
</code></pre>
<p>However, MVVM is generally used with the <strong>Repository pattern</strong> in Android because this combination provides a robust, scalable, and maintainable architecture.</p>
<blockquote>
<p>The Repository Pattern is a design pattern that provides an abstraction of data sources, such as databases, network services, or caches. It centralizes data access logic and provides a clean API for the rest of the application.</p>
</blockquote>
<p>The combination is very effective because of:</p>
<ul>
<li><p><strong>Separation of Concerns:</strong> MVVM handles UI logic, while Repository manages data access.</p>
</li>
<li><p><strong>Abstraction of Data Sources:</strong> Repository hides complexity of multiple data sources.</p>
</li>
<li><p><strong>Improved Testability:</strong> Easier to test ViewModels and data access logic independently.</p>
</li>
<li><p><strong>Offline-First Approach:</strong> Repository can implement caching for offline use.</p>
</li>
<li><p><strong>Scalability:</strong> Easier to add new features or data sources without changing ViewModels.</p>
</li>
<li><p>Lifecycle Management: ViewModel handles UI-related data, Repository manages long-running operations.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722086006282/27986b04-2d88-454e-9d8d-1b6013f0f8cb.png" alt class="image--center mx-auto" /></p>
<p><strong>Example</strong>:</p>
<ol>
<li><strong>Model Layer</strong></li>
</ol>
<p>User.kt</p>
<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">User</span></span>(<span class="hljs-keyword">val</span> name: String, <span class="hljs-keyword">val</span> email: String)
</code></pre>
<p>UserApi.kt</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">object</span> UserApi {
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getUser</span><span class="hljs-params">()</span></span>: User {
        <span class="hljs-comment">// Here you can write the code to fetch data from internet</span>
        <span class="hljs-comment">// For now, I am returning sample data</span>
        <span class="hljs-keyword">return</span> User(<span class="hljs-string">"Yashraj"</span>, <span class="hljs-string">"yash@mail.com"</span>)
    }
}
</code></pre>
<p>UserRepository.kt</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRepository</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> api: UserApi) {
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getUser</span><span class="hljs-params">()</span></span>: User {
        <span class="hljs-comment">// The data you fetch from api can be cache here in local database</span>
        <span class="hljs-comment">// For now, I am directly calling it</span>
        <span class="hljs-keyword">return</span> api.getUser()
    }
}
</code></pre>
<ol start="2">
<li><strong>ViewModel Layer</strong></li>
</ol>
<p>UserViewModel.kt</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserViewModel</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> repository: UserRepository) : ViewModel() {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> _user = MutableLiveData&lt;User&gt;()
    <span class="hljs-keyword">val</span> user: LiveData&lt;User&gt; = _user

     <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">loadUser</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">val</span> userData = repository.getUser()
        _user.postValue(userData)
    }
}
</code></pre>
<p>ViewModelFactory.kt</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// Custom factory to create UserViewModel instances with UserRepository.</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserViewModelFactory</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> userRepository: UserRepository) : ViewModelProvider.Factory {
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-type">&lt;T : ViewModel&gt;</span> <span class="hljs-title">create</span><span class="hljs-params">(modelClass: <span class="hljs-type">Class</span>&lt;<span class="hljs-type">T</span>&gt;)</span></span>: T {

        <span class="hljs-comment">// Checks if the requested ViewModel class is UserViewModel.</span>
        <span class="hljs-comment">// If true, creates UserViewModel with UserRepository.</span>
        <span class="hljs-keyword">if</span> (modelClass.isAssignableFrom(UserViewModel::<span class="hljs-keyword">class</span>.java)) {
            @Suppress(<span class="hljs-string">"UNCHECKED_CAST"</span>)
            <span class="hljs-keyword">return</span> UserViewModel(userRepository) <span class="hljs-keyword">as</span> T
        }
        <span class="hljs-comment">// else throws an exception.</span>
        <span class="hljs-keyword">throw</span> IllegalArgumentException(<span class="hljs-string">"Unknown ViewModel class"</span>)
    }
}
</code></pre>
<ol start="3">
<li><strong>View Layer</strong></li>
</ol>
<p>(The activity_main.xml layout code will remain same as of the above given example.)</p>
<p>MainActivity.kt</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> viewModelFactory: UserViewModelFactory
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> tvData: TextView
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> btnLoadData: Button
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> viewModel: UserViewModel

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        tvData = findViewById(R.id.tv_data)
        btnLoadData = findViewById(R.id.btn_load)

        <span class="hljs-comment">// UserRepository(UserApi) creates the repository with the API.</span>
        <span class="hljs-keyword">val</span> repository = UserRepository(UserApi)

        <span class="hljs-comment">// UserViewModelFactory(UserRepository(UserApi)) creates the factory with the repository.</span>
        viewModelFactory = UserViewModelFactory(repository)

        <span class="hljs-comment">// ViewModelProvider(this, viewModelFactory) initializes the provider with the factory.</span>
        <span class="hljs-comment">// [UserViewModel::class.java] gets the UserViewModel instance from the provider.</span>
        viewModel = ViewModelProvider(<span class="hljs-keyword">this</span>,viewModelFactory)[UserViewModel::<span class="hljs-keyword">class</span>.java]

        // Observe the LiveData from the ViewModel to update the UI <span class="hljs-keyword">when</span> <span class="hljs-keyword">data</span> changes
        viewModel.user.observe(this) { user -&gt;
            tvData.text = <span class="hljs-string">"<span class="hljs-subst">${user.name}</span> \n <span class="hljs-subst">${user.email}</span>"</span>
        }

        btnLoadData.setOnClickListener {
            viewModel.loadUser()
        }
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722085999061/abe72059-a7f7-4b4c-9bb0-44176974aada.png" alt class="image--center mx-auto" /></p>
<p>The output will be the same for both of the above examples in here.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722173582510/10654a9a-cc57-4d19-8164-a365f1e991c3.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-pros-and-cons-of-mvvm-in-android">Pros and Cons of MVVM in Android</h1>
<p>While MVVM offers many benefits, it's important to consider both its advantages and disadvantages when deciding whether to use it in your Android project.</p>
<h3 id="heading-pros">Pros</h3>
<ol>
<li><p><strong>Separation of Concerns</strong>: MVVM clearly separates the user interface (View) from the business logic (ViewModel) and data (Model). This separation makes the code more organized and easier to maintain.</p>
</li>
<li><p><strong>Testability</strong>: The clear separation of components makes unit testing much easier, especially for the ViewModel and Model. You can test business logic without dealing with Android framework dependencies.</p>
</li>
<li><p><strong>Reusability</strong>: ViewModels can be shared across multiple Views (Activities or Fragments), promoting code reuse and consistency.</p>
</li>
<li><p><strong>Lifecycle Management</strong>: ViewModels are lifecycle-aware and survive configuration changes like screen rotations, helping to preserve data and state.</p>
</li>
<li><p><strong>Data Binding Support</strong>: MVVM works seamlessly with Android's data binding library, which can significantly reduce boilerplate code in the View layer.</p>
</li>
<li><p><strong>Scalability</strong>: As your app grows, MVVM's structure makes it easier to add new features or modify existing ones without affecting other parts of the app.</p>
</li>
</ol>
<h3 id="heading-cons">Cons</h3>
<ol>
<li><p><strong>Overengineering for Simple Apps</strong>: For very small or simple applications, implementing MVVM might be overkill and could unnecessarily complicate the codebase.</p>
</li>
<li><p><strong>Boilerplate Code</strong>: While MVVM can reduce boilerplate in some areas (especially with data binding), it can increase it in others, particularly when setting up the initial architecture.</p>
</li>
<li><p><strong>Risk of bulky ViewModels</strong>: Without careful design, ViewModels can become bulky with too much logic, defeating the purpose of separation of concerns.</p>
</li>
<li><p><strong>Overuse of Data Binding</strong>: While data binding can simplify View code, overuse can lead to complex XML layouts that are hard to understand and maintain.</p>
</li>
</ol>
<h1 id="heading-conclusion">Conclusion</h1>
<p>MVVM architecture, especially when paired with the Repository pattern, offers a robust solution for Android app development. It effectively separates concerns by dividing the app into View (UI), ViewModel (UI logic and state management), and Model (data and business logic) components, with the Repository acting as a centralized data management layer. This separation enhances testability, maintainability, and scalability of the app.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding MVC and MVP Architectures in Android Development]]></title><description><![CDATA[Introduction
Architectural patterns are essential for building maintainable Android applications. This post examines two popular approaches: Model-View-Controller (MVC) and Model-View-Presenter (MVP). We'll explore their components, advantages, and d...]]></description><link>https://blog.yashraj.dev/understanding-mvc-and-mvp-architectures-in-android-development</link><guid isPermaLink="true">https://blog.yashraj.dev/understanding-mvc-and-mvp-architectures-in-android-development</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[mvc]]></category><category><![CDATA[mvp]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Thu, 25 Jul 2024 12:08:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721907761540/20fed4cb-8ec0-4f8f-be09-a5de8ab5ea06.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Architectural patterns are essential for building maintainable Android applications. This post examines two popular approaches: Model-View-Controller (MVC) and Model-View-Presenter (MVP). We'll explore their components, advantages, and disadvantages to help you choose the right pattern for your Android projects.</p>
<h1 id="heading-mvc-model-view-controller-in-android">MVC (Model-View-Controller) in Android</h1>
<p>Separates an app into data and business logic (Model), user interface (View), and input handling (Controller). Simple to implement but can lead to overly large Controllers in complex apps.</p>
<p><strong>MVC Components:</strong></p>
<p>a) Model:</p>
<ul>
<li><p>Represents the data and business logic of the application.</p>
</li>
<li><p>Responsible for managing the data, performing calculations, and enforcing business rules.</p>
</li>
<li><p>Independent of the user interface.</p>
</li>
<li><p>Can notify observers (usually the Controller) when its state changes.</p>
</li>
</ul>
<p>Example:</p>
<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">UserModel</span></span>(
    <span class="hljs-keyword">var</span> name: String = <span class="hljs-string">""</span>,
    <span class="hljs-keyword">var</span> email: String = <span class="hljs-string">""</span>
) {

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">validate</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Boolean</span> {
        <span class="hljs-keyword">return</span> name.isNotEmpty() &amp;&amp; email.contains(<span class="hljs-string">"@"</span>)
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">save</span><span class="hljs-params">()</span></span> {
        <span class="hljs-comment">// Save user to database or server      </span>
    }
}
</code></pre>
<p>b) View:</p>
<ul>
<li><p>Responsible for presenting data to the user and receiving user input.</p>
</li>
<li><p>In Android, this typically consists of XML layout files and custom View classes.</p>
</li>
<li><p>It should contain little to no business logic.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- activity_user.xml --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">LinearLayout</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
    <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>
    <span class="hljs-attr">android:orientation</span>=<span class="hljs-string">"vertical"</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">EditText</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/nameEditText"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:hint</span>=<span class="hljs-string">"Name"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">EditText</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/emailEditText"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:hint</span>=<span class="hljs-string">"Email"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/saveButton"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:text</span>=<span class="hljs-string">"Save"</span> /&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">LinearLayout</span>&gt;</span>
</code></pre>
<p>c) Controller:</p>
<ul>
<li><p>Acts as an intermediary between the Model and View.</p>
</li>
<li><p>Handles user input from the View, updates the Model, and refreshes the View with updated data.</p>
</li>
<li><p>In Android, this role is typically filled by Activities or Fragments.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> userModel: UserModel
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> nameEditText: EditText
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> emailEditText: EditText
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> saveButton: Button

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user)

        userModel = UserModel()
        nameEditText = findViewById(R.id.nameEditText)
        emailEditText = findViewById(R.id.emailEditText)
        saveButton = findViewById(R.id.saveButton)

        saveButton.setOnClickListener {
            updateModel()
            <span class="hljs-keyword">if</span> (userModel.validate()) {
                userModel.save()
                showSuccessMessage()
            } <span class="hljs-keyword">else</span> {
                showErrorMessage()
            }
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">updateModel</span><span class="hljs-params">()</span></span> {
        userModel.name = nameEditText.text.toString()
        userModel.email = emailEditText.text.toString()
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showSuccessMessage</span><span class="hljs-params">()</span></span> {
        Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">"User saved successfully"</span>, Toast.LENGTH_SHORT).show()
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showErrorMessage</span><span class="hljs-params">()</span></span> {
        Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">"Invalid user data"</span>, Toast.LENGTH_SHORT).show()
    }
}
</code></pre>
<p>Interactions:</p>
<ol>
<li><p>User interacts with the View (e.g., enters data in EditTexts).</p>
</li>
<li><p>View notifies the Controller of user actions (e.g., button click).</p>
</li>
<li><p>Controller updates the Model based on user input.</p>
</li>
<li><p>Controller may update the View if necessary (e.g., show error messages).</p>
</li>
<li><p>Model may notify the Controller of data changes (in more complex implementations).</p>
</li>
<li><p>Controller updates the View to reflect Model changes.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721824055898/52d732bf-27b8-457e-84c5-bb1a2ffca246.png" alt class="image--center mx-auto" /></p>
<p>Advantages:</p>
<ol>
<li><p>Simplicity: Easier to understand and implement, especially for smaller projects.</p>
</li>
<li><p>Faster development: Less boilerplate code required.</p>
</li>
<li><p>Good for small to medium-sized applications.</p>
</li>
<li><p>Direct communication between View and Model can be efficient.</p>
</li>
</ol>
<p>Disadvantages:</p>
<ol>
<li><p>Tight coupling: Controller often becomes tightly coupled with View.</p>
</li>
<li><p>Testability issues: Difficult to unit test due to Android dependencies.</p>
</li>
<li><p>Scalability problems: Can become unwieldy in larger, complex applications.</p>
</li>
<li><p>Controllers often become too complex, handling many different tasks.</p>
</li>
</ol>
<h1 id="heading-mvp-model-view-presenter-in-android">MVP (Model-View-Presenter) in Android</h1>
<p>Enhances separation with a Presenter handling presentation logic and View-Model interactions. Improves testability and modularity but requires more initial setup and code.</p>
<p><strong>MVP Components:</strong></p>
<p>a) Model:</p>
<ul>
<li><p>Similar to MVC, represents data and business logic.</p>
</li>
<li><p>Independent of the user interface.</p>
</li>
</ul>
<p>Example:</p>
<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">UserModel</span></span>(
    <span class="hljs-keyword">var</span> name: String = <span class="hljs-string">""</span>,
    <span class="hljs-keyword">var</span> email: String = <span class="hljs-string">""</span>
) {

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">validate</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Boolean</span> {
        <span class="hljs-keyword">return</span> name.isNotEmpty() &amp;&amp; email.contains(<span class="hljs-string">"@"</span>)
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">save</span><span class="hljs-params">()</span></span> {
        <span class="hljs-comment">// Save user to database or server</span>
    }
}
</code></pre>
<p>b) View:</p>
<ul>
<li><p>Responsible for displaying data and sending user actions to the Presenter.</p>
</li>
<li><p>In Android, this is typically an Activity or Fragment implementing a View interface.</p>
</li>
<li><p>Displays data and forwards user actions to the Presenter.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserView</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showError</span><span class="hljs-params">(message: <span class="hljs-type">String</span>)</span></span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showSuccess</span><span class="hljs-params">()</span></span>
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>(), UserView {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> presenter: UserPresenter
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> nameEditText: EditText
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> emailEditText: EditText
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> saveButton: Button

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user)

        nameEditText = findViewById(R.id.nameEditText)
        emailEditText = findViewById(R.id.emailEditText)
        saveButton = findViewById(R.id.saveButton)

        presenter = UserPresenter(<span class="hljs-keyword">this</span>, UserModel())

        saveButton.setOnClickListener {
            presenter.onSaveClicked(
                nameEditText.text.toString(),
                emailEditText.text.toString()
            )
        }
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showError</span><span class="hljs-params">(message: <span class="hljs-type">String</span>)</span></span> {
        Toast.makeText(<span class="hljs-keyword">this</span>, message, Toast.LENGTH_SHORT).show()
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showSuccess</span><span class="hljs-params">()</span></span> {
        Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">"User saved successfully"</span>, Toast.LENGTH_SHORT).show()
    }
}
</code></pre>
<p>c) Presenter:</p>
<ul>
<li><p>Acts as an intermediary between Model and View.</p>
</li>
<li><p>Contains the presentation logic.</p>
</li>
<li><p>Updates the Model and instructs the View to update itself.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserPresenter</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> view: UserView, <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> model: UserModel) {
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onSaveClicked</span><span class="hljs-params">(name: <span class="hljs-type">String</span>, email: <span class="hljs-type">String</span>)</span></span> {
        model.name = name
        model.email = email

        <span class="hljs-keyword">if</span> (model.validate()) {
            model.save()
            view.showSuccess()
        } <span class="hljs-keyword">else</span> {
            view.showError(<span class="hljs-string">"Invalid user data"</span>)
        }
    }
}
</code></pre>
<p>Interactions:</p>
<ol>
<li><p>User interacts with the View.</p>
</li>
<li><p>View calls appropriate method on the Presenter.</p>
</li>
<li><p>Presenter updates the Model if necessary.</p>
</li>
<li><p>If Model is updated, it performs necessary business logic and data operations.</p>
</li>
<li><p>Presenter receives results from the Model and prepares data for display.</p>
</li>
<li><p>Presenter updates the View using the view interface.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721824087623/271e72a0-4315-4a0a-81b0-26f9b5249af5.png" alt class="image--center mx-auto" /></p>
<p>Advantages:</p>
<ol>
<li><p>Better separation of concerns: Clear division of responsibilities.</p>
</li>
<li><p>Improved testability: Presenter can be easily unit tested.</p>
</li>
<li><p>More modular and flexible: Easier to modify or replace individual components.</p>
</li>
<li><p>Reduces complexity in Views: Views become very passive.</p>
</li>
</ol>
<p>Disadvantages:</p>
<ol>
<li><p>More boilerplate code: Requires additional interfaces and classes.</p>
</li>
<li><p>More complex architecture to understand and implement.</p>
</li>
<li><p>Potential over-engineering for simple apps.</p>
</li>
<li><p>Risk of tight coupling between Presenter and View if not carefully designed.</p>
</li>
</ol>
<p><strong>The output will be same in the above given examples for MVC and MVP.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721897752914/d8312070-a1ed-4f24-a4ba-722b08d3b0a2.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-key-differences">Key Differences</h1>
<ol>
<li><p>Separation of Logic:</p>
<ul>
<li><p>MVC: Controller handles user input and some business logic.</p>
</li>
<li><p>MVP: Presenter contains all presentation logic.</p>
</li>
</ul>
</li>
<li><p>View-Model Interaction:</p>
<ul>
<li><p>MVC: View can directly observe Model changes.</p>
</li>
<li><p>MVP: View never interacts directly with Model, all goes through Presenter.</p>
</li>
</ul>
</li>
<li><p>Testability:</p>
<ul>
<li><p>MVC: Generally harder to unit test due to Android dependencies.</p>
</li>
<li><p>MVP: Easier to unit test, especially the Presenter.</p>
</li>
</ul>
</li>
<li><p>Complexity:</p>
<ul>
<li><p>MVC: Simpler for small applications.</p>
</li>
<li><p>MVP: Better suited for larger, more complex applications.</p>
</li>
</ul>
</li>
<li><p>Code Distribution:</p>
<ul>
<li><p>MVC: Logic often concentrated in Controller.</p>
</li>
<li><p>MVP: Logic more evenly distributed between Model and Presenter.</p>
</li>
</ul>
</li>
</ol>
<h1 id="heading-conclusion">Conclusion</h1>
<p>MVC and MVP offer different advantages for Android development. MVC is simpler and faster for small projects, while MVP provides better separation of concerns for complex applications. Your choice depends on project needs and team expertise.</p>
]]></content:encoded></item><item><title><![CDATA[Tasks, Backstack and Launch Modes]]></title><description><![CDATA[What is a Task?
A task in Android is a collection of activities that users interact with when trying to do something in your app, representing an application’s workflow where each activity is a focused action that a user can do. A task usually starts...]]></description><link>https://blog.yashraj.dev/tasks-backstack-and-launch-modes</link><guid isPermaLink="true">https://blog.yashraj.dev/tasks-backstack-and-launch-modes</guid><category><![CDATA[backstack]]></category><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[tasks]]></category><category><![CDATA[launch mode]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Thu, 18 Jul 2024 20:18:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721248033390/d51e5a88-6c2c-49ea-a802-4dd400f3a0a7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-is-a-task">What is a Task?</h1>
<p>A task in Android is a collection of activities that users interact with when trying to do something in your app, representing an application’s workflow where each activity is a focused action that a user can do. A task usually starts when a user launches an application and can include multiple activities across different applications. When you tap the app's launcher icon, the system searches for an existing task that matches the Intent and Activity. If it finds one, it resumes that task, bringing you back to where you left off. If no matching task is found, a new task is created with the newly launched activity as the base activity on the task’s back stack.</p>
<p>Here is an example showing how the app closes on Activity 3 and, after the app is launched again, it resumes from the same activity:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720882664769/0c0d5293-0476-4ad4-811f-1cbf9a12816d.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-understanding-the-backstack">Understanding the Backstack</h1>
<p>The backstack in Android is a Last In, First Out (LIFO) stack that maintains the order of activities the user interacts with. When a new activity starts, it is pushed onto the backstack. Pressing the back button pops the topmost activity off the stack, resuming the previous activity.</p>
<p>Here’s an example showing how activities are added to the backstack:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Activity1</span> : <span class="hljs-type">AppCompatActivity</span></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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_1)

        <span class="hljs-keyword">val</span> btnLaunch = findViewById&lt;Button&gt;(R.id.btn_launch_activity_2)
        btnLaunch.setOnClickListener {
            startActivity(Intent(<span class="hljs-keyword">this</span>, Activity2::<span class="hljs-keyword">class</span>.java))
        }
    }
}
</code></pre>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Activity2</span> : <span class="hljs-type">AppCompatActivity</span></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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_2)

        <span class="hljs-keyword">val</span> btnLaunch = findViewById&lt;Button&gt;(R.id.btn_launch_activity_3)
        btnLaunch.setOnClickListener {
            startActivity(Intent(<span class="hljs-keyword">this</span>, Activity3::<span class="hljs-keyword">class</span>.java))
        }
    }
}
</code></pre>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Activity3</span> : <span class="hljs-type">AppCompatActivity</span></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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_3)
    }
}
</code></pre>
<ol>
<li>When the app is first launched, Activity1 is added to the backstack.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720876997925/09ba6c50-c507-407f-933f-8c47abee2e50.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720876965442/00bf8115-4c6e-4a33-b65f-4bd264f03def.png" alt class="image--center mx-auto" /></p>
<ol start="2">
<li>Upon clicking "Launch Activity 2" button in Activity1, Activity2 is launched and added to the backstack.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720877009120/66f5ed54-08e9-4796-9c7d-698389b329cf.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720877019214/496e7f3f-0888-4416-941d-beba8531436a.png" alt class="image--center mx-auto" /></p>
<ol start="3">
<li>Similarly, clicking "Launch Activity 3" button in Activity2 launches Activity3, adding it to the backstack.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720877038692/b0dccf6d-2d4f-4ffd-b1f9-327eebae1ea8.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720877055391/0be4eda2-25a2-4788-9b19-26cabb57d011.png" alt class="image--center mx-auto" /></p>
<p>In this example, starting from <code>Activity1</code>, launching <code>Activity2</code> adds it to the backstack. Similarly, launching <code>Activity3</code> from <code>Activity2</code> pushes it onto the backstack. If you press the back button in <code>Activity3</code> will pop it off the stack, resuming <code>Activity2</code>.</p>
<h1 id="heading-launch-modes">Launch Modes</h1>
<p>Launch modes determine how activities are launched and associated with tasks. To specify launch modes in an Android application, you define them in the <code>AndroidManifest.xml</code> file within the <code>&lt;activity&gt;</code> element using the <code>android:launchMode</code> attribute. Example:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">application</span> <span class="hljs-attr">...</span>&gt;</span>
        ...
        <span class="hljs-tag">&lt;<span class="hljs-name">activity</span>
            <span class="hljs-attr">android:name</span>=<span class="hljs-string">".DemoActivity"</span>
            <span class="hljs-attr">android:launchMode</span>=<span class="hljs-string">"standard"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">activity</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p>There are four launch modes in Android:</p>
<ol>
<li><p><strong>Standard (default)</strong></p>
</li>
<li><p><strong>SingleTop</strong></p>
</li>
<li><p><strong>SingleTask</strong></p>
</li>
<li><p><strong>SingleInstance</strong></p>
</li>
</ol>
<h3 id="heading-standard">Standard</h3>
<p>This default launch mode creates a new instance of the activity each time it’s launched, even if an instance already exists. For example, if activities A, B, and C are in a task, and B is launched again, the task becomes A → B → C → B, with a new instance of B. You do not need to set anything for the standard launch mode since it is the default. However, for clarity, you can explicitly set it as follows:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">application</span> <span class="hljs-attr">...</span>&gt;</span>
        ...
        <span class="hljs-tag">&lt;<span class="hljs-name">activity</span>
            <span class="hljs-attr">android:name</span>=<span class="hljs-string">".Activity_B"</span>
            <span class="hljs-attr">android:launchMode</span>=<span class="hljs-string">"standard"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">activity</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721151092832/9b49cd05-39fb-4df5-bfd4-c5634eb0b28e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-singletop">SingleTop</h3>
<p>If an instance of the activity is already at the top of the backstack, it is not recreated; instead, the existing instance receives the intent via the <code>onNewIntent()</code> method. If a new instance is not present at the top then a new instance will be created. For example, we have activities A, B, and C, launching B will create a new instance of activity B as it is not at the top then we will get A → B → C → B, launching B again results in A → B → C → B (same instance), where <code>onNewIntent()</code> is called. To specify the <code>SingleTop</code> launch mode:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">application</span> <span class="hljs-attr">...</span>&gt;</span>
        ...
        <span class="hljs-tag">&lt;<span class="hljs-name">activity</span>
            <span class="hljs-attr">android:name</span>=<span class="hljs-string">".Activity_B"</span>
            <span class="hljs-attr">android:launchMode</span>=<span class="hljs-string">"singleTop"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">activity</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721151005049/776c4cbf-b6df-4d0d-9cce-cd72e35ccc2c.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-singletask">SingleTask</h3>
<p>An activity with the singleTask launch mode can have only one instance in the system at a time. If no instance exists, a new one is created. If an instance is already present, instead of creating a new one, the existing instance handles the intent through the <code>onNewIntent()</code> method. For example, with activities A, B, and C, launching D (singleTask) results in A → B → C → D, a new instance of D is created. If B is also singleTask and is launched, the task becomes A → B, removing C and D. This means that the existing instance of B is reused, and the intent data is routed through the <code>onNewIntent()</code> method. To specify the <code>SingleTask</code> launch mode:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">application</span> <span class="hljs-attr">...</span>&gt;</span>
        ...
        <span class="hljs-tag">&lt;<span class="hljs-name">activity</span>
            <span class="hljs-attr">android:name</span>=<span class="hljs-string">".Activity_B"</span>
            <span class="hljs-attr">android:launchMode</span>=<span class="hljs-string">"singleTask"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">activity</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721150990383/436d67b3-7850-418c-ba91-c4c6e9830fa0.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-singleinstance">SingleInstance</h3>
<p>Similar to SingleTask but stricter, this mode allows the activity to be the only one in its task, making it completely isolated. For example, launching D (singleInstance) from a task with A, B, and C results in two separate tasks: Task 1 (A → B → C) and Task 2 (D). If D is launched again, the existing instance handles the intent with <code>onNewIntent()</code>. To specify the <code>SingleInstance</code> launch mode:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">application</span> <span class="hljs-attr">...</span>&gt;</span>
        ...
        <span class="hljs-tag">&lt;<span class="hljs-name">activity</span>
            <span class="hljs-attr">android:name</span>=<span class="hljs-string">".Activity_D"</span>
            <span class="hljs-attr">android:launchMode</span>=<span class="hljs-string">"singleInstance"</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">activity</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721151457054/55ae8af5-d1ce-4424-9b87-ed014c994b26.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Fragments in Android]]></title><description><![CDATA[What are Fragments?
In Android, a fragment is a reusable portion of your app's user interface. You can think of a fragment as a mini-activity within an activity. Like activities, fragments have their own lifecycle, meaning they go through stages such...]]></description><link>https://blog.yashraj.dev/fragments-in-android</link><guid isPermaLink="true">https://blog.yashraj.dev/fragments-in-android</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[fragment]]></category><category><![CDATA[lifecycle]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Thu, 11 Jul 2024 20:23:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720726329799/b77e7d5c-dd4f-44b7-b7a2-1b539d7df61e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-what-are-fragments">What are Fragments?</h3>
<p>In Android, a fragment is a reusable portion of your app's user interface. You can think of a fragment as a mini-activity within an activity. Like activities, fragments have their own lifecycle, meaning they go through stages such as creation, starting, pausing, stopping, and destroying. A fragment receives its own input events, and you can add or remove it while the activity is running.</p>
<h3 id="heading-why-use-fragments">Why Use Fragments?</h3>
<p>Here are some key reasons why fragments are useful:</p>
<ol>
<li><p><strong>Modularity</strong>: Fragments allow you to divide your UI into smaller, manageable pieces. This makes your code easier to manage and maintain.</p>
</li>
<li><p><strong>Reusability</strong>: You can reuse fragments in multiple activities, reducing redundancy and saving time.</p>
</li>
<li><p><strong>Adaptability</strong>: Fragments help you create flexible UIs that work on different screen sizes and orientations.</p>
<p> For example, a tablet can display multiple fragments side by side, while a phone might show them one at a time.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720527672096/bdaac120-7d15-473c-9283-8e589ef336fa.png" alt class="image--center mx-auto" /></p>
<p>Image Source: <a target="_blank" href="https://developer.android.com/guide/fragments">https://developer.android.com/guide/fragments</a></p>
<h3 id="heading-how-to-create-a-fragment">How to Create a Fragment?</h3>
<p>Creating a fragment is similar to creating an activity. Here’s a basic example:</p>
<ol>
<li>Create a new class <code>DemoFragment</code> that extends <code>Fragment</code> and override its methods to insert your app logic.</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DemoFragment</span> : <span class="hljs-type">Fragment</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> TAG = <span class="hljs-string">"DemoFragment"</span>

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAttach</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>)</span></span> {
        <span class="hljs-keyword">super</span>.onAttach(context)
        Log.d(TAG, <span class="hljs-string">"onAttach: Fragment attached to activity"</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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        Log.d(TAG, <span class="hljs-string">"onCreate: Fragment create"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreateView</span><span class="hljs-params">(
        inflater: <span class="hljs-type">LayoutInflater</span>, container: <span class="hljs-type">ViewGroup</span>?,
        savedInstanceState: <span class="hljs-type">Bundle</span>?
    )</span></span>: View? {

        Log.d(TAG, <span class="hljs-string">"onCreateView: Fragment create view"</span>)
       <span class="hljs-comment">// Inflate the layout for this fragment</span>
        <span class="hljs-keyword">return</span> inflater.inflate(R.layout.fragment_demo, container, <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">onViewCreated</span><span class="hljs-params">(view: <span class="hljs-type">View</span>, savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onViewCreated(view, savedInstanceState)
        Log.d(TAG, <span class="hljs-string">"onViewCreated: Fragment view created"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onStart</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onStart()
        Log.d(TAG, <span class="hljs-string">"onStart: Fragment started"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onResume</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onResume()
        Log.d(TAG, <span class="hljs-string">"onResume: Fragment resumed"</span>)
    }-

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onPause</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onPause()
        Log.d(TAG, <span class="hljs-string">"onPause: Fragment paused"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onStop</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onStop()
        Log.d(TAG, <span class="hljs-string">"onStop: Fragment stopped"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onDestroyView</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onDestroyView()
        Log.d(TAG, <span class="hljs-string">"onDestroyView: Fragment view destroyed"</span>)
    }

    <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()
        Log.d(TAG, <span class="hljs-string">"onDestroy: Fragment destroyed"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onDetach</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onDetach()
        Log.d(TAG, <span class="hljs-string">"onDetach: Fragment detached from activity"</span>)
    }

}
</code></pre>
<ol start="2">
<li>In your activity, instantiate and add the fragment using <code>FragmentManager</code>.</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FragmentHolderActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> TAG = <span class="hljs-string">"FragmentHolderActivity"</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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_fragment_holder)

        <span class="hljs-keyword">if</span> (savedInstanceState == <span class="hljs-literal">null</span>) {
        <span class="hljs-comment">// Get the FragmentManager to interact with fragments associated with this activity</span>
            <span class="hljs-keyword">val</span> fragmentManager: FragmentManager = supportFragmentManager
        <span class="hljs-comment">// Begin a new fragment transaction</span>
            <span class="hljs-keyword">val</span> fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
        <span class="hljs-comment">// Create a new instance of DemoFragment</span>
            <span class="hljs-keyword">val</span> fragment = DemoFragment()
        <span class="hljs-comment">// Add the fragment to the container specified by its ID (R.id.fragment_container)</span>
            fragmentTransaction.add(R.id.fragment_container, fragment)
        <span class="hljs-comment">// Commit the transaction to apply the changes</span>
            fragmentTransaction.commit()
        }
        Log.d(TAG, <span class="hljs-string">"onCreate: Activity created"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onStart</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onStart()
        Log.d(TAG, <span class="hljs-string">"onStart: Activity started"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onResume</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onResume()
        Log.d(TAG, <span class="hljs-string">"onResume: Activity resumed"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onPause</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onPause()
        Log.d(TAG, <span class="hljs-string">"onPause: Activity paused"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onStop</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onStop()
        Log.d(TAG, <span class="hljs-string">"onStop: Activity stopped"</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onRestart</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onRestart()
        Log.d(TAG, <span class="hljs-string">"onRestart: Activity restarted"</span>)
    }

    <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()
        Log.d(TAG, <span class="hljs-string">"onDestroy: Activity destroyed"</span>)
    }
}
</code></pre>
<blockquote>
<p>Note: The fragment transaction is created only when <code>savedInstanceState</code> is null. This ensures the fragment is added just once when the activity starts initially. When a configuration change happens and the activity is recreated, <code>savedInstanceState</code> isn't null anymore. In this case, the fragment isn't added again; it's automatically restored from <code>savedInstanceState</code>.</p>
</blockquote>
<ol start="3">
<li>Include a <code>FragmentContainerView</code> in your activity's layout file where the fragment will be placed.</li>
</ol>
<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">androidx.fragment.app.FragmentContainerView</span>
    <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
    <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>
    <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/fragment_container"</span> /&gt;</span>
</code></pre>
<p><strong>FragmentManager</strong>: The main class to manage fragment operations like adding, removing, replacing fragments, and handling the fragment back stack.</p>
<p><strong>FragmentTransaction</strong>: Used to perform a set of fragment operations (like adding, replacing, or removing fragments) in a single atomic action.</p>
<ul>
<li><p><strong>Adding Fragments</strong>: Attach fragments to an activity.</p>
</li>
<li><p><strong>Removing Fragments</strong>: Detach fragments from an activity.</p>
</li>
<li><p><strong>Replacing Fragments</strong>: Replace existing fragments with new ones.</p>
</li>
<li><p><strong>Finding Fragments</strong>: Find fragments by their ID or tag.</p>
</li>
</ul>
<h3 id="heading-fragment-lifecycle">Fragment Lifecycle</h3>
<p>The lifecycle of fragment goes through the following stages:</p>
<ol>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720727885942/05eb5ffe-53d9-4a5d-b5cb-4b2978bcdd5f.png" alt class="image--center mx-auto" /></p>
<p> <strong>onAttach()</strong>: Called when the fragment is first attached to its host activity.</p>
</li>
<li><p><strong>onCreate()</strong>: The fragment is created. The saved instance state can be used to restore the fragment's previous state.</p>
</li>
<li><p><strong>onCreateView()</strong>: Called to create the view hierarchy associated with the fragment.</p>
</li>
<li><p><strong>onViewCreated()</strong>: Called immediately after <code>onCreateView()</code>. You can perform any additional setup of the fragment's view here.</p>
</li>
<li><p><strong>onStart()</strong>: Called when the fragment is visible to the user.</p>
</li>
<li><p><strong>onResume()</strong>: Called when the fragment is visible and actively running.</p>
</li>
<li><p><strong>onPause()</strong>: Called when the fragment is not actively running.</p>
</li>
<li><p><strong>onStop()</strong>: Called when the fragment is no longer visible to the user.</p>
</li>
<li><p><strong>onDestroyView()</strong>: Called to clean up resources associated with the view.</p>
</li>
<li><p><strong>onDestroy()</strong>: Called when the fragment is destroyed.</p>
</li>
<li><p><strong>onDetach()</strong>: Called when the fragment has been detached from the activity.</p>
</li>
</ol>
<ul>
<li><strong>Lifecycle methods execution when the app is launched</strong> (refer to the code above on how to create a fragment)<strong>:</strong></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720540516795/ce9d28ad-f0fe-440f-a3b7-04d4cccf4067.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720539293310/f0a62cff-e862-4ef2-8835-62a62d75a0fd.png" alt class="image--center mx-auto" /></p>
<p>This demonstrates the sequence of fragment and activity lifecycle methods executed when the app is launched.</p>
<ul>
<li><strong>Lifecycle methods execution when the app is closed and removed from the background</strong> (refer to the code above on how to create a fragment)<strong>.</strong></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720540527898/b9e9a462-7767-408a-b663-35f43fdaa38f.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720539485162/e04d5475-9847-4967-bdca-3c8659e90ed8.png" alt class="image--center mx-auto" /></p>
<p>This demonstrates the order of fragment and activity lifecycle methods executed when the app is closed and removed from the background.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Fragments serve as modular components that allow you to build dynamic and <a target="_blank" href="http://stackoverflow.com/questions/39418249/meaning-of-fragment-having-its-own-lifecycle">f</a>lexible UIs in Android. They make it easier to manage complex interfaces and ensure your app works well on various devices. By using fragments, you can create better and more adaptable Android applications.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Intents and Intent Filters in Android]]></title><description><![CDATA[What are Intents?
An Intent is a message object that represents a request for an action to be performed. It can be used to start activities, services, or broadcast receivers. In simple terms, Intents act as a bridge to pass information and instructio...]]></description><link>https://blog.yashraj.dev/understanding-intents-and-intent-filters-in-android</link><guid isPermaLink="true">https://blog.yashraj.dev/understanding-intents-and-intent-filters-in-android</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[intent]]></category><category><![CDATA[intents]]></category><category><![CDATA[Kotlin]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Fri, 05 Jul 2024 15:44:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720193503499/27b4fe7e-1d9f-458f-89fd-530ebc986b8e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-are-intents">What are Intents?</h1>
<p>An <strong>Intent</strong> is a message object that represents a request for an action to be performed. It can be used to start activities, services, or broadcast receivers. In simple terms, Intents act as a bridge to pass information and instructions between different components of your application or between different applications.</p>
<h3 id="heading-how-intents-work">How Intents Work</h3>
<p>When an Intent is created and sent, the Android system uses it to figure out which component should respond to the request. Depending on the type of Intent and how it's used, the system may:</p>
<ul>
<li><p><strong>Start an Activity</strong>: Move the user to a different screen.</p>
</li>
<li><p><strong>Start a Service</strong>: Perform background tasks without user interaction.</p>
</li>
<li><p><strong>Deliver a Broadcast</strong>: Send messages to multiple components interested in system-wide or app-wide events.</p>
</li>
</ul>
<h1 id="heading-types-of-intents">Types of Intents</h1>
<ol>
<li><p>Explicit Intents</p>
</li>
<li><p>Implicit Intents</p>
</li>
</ol>
<h2 id="heading-explicit-intent">Explicit Intent</h2>
<p>An Explicit Intent specifies the exact component to start by name. This is commonly used within an application when you know which activity or service you want to start.</p>
<p>Example 1: Here’s how to launch another activity within the same app using explicit intent.</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IntentSenderActivity</span>: <span class="hljs-type">AppCompatActivity</span></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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_intent_sender)

        <span class="hljs-keyword">val</span> btnLaunch = findViewById&lt;Button&gt;(R.id.btn_launch)

        btnLaunch.setOnClickListener {
            <span class="hljs-comment">// Create an explicit Intent to start IntentReceiverActivity</span>
           <span class="hljs-keyword">val</span> intent = Intent(<span class="hljs-keyword">this</span>, IntentReceiverActivity::<span class="hljs-keyword">class</span>.java)
            <span class="hljs-comment">// Start the activity specified by the Intent</span>
           startActivity(intent)
        }
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720023401938/f11e0bbf-59a8-4162-b858-42b66fad4031.gif" alt class="image--center mx-auto" /></p>
<p>Example 2: Launching a Calculator App Using Explicit Intent</p>
<p>Here we will launch the calculator app installed on your phone. To do so, you need the name of the package and the name of the class that implements the component.</p>
<p>Steps to Retrieve Package Name and Main Activity:</p>
<ol>
<li>Open a terminal and connect to your Android device:</li>
</ol>
<pre><code class="lang-kotlin">adb shell
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720173162506/145bb883-204e-4477-8b40-35587ae021bf.png" alt class="image--center mx-auto" /></p>
<ol start="2">
<li>List all installed packages:</li>
</ol>
<pre><code class="lang-kotlin">pm list packages
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720128345996/c725e586-9182-4d47-adc4-ca9ae68231c6.png" alt class="image--center mx-auto" /></p>
<ol start="3">
<li>Filter the list to find the calculator package:</li>
</ol>
<pre><code class="lang-kotlin">pm list packages | grep calculator
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720128294441/1d6c7119-636a-4e09-a592-e0b4f1370ea2.png" alt class="image--center mx-auto" /></p>
<p>Here you will get the package name of the calculator app, i.e., <code>com.oneplus.calculator</code>.</p>
<ol start="4">
<li>Get the main activity of the calculator app:</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-comment">//dumpsys package &lt;package_name&gt; | grep -A 1 "MAIN"</span>
dumpsys <span class="hljs-keyword">package</span> com.oneplus.calculator | grep -A <span class="hljs-number">1</span> <span class="hljs-string">"MAIN"</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720128052188/ad05e263-2f32-49fa-a62c-ef5b912fd7ae.png" alt class="image--center mx-auto" /></p>
<p>Here we get the package name <code>com.oneplus.calculator</code> and the name of the main component which is the launcher activity <code>com.android.calculator2.activity.MiniActivity</code> .</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IntentSenderActivity</span>: <span class="hljs-type">AppCompatActivity</span></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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_intent_sender)

        <span class="hljs-keyword">val</span> btnLaunch = findViewById&lt;Button&gt;(R.id.btn_launch)
        btnLaunch.setOnClickListener {
            <span class="hljs-comment">// Create an implicit Intent with the ACTION_MAIN action</span>
            <span class="hljs-keyword">val</span> intent = Intent(Intent.ACTION_MAIN)
            <span class="hljs-comment">// Set the component to target the calculator app</span>
            intent.setComponent(ComponentName(<span class="hljs-string">"com.oneplus.calculator"</span>, <span class="hljs-string">"com.android.calculator2.Calculator"</span>))
            <span class="hljs-keyword">try</span> {
                <span class="hljs-comment">// Attempt to start the calculator activity</span>
                startActivity(intent)
            } <span class="hljs-keyword">catch</span> (e: Exception) {
                <span class="hljs-comment">// Show a Toast message if the calculator app is not found</span>
                Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">"Calculator app not found"</span>, Toast.LENGTH_SHORT).show()
            }
        }
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720023371774/58a47b68-8a35-49eb-9326-66f1d8ed2048.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-implicit-intent">Implicit Intent</h2>
<p>Used when you declare an action to be performed. The system determines the appropriate component(s) to handle the intent based on the intent filter declarations in the manifest of other apps.</p>
<p>Example: Here’s how to launch the dialer app using an implicit intent.</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IntentReceiverActivity</span>: <span class="hljs-type">AppCompatActivity</span></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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_intent_receiver)

        <span class="hljs-keyword">val</span> btnLaunch = findViewById&lt;Button&gt;(R.id.btn_launch)

        btnLaunch.setOnClickListener {
            <span class="hljs-comment">// Create an implicit Intent with the ACTION_DIAL action</span>
            <span class="hljs-keyword">val</span> intent = Intent(Intent.ACTION_DIAL)
            <span class="hljs-comment">// Set the data to a phone number URI</span>
            intent.<span class="hljs-keyword">data</span> = Uri.parse(<span class="hljs-string">"tel:1234567890"</span>)
            <span class="hljs-comment">// Create a chooser dialog for the Intent</span>
            <span class="hljs-keyword">val</span> chooser = Intent.createChooser(intent, <span class="hljs-string">"Choose Dialer"</span>)
            <span class="hljs-comment">// Start the activity specified by the chooser</span>
            startActivity(chooser)
        }
    }
}
</code></pre>
<p>In this example, a chooser is created to display a chooser dialog, allowing you to select the desired dialer app. If you do not create a chooser as shown in the code below,</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> intent = Intent(Intent.ACTION_DIAL)
intent.<span class="hljs-keyword">data</span> = Uri.parse(<span class="hljs-string">"tel:1234567890"</span>)
startActivity(intent)
</code></pre>
<p>and directly launch the intent, the system will automatically use the default app set for that functionality (in this case, the dialer app). As a result, the chooser dialog will not appear, and the default app will be launched instead.</p>
<p>However, if no default app is set and if multiple matches are found, the system presents a chooser dialog to the user, allowing them to select the preferred app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720023301743/846d5121-5101-4952-820e-27c192a31b38.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-intent-filters">Intent Filters</h1>
<p>An <strong>Intent Filter</strong> is an expression in an app's manifest file that specifies the types of Intents the component can respond to. It allows the system to determine which components can handle a given Intent.</p>
<h3 id="heading-key-elements-of-intent-filters">Key Elements of Intent Filters</h3>
<ol>
<li><p><code>action</code>: Specifies the general action to be performed, such as <code>ACTION_VIEW</code>, <code>ACTION_EDIT</code>, or <code>ACTION_SEND</code>.</p>
</li>
<li><p><code>category</code>: Provides additional information about the action to be performed, like <code>CATEGORY_DEFAULT</code> or <code>CATEGORY_BROWSABLE</code>.</p>
</li>
<li><p><code>data</code>: Specifies the type of data the intent is expecting, using schemes, host names, MIME types, etc.</p>
</li>
</ol>
<p>When an app sends an Implicit Intent, the Android system matches it against the Intent Filters of all installed apps. If a match is found, the system launches the corresponding component. If multiple matches are found, the system presents a chooser dialog to the user, allowing them to select the preferred app.</p>
<p>Example: Here's how you can receive data from another app using intent filter.</p>
<ol>
<li>Create an activity where we will be receiving an image which will be shared from a browser app.</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IntentReceiverActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> imageView: ImageView

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_intent_receiver)

        imageView = findViewById(R.id.imageView)

        <span class="hljs-comment">// Handle the initial Intent that started the activity</span>
        handleIntent(intent)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onNewIntent</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>)</span></span> {
        <span class="hljs-keyword">super</span>.onNewIntent(intent)

        <span class="hljs-comment">// Handle any new Intents received while the activity is already running</span>
        handleIntent(intent)
    }

    <span class="hljs-comment">// Function to handle the Intent and extract the URI of the image</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">handleIntent</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>)</span></span> {

        <span class="hljs-comment">// Get the URI from the Intent extras</span>
        <span class="hljs-keyword">val</span> uri = <span class="hljs-keyword">if</span> (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.TIRAMISU) {
            intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::<span class="hljs-keyword">class</span>.java)
        } <span class="hljs-keyword">else</span> {
            intent.getParcelableExtra(Intent.EXTRA_STREAM)
        }

        <span class="hljs-comment">// If the URI is not null, set it as the image source for the ImageView</span>
        uri?.let {
            imageView.setImageURI(it)
        }
    }
}
</code></pre>
<p>When sharing an image from the browser app, if the activity is not already running, the <code>onCreate()</code> method is called. Inside <code>onCreate()</code>, the <code>handleIntent()</code> method processes the data (image URI). If the activity is already running, <code>onCreate()</code> is not called; instead, <code>onNewIntent()</code> is triggered, where we again call the <code>handleIntent()</code> method to handle the new data.</p>
<ol start="2">
<li>Inside the manifest file, declare the <code>IntentReceiverActivity</code> and the intent filters.</li>
</ol>
<pre><code class="lang-kotlin">&lt;manifest&gt;
    &lt;application ...&gt;
        ...
        &lt;activity
            android:name=<span class="hljs-string">"._05intent.IntentReceiverActivity"</span>
            android:exported=<span class="hljs-string">"true"</span>
            android:label=<span class="hljs-string">"Intents Receiver"</span>
            android:launchMode=<span class="hljs-string">"singleTop"</span> &gt;
            &lt;intent-filter&gt;

                &lt;!-- Filter <span class="hljs-keyword">for</span> SEND action --&gt;
                &lt;action android:name=<span class="hljs-string">"android.intent.action.SEND"</span> /&gt;

                &lt;!-- Category default <span class="hljs-keyword">is</span> required <span class="hljs-keyword">for</span> most implicit intents --&gt;
                &lt;category android:name=<span class="hljs-string">"android.intent.category.DEFAULT"</span> /&gt;

                &lt;!-- Specify the MIME type <span class="hljs-keyword">for</span> the <span class="hljs-keyword">data</span> the activity can handle --&gt;
                &lt;<span class="hljs-keyword">data</span> android:mimeType=<span class="hljs-string">"image/*"</span> /&gt;
            &lt;/intent-filter&gt;
        &lt;/activity&gt;
    &lt;/application&gt;
&lt;/manifest&gt;
</code></pre>
<ol>
<li><p><code>&lt;activity&gt;</code>:</p>
<ul>
<li><p>Declares an activity that is part of the application.</p>
</li>
<li><p><code>android:name</code>: Specifies the class name of the activity.</p>
</li>
<li><p><code>android:exported</code>: Indicates whether the activity can be launched by components of other applications.</p>
</li>
<li><p><code>android:label</code>: Specifies the user-readable name for the activity, displayed in the UI.</p>
</li>
<li><p><code>android:launchMode</code>: Determines how the activity is launched, with <code>"singleTop"</code> preventing multiple instances if one already exists at the top of the stack.v</p>
</li>
</ul>
</li>
<li><p><code>&lt;intent-filter&gt;</code>:</p>
<ul>
<li><p>Describes the types of intents the activity can respond to.</p>
</li>
<li><p><code>&lt;action android:name="android.intent.action.SEND" /&gt;</code>:</p>
<ul>
<li>Specifies that the activity can handle the <code>SEND</code> action, which is used when an app sends data to another app.</li>
</ul>
</li>
<li><p><code>&lt;category android:name="android.intent.category.DEFAULT" /&gt;</code>:</p>
<ul>
<li>Indicates that the activity can handle the default category of intents. This is required for most implicit intents.</li>
</ul>
</li>
<li><p><code>&lt;data android:mimeType="image/*" /&gt;</code>:</p>
<ul>
<li>Specifies the type of data the activity can handle. In this case, the activity is set up to handle image files.</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>This configuration ensures that the <code>IntentReceiverActivity</code> can be launched when an image is shared using an <code>Intent</code> with the <code>SEND</code> action and the MIME type of <code>image/*</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720023279251/b655a755-95c8-4682-a4ab-37db4948b13b.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Understanding intents and intent filters is essential for developing Android apps that communicate effectively with each other and provide a seamless user experience. Intents allow you to start activities, services, and broadcast receivers, enabling different app components to work together. By using explicit intents, you can target specific components, while implicit intents allow the system to choose the best component to handle the action. Intent filters in the manifest help declare what types of intents an activity can handle. With this knowledge, you can create more dynamic and interactive Android applications.</p>
]]></content:encoded></item><item><title><![CDATA[Android Activities and Their Lifecycle: A Developer's Guide]]></title><description><![CDATA[Introduction
An Activity is an application component that provides a screen for user interaction, allowing users to perform tasks like taking a photo, sending a message, or playing a video. Each activity is given a window to draw its user interface, ...]]></description><link>https://blog.yashraj.dev/android-activities-and-their-lifecycle-a-developers-guide</link><guid isPermaLink="true">https://blog.yashraj.dev/android-activities-and-their-lifecycle-a-developers-guide</guid><category><![CDATA[Android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Activities, Android, ActivityLifecycle]]></category><category><![CDATA[ActivityLifecycle]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Sun, 30 Jun 2024 23:12:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/TbLdLyigPj4/upload/c1f16930ec84b9fe9ff142db9cdacea1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>An <strong>Activity</strong> is an application component that provides a screen for user interaction, allowing users to perform tasks like taking a photo, sending a message, or playing a video. Each activity is given a window to draw its user interface, typically filling the screen but sometimes smaller and floating over other windows.</p>
<p>An application can have multiple activities, loosely bound to each other, with each activity declared in the manifest file. One activity is usually designated as the "main" or "launcher" activity, presented to the user when the application is launched for the first time. Each activity can start other activities to perform different actions.</p>
<h1 id="heading-activity-lifecycle">Activity Lifecycle</h1>
<p>Activities are managed by the Android operating system and follow a lifecycle consisting of various states and callbacks. Understanding the activity lifecycle is crucial for managing resources, handling user interactions, and maintaining a smooth user experience.</p>
<p>Here is a diagrammatic representation of activity lifecycle:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719608377173/545c48f2-0e3b-4db9-b3e7-0c33dd2f5776.png" alt class="image--center mx-auto" /></p>
<p>Here's a brief overview of the different states and callbacks in the lifecycle:</p>
<ol>
<li><p>onCreate():</p>
<ul>
<li><p>This is the first callback called when an activity is created.</p>
</li>
<li><p>Initialize essential components, set up the user interface, and perform any one-time setup tasks.</p>
</li>
</ul>
</li>
<li><p>onStart():</p>
<ul>
<li><p>The activity enters the "started" state after <code>onCreate()</code>.</p>
</li>
<li><p>The activity becomes visible to the user but doesn't have focus yet.</p>
</li>
</ul>
</li>
<li><p>onResume():</p>
<ul>
<li><p>The activity moves to the "resumed" state and comes into the foreground.</p>
</li>
<li><p>It is now fully visible and ready to receive user input.</p>
</li>
<li><p>Start animations, initialize sensors, or register broadcast receivers here.</p>
</li>
</ul>
</li>
<li><p>onPause():</p>
<ul>
<li><p>Triggered when the activity loses focus and goes into the background.</p>
</li>
<li><p>The activity is still partially visible but no longer has user input focus.</p>
</li>
<li><p>Release resources, pause animations, or save persistent data for a smooth transition.</p>
</li>
</ul>
</li>
<li><p>onStop():</p>
<ul>
<li><p>The activity enters the "stopped" state when it is no longer visible to the user.</p>
</li>
<li><p>This can happen when the user navigates away from the activity.</p>
</li>
<li><p>Perform operations that should happen when the activity is not visible, such as saving data or releasing resources that are not needed while the activity is not in the foreground.</p>
</li>
</ul>
</li>
<li><p>onRestart():</p>
<ul>
<li><p>Invoked if an activity was stopped and is now being restarted, before <code>onStart()</code>.</p>
</li>
<li><p>Perform any necessary setup before the activity becomes visible again.</p>
</li>
</ul>
</li>
<li><p>onDestroy():</p>
<ul>
<li><p>The final callback in the activity lifecycle, called when the system is about to destroy the activity.</p>
</li>
<li><p>Clean up all remaining resources, unregister receivers, and ensure all necessary data is saved.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-example">Example:</h3>
<ol>
<li><p><strong>Activity Declaration:</strong></p>
<ul>
<li>Define the activity class in your application. This is where you initialize components and set up the user interface.</li>
</ul>
</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DemoActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> TAG = <span class="hljs-string">"Demo_Activity"</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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo)
        Log.d(TAG, <span class="hljs-string">"onCreate: "</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onStart</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onStart()
        Log.d(TAG, <span class="hljs-string">"onStart: "</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onResume</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onResume()
        Log.d(TAG, <span class="hljs-string">"onResume: "</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onPause</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onPause()
        Log.d(TAG, <span class="hljs-string">"onPause: "</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onStop</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onStop()
        Log.d(TAG, <span class="hljs-string">"onStop: "</span>)
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onRestart</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onRestart()
        Log.d(TAG, <span class="hljs-string">"onRestart: "</span>)
    }

    <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()
        Log.d(TAG, <span class="hljs-string">"onDestroy: "</span>)
    }

}
</code></pre>
<ol start="2">
<li><p><strong>Manifest File:</strong></p>
<ul>
<li><p>Ensure your activity is declared in the manifest file. This is crucial for the Android system to recognize and manage your activity.</p>
</li>
<li><p><strong>Intent Filter:</strong></p>
<ul>
<li><p>Add an <code>&lt;intent-filter&gt;</code> to specify the types of intents the activity can handle.</p>
</li>
<li><p>For the launcher activity, include:</p>
<ul>
<li><p><code>&lt;action android:name="android.intent.action.MAIN" /&gt;</code> to indicate the entry point of the application.</p>
</li>
<li><p><code>&lt;category android:name="android.intent.category.LAUNCHER" /&gt;</code> to specify that this activity should appear in the app launcher.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-kotlin">    &lt;manifest&gt;
        &lt;application ...&gt;
        ...
            &lt;activity
                android:name=<span class="hljs-string">"._04activities.DemoActivity"</span>
                android:exported=<span class="hljs-string">"false"</span> &gt;
                &lt;intent-filter&gt;
                    &lt;action android:name=<span class="hljs-string">"android.intent.action.MAIN"</span> /&gt;

                    &lt;category android:name=<span class="hljs-string">"android.intent.category.LAUNCHER"</span> /&gt;
                &lt;/intent-filter&gt;
            &lt;/activity&gt;
        &lt;/application&gt;
    &lt;/manifest&gt;
</code></pre>
<h3 id="heading-lifecycle-methods-execution-in-different-scenarios"><strong>Lifecycle Methods Execution in Different Scenarios</strong></h3>
<ol>
<li><p><strong>When the App is Launched:</strong></p>
<p> The activity goes through the following lifecycle methods:</p>
<ul>
<li><p><code>onCreate()</code></p>
</li>
<li><p><code>onStart()</code></p>
</li>
<li><p><code>onResume()</code></p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719779429766/88d4b4b6-6255-4144-a901-f96f83846b03.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719780556234/0c51f32f-5fd8-4dfb-ba98-0c29536ffee7.png" alt class="image--center mx-auto" /></p>
<ol start="2">
<li><p><strong>When There is a Configuration Change (e.g., Screen Rotation):</strong></p>
<p> The activity handles the configuration change by going through these lifecycle methods:</p>
<ul>
<li><p><code>onPause()</code></p>
</li>
<li><p><code>onStop()</code></p>
</li>
<li><p><code>onDestroy()</code></p>
</li>
<li><p><code>onCreate()</code></p>
</li>
<li><p><code>onStart()</code></p>
</li>
<li><p><code>onResume()</code></p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719779460393/d2cb0efc-7ff2-4b67-96b6-d5bc6cb83ed8.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719780597506/ce478c25-c69e-44c2-8241-a6e2aed48623.png" alt class="image--center mx-auto" /></p>
<ol start="3">
<li><p><strong>When the App is Closed and Removed from the Background:</strong></p>
<ul>
<li><p>When the app is moved to the background, the activity goes through:</p>
<ul>
<li><p><code>onPause()</code></p>
</li>
<li><p><code>onStop()</code></p>
</li>
</ul>
</li>
<li><p>When the app is removed from the background, the activity enters:</p>
<ul>
<li><code>onDestroy()</code></li>
</ul>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719779474328/f77e45e2-79c6-4329-a6a5-5c8e2637cc6c.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719780631967/9956b7ea-17b0-49d4-b2e8-c37cc4411d2e.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In conclusion, Android activities are essential for creating engaging and dynamic user interfaces in apps. From initializing components in <code>onCreate()</code> to managing resources and responding to user interactions throughout its lifecycle, each activity plays a key role in delivering a seamless user experience. By understanding and effectively managing the activity lifecycle, you can optimize the performance, ensure efficient resource utilization, and enhance overall app reliability.</p>
]]></content:encoded></item><item><title><![CDATA[How to Use Content Provider and Content Resolver for data sharing between apps]]></title><description><![CDATA[Introduction
A content provider in Android provides secure access to a central repository of data that can be stored in a variety of formats, such as a SQLite database, a file, or a web service. It provides a standardized interface for other applicat...]]></description><link>https://blog.yashraj.dev/how-to-use-content-provider-and-content-resolver-for-data-sharing-between-apps</link><guid isPermaLink="true">https://blog.yashraj.dev/how-to-use-content-provider-and-content-resolver-for-data-sharing-between-apps</guid><category><![CDATA[content resolver]]></category><category><![CDATA[Android]]></category><category><![CDATA[content-provider]]></category><category><![CDATA[android component]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Wed, 26 Jun 2024 20:27:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/w33-zg-dNL4/upload/d21b9574bf8ad970dd2bc9b5a6907242.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>A content provider in Android provides secure access to a central repository of data that can be stored in a variety of formats, such as a SQLite database, a file, or a web service. It provides a standardized interface for other applications to securely access or modify the data as needed. In activities or fragments, we typically use a ContentResolver object within our application context to interact with content providers. The ContentResolver communicates with the provider, which is an instance of a class implementing ContentProvider.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719351964068/8c526b4d-3fd0-40e7-9dc4-1d5f06a288ce.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-what-is-a-cursor">What is a Cursor?</h1>
<p>When querying a ContentProvider, the result is typically returned as a Cursor object. A Cursor provides read-write access to the result set of a database query. It allows you to move through the data, retrieve column values, and perform other operations on the result set. When using a ContentResolver to query a ContentProvider, you'll typically receive and work with a Cursor to access the returned data.</p>
<h1 id="heading-what-is-a-content-provider">What is a Content Provider?</h1>
<p>A content provider in Android helps to securely share data between applications by providing an abstraction layer. It exposes a set of CRUD (Create, Read, Update, Delete) operations that can be performed on the data, allowing applications to access data from different sources such as a database, a file, or a web service.</p>
<h3 id="heading-example-implementation">Example Implementation</h3>
<p>Here I have created a custom ContentProvider which will be sharing the data with other apps. Also, I have used SharedPreference for storage here, you can use SQLite database or any other means of storage.</p>
<h4 id="heading-provider-app">Provider App</h4>
<ol>
<li><strong>ContentProvider Implementation (PreferencesContentProvider.kt):</strong></li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-comment">// PreferencesContentProvider class to expose SharedPreferences via a ContentProvider</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PreferencesContentProvider</span> : <span class="hljs-type">ContentProvider</span></span>() {

    <span class="hljs-comment">// SharedPreferences instance</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> preferences: SharedPreferences

    <span class="hljs-comment">// Called when the provider is created</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">()</span></span>: <span class="hljs-built_in">Boolean</span> {
        preferences = PreferenceManager.getDefaultSharedPreferences(context)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }

    <span class="hljs-comment">// Handle query requests from clients</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">query</span><span class="hljs-params">(
        uri: <span class="hljs-type">Uri</span>,
        projection: <span class="hljs-type">Array</span>&lt;<span class="hljs-type">out</span> <span class="hljs-type">String</span>&gt;?,
        selection: <span class="hljs-type">String</span>?,
        selectionArgs: <span class="hljs-type">Array</span>&lt;<span class="hljs-type">out</span> <span class="hljs-type">String</span>&gt;?,
        sortOrder: <span class="hljs-type">String</span>?
    )</span></span>: Cursor? {
        <span class="hljs-comment">// Create a cursor to hold the key-value pairs from SharedPreferences</span>
        <span class="hljs-keyword">val</span> matrixCursor = MatrixCursor(arrayOf(<span class="hljs-string">"key"</span>, <span class="hljs-string">"value"</span>))
        <span class="hljs-keyword">val</span> allEntries = preferences.all
        <span class="hljs-keyword">for</span> ((key, value) <span class="hljs-keyword">in</span> allEntries) {
            <span class="hljs-comment">// Add each key-value pair to the cursor</span>
            matrixCursor.addRow(arrayOf(key, value.toString()))
        }
        <span class="hljs-keyword">return</span> matrixCursor
    }

    <span class="hljs-comment">// Return the MIME type of data in the content provider</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getType</span><span class="hljs-params">(uri: <span class="hljs-type">Uri</span>)</span></span>: String? {
        <span class="hljs-keyword">return</span> <span class="hljs-string">"vnd.android.cursor.dir/vnd.<span class="hljs-subst">${PreferencesContract.AUTHORITY}</span>.preferences"</span>
    }

    <span class="hljs-comment">// Handle requests to insert a new row</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">insert</span><span class="hljs-params">(uri: <span class="hljs-type">Uri</span>, values: <span class="hljs-type">ContentValues</span>?)</span></span>: Uri? {
        <span class="hljs-keyword">val</span> editor = preferences.edit()
        values?.let {
            <span class="hljs-keyword">for</span> (key <span class="hljs-keyword">in</span> it.keySet()) {
                <span class="hljs-keyword">val</span> value = it.getAsString(key)
                Log.d(<span class="hljs-string">"TAG"</span>, <span class="hljs-string">"insert: <span class="hljs-variable">$key</span> <span class="hljs-variable">$value</span>"</span>)
                <span class="hljs-comment">// Save each key-value pair to SharedPreferences</span>
                editor.putString(key, value)
            }
        }
        editor.apply()
        <span class="hljs-comment">// Notify any listeners that the data has changed</span>
        context?.contentResolver?.notifyChange(uri, <span class="hljs-literal">null</span>)
        <span class="hljs-keyword">return</span> uri
    }

    <span class="hljs-comment">// Handle requests to delete one or more rows</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">delete</span><span class="hljs-params">(uri: <span class="hljs-type">Uri</span>, selection: <span class="hljs-type">String</span>?, selectionArgs: <span class="hljs-type">Array</span>&lt;<span class="hljs-type">out</span> <span class="hljs-type">String</span>&gt;?)</span></span>: <span class="hljs-built_in">Int</span> {
        <span class="hljs-keyword">val</span> editor = preferences.edit()
        selectionArgs?.forEach { key -&gt;
            <span class="hljs-comment">// Remove each key specified in the selectionArgs</span>
            editor.remove(key)
        }
        editor.apply()
        <span class="hljs-comment">// Notify any listeners that the data has changed</span>
        context?.contentResolver?.notifyChange(uri, <span class="hljs-literal">null</span>)
        <span class="hljs-keyword">return</span> selectionArgs?.size ?: <span class="hljs-number">0</span>
    }

    <span class="hljs-comment">// Handle requests to update one or more rows</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">update</span><span class="hljs-params">(uri: <span class="hljs-type">Uri</span>, values: <span class="hljs-type">ContentValues</span>?, selection: <span class="hljs-type">String</span>?, selectionArgs: <span class="hljs-type">Array</span>&lt;<span class="hljs-type">out</span> <span class="hljs-type">String</span>&gt;?)</span></span>: <span class="hljs-built_in">Int</span> {
        <span class="hljs-comment">// Use the insert method to handle updates as well</span>
        <span class="hljs-keyword">return</span> insert(uri, values)?.let { <span class="hljs-number">1</span> } ?: <span class="hljs-number">0</span>
    }
}

<span class="hljs-comment">// Object to define the contract for accessing the content provider</span>
<span class="hljs-keyword">object</span> PreferencesContract {
    <span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> AUTHORITY = <span class="hljs-string">"com.example.blogs._3content_providers"</span>
    <span class="hljs-keyword">val</span> CONTENT_URI: Uri = Uri.parse(<span class="hljs-string">"content://<span class="hljs-variable">$AUTHORITY</span>/preferences"</span>)
}
</code></pre>
<p>MatrixCursor is a mutable cursor implementation backed by an array of objects. Unlike cursors tied to database results, MatrixCursor allows for the dynamic addition of rows directly in memory, making it ideal for creating custom, in-memory datasets. This feature is particularly useful in scenarios where data does not originate from a database, such as data from SharedPreferences. In this ContentProvider implementation, MatrixCursor is used to create a cursor-like interface for SharedPreferences data, enabling seamless integration and manipulation as if it were retrieved from a database. It allows us to:</p>
<ul>
<li><p>Define custom columns ("key" and "value") that match our SharedPreferences structure.</p>
</li>
<li><p>Dynamically add rows for each key-value pair in SharedPreferences.</p>
</li>
<li><p>Return a Cursor object that client application can use to read the data, maintaining a consistent interface with other ContentProviders.</p>
</li>
<li><p>Avoid the need for an actual database, as SharedPreferences is already an efficient key-value store.</p>
</li>
</ul>
<ol start="2">
<li>Declare ContentProvider in AndroidManifest.xml:</li>
</ol>
<pre><code class="lang-kotlin">&lt;manifest xmlns:android=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
    xmlns:tools=<span class="hljs-string">"http://schemas.android.com/tools"</span>
    <span class="hljs-keyword">package</span>=<span class="hljs-string">"com.example.blogs"</span>&gt;

    &lt;application 
        ...&gt;
        ...
        &lt;provider
         android:name=<span class="hljs-string">"com.example.blogs._3content_providers.PreferencesContentProvider"</span>
         android:authorities=<span class="hljs-string">"com.example.blogs._3content_providers"</span>
         android:enabled=<span class="hljs-string">"true"</span>
         android:exported=<span class="hljs-string">"true"</span>
         android:grantUriPermissions=<span class="hljs-string">"true"</span> /&gt;

    &lt;/application&gt;
&lt;/manifest&gt;
</code></pre>
<ol start="3">
<li>Activity to Save Data (ContentProviderActivity.kt):</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ContentProviderActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: ActivityContentProviderBinding

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        binding = ActivityContentProviderBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.apply {
            btnSaveData.setOnClickListener {
                insertPreference(<span class="hljs-string">"name"</span>, etSampleData.text.toString())
                etSampleData.text.clear()
            }
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">insertPreference</span><span class="hljs-params">(key: <span class="hljs-type">String</span>, value: <span class="hljs-type">String</span>)</span></span> {
        <span class="hljs-keyword">val</span> uri = PreferencesContract.CONTENT_URI
        <span class="hljs-keyword">val</span> values = ContentValues().apply {
            put(key, value)
        }
        contentResolver.insert(uri, values)
    }
}
</code></pre>
<h3 id="heading-some-built-in-content-providers-in-android">Some Built-in Content Providers in Android</h3>
<ul>
<li><p><strong>ContactsContract:</strong></p>
<p>  This built-in content provider is used to provide access to the device's contact data such as a phone number or an email address.</p>
</li>
<li><p><strong>MediaStore:</strong></p>
<p>  This built-in content provider is used to provide access to the device's media files such as videos, photos, and also audio recordings.</p>
</li>
</ul>
<h1 id="heading-what-is-a-content-resolver">What is a Content Resolver?</h1>
<p>A <code>ContentResolver</code> is an object that acts as an intermediary to communicate with content providers. When we need to access a content provider, we use a <code>ContentResolver</code> object within our application context. The <code>ContentResolver</code> sends data requests to the provider, which performs the requested actions and returns the results back to the <code>ContentResolver</code>. This process allows secure data sharing between different applications.</p>
<p>The <code>ContentResolver</code> is used to perform operations like querying, inserting, updating, and deleting data through the ContentProvider. It uses URIs to specify the content and operations.</p>
<p>Here's how you can use the <code>ContentResolver</code> to query the data exposed by the <code>PreferencesContentProvider</code>. In the code below, I have shown how you can receive the data shared by our provider app:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ResolverActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: ActivityResolverBinding
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> text: String

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        binding = ActivityResolverBinding.inflate(layoutInflater)
        setContentView(binding.root)

        queryPreferences()
        binding.btnGetData.setOnClickListener {
            queryPreferences()
            binding.tvProviderData.text = text
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">queryPreferences</span><span class="hljs-params">()</span></span> {
        <span class="hljs-comment">// Define the URI for the content to access</span>
        <span class="hljs-keyword">val</span> uri = PreferencesContract.CONTENT_URI

        <span class="hljs-comment">// Define the columns to retrieve</span>
        <span class="hljs-keyword">val</span> projection = arrayOf(<span class="hljs-string">"key"</span>, <span class="hljs-string">"value"</span>)

        <span class="hljs-comment">// Use the content resolver to query the content provider</span>
        <span class="hljs-keyword">val</span> cursor = contentResolver.query(uri, projection, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">null</span>)

        cursor?.apply {
            <span class="hljs-comment">// Iterate through the cursor rows</span>
            <span class="hljs-keyword">while</span> (moveToNext()) {
                <span class="hljs-comment">// Get the key and value from the current row</span>
                <span class="hljs-keyword">val</span> key = getString(getColumnIndexOrThrow(<span class="hljs-string">"key"</span>))
                <span class="hljs-keyword">val</span> value = getString(getColumnIndexOrThrow(<span class="hljs-string">"value"</span>))

            <span class="hljs-comment">// Assign the value to text variable</span>
                Log.d(<span class="hljs-string">"TAG"</span>, <span class="hljs-string">"queryPreferences: Key: <span class="hljs-variable">$key</span>, Value: <span class="hljs-variable">$value</span>"</span>)
                text = value
            }
            <span class="hljs-comment">// Close the cursor to release resources</span>
            close()
        }
    }
}

<span class="hljs-comment">// Define the PreferencesContract object to store constants related to the content provider</span>
<span class="hljs-keyword">object</span> PreferencesContract {
    <span class="hljs-comment">// The authority of the content provider</span>
    <span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> AUTHORITY = <span class="hljs-string">"com.example.blogs._3content_providers"</span>

    <span class="hljs-comment">// The URI for the preferences table</span>
    <span class="hljs-keyword">val</span> CONTENT_URI: Uri = Uri.parse(<span class="hljs-string">"content://<span class="hljs-variable">$AUTHORITY</span>/preferences"</span>)
}
</code></pre>
<p>In the manifest file, we will write the package name of our provider app</p>
<pre><code class="lang-kotlin">&lt;manifest&gt;
   &lt;queries&gt;
      &lt;<span class="hljs-keyword">package</span> android:name=<span class="hljs-string">"com.example.blogs"</span> /&gt;
   &lt;/queries&gt;
   &lt;application
        ...&gt;
        ....
    &lt;/application&gt;
&lt;manifest&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719260751161/183bc59b-3068-41f7-b1b2-9ee2b982827e.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>By using a ContentProvider, you can securely share data between applications, providing a standardized interface for CRUD operations. The example shows how to create a custom ContentProvider to expose SharedPreferences data and access it from another application using a ContentResolver. Using proper URI matching and handling ensures secure and organized access to the shared data. Understanding the role of the ContentResolver is critical, as it serves as the bridge between the client application and the ContentProvider, allowing seamless data access and manipulation.</p>
]]></content:encoded></item><item><title><![CDATA[Snap N Search: Your Personal Visual Exploration Assistant]]></title><description><![CDATA[In today's fast-paced world, we're constantly surrounded by visual information, from product labels to street signs, and everything in between. With the Snap & Search app, you can instantly unlock the power of Google Lens and explore the world around...]]></description><link>https://blog.yashraj.dev/snap-n-search-your-personal-visual-exploration-assistant</link><guid isPermaLink="true">https://blog.yashraj.dev/snap-n-search-your-personal-visual-exploration-assistant</guid><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Thu, 13 Jun 2024 14:23:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718287585991/f1000df8-d417-4006-a16a-2c1311735e7e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's fast-paced world, we're constantly surrounded by visual information, from product labels to street signs, and everything in between. With the Snap &amp; Search app, you can instantly unlock the power of Google Lens and explore the world around you with just a few taps.</p>
<p>The Snap &amp; Search app is a game-changer in the world of visual search. Its sleek and user-friendly interface allows you to capture screenshots and instantly search with Google Lens, providing accurate and relevant information about anything you see on your screen.</p>
<p>Capturing screenshots is a breeze with Snap &amp; Search. For Android 9 and later versions, you can use the handy floating button provided by the app. This floating button can be customized to your liking - you can change its color, size, and even transparency to suit your preferences. If you're on Android 12 or higher, you have the additional option to simply long-press the home button to capture a screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718288509421/8ebd0b90-69e4-45bb-bef3-2bd7c19f9f79.png?height=500" alt class="image--center mx-auto" /></p>
<p>One of the standout features of Snap N Search is its commitment to privacy. Unlike many other apps, it doesn't require any storage permissions, ensuring that your data remains secure and private. Additionally, the app itself doesn't require internet access, which means that none of your data is sent anywhere unless you actively choose to use Google Lens, which does require an internet connection.</p>
<p>Using Snap N Search is incredibly simple. Just capture a screenshot of anything you want to explore, whether it's a product label, a piece of text, or even a landmark. The app will then seamlessly integrate with Google Lens, providing you with detailed information, translations, and even the ability to search for similar images or products.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718288256196/44dce663-f306-422b-8a6c-0e7f4e0f6107.png?height=500" alt class="image--center mx-auto" /></p>
<p>One of the most exciting aspects of Snap N Search is its open-source nature. By making the app's source code available to the community, the developers are promoting transparency and encouraging community-driven development.</p>
<p>Whether you're a curious explorer, a savvy shopper, or simply someone who wants to learn more about the world around them, Snap N Search is the perfect companion app. With its powerful visual search capabilities, privacy-focused design, and user-friendly interface, it's sure to become an essential tool in your digital arsenal.</p>
<p>So why wait? Download Snap &amp; Search today and start exploring the world with just a snap!. And if you need any guidance, be sure to check out the helpful tutorial video that walks you through using all of the app's great features.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=m-fHls09JRE">https://www.youtube.com/watch?v=m-fHls09JRE</a></div>
]]></content:encoded></item><item><title><![CDATA[Exploring Android Services: Definitions, Types, and Use Cases]]></title><description><![CDATA[Introduction
Services is an Android app component that is used to perform long-running task in the background that does not have a UI. It can be used for various functionalities which don't need user input such as playing music, downloading data, wat...]]></description><link>https://blog.yashraj.dev/exploring-android-services-definitions-types-and-use-cases</link><guid isPermaLink="true">https://blog.yashraj.dev/exploring-android-services-definitions-types-and-use-cases</guid><category><![CDATA[services in android]]></category><category><![CDATA[android app development]]></category><category><![CDATA[Android]]></category><category><![CDATA[Kotlin]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Fri, 24 May 2024 10:03:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/f0dJjQMhfXo/upload/683d29731ca2edf422cbb4329a03244e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Services is an Android app component that is used to perform long-running task in the background that does not have a UI. It can be used for various functionalities which don't need user input such as playing music, downloading data, watching network traffic and much more. Services can also be used for building a continuous connection to a distant server, for various purposes such as sending or receiving messages from a chat server.</p>
<h1 id="heading-types-of-services-in-android">Types of Services in Android</h1>
<ul>
<li><p>Foreground Services</p>
</li>
<li><p>Background Services</p>
</li>
<li><p>Bound Services</p>
</li>
</ul>
<h2 id="heading-foreground-services">Foreground Services</h2>
<p>Foreground services are those services that notify the users about ongoing operations by displaying a notification in the notification bar. Users can interact with the service through the notification provided by the task. These services can keep running even if the app is terminated. Example use cases:</p>
<ol>
<li><p>A music streaming app uses a foreground service for continuous playback and player controls.</p>
</li>
<li><p>A video call app employs a foreground service for maintaining an active call session with video and audio.</p>
</li>
<li><p>An audio recording app starts a foreground service for capturing high-quality audio recordings.</p>
</li>
</ol>
<p>Here is a simple example code for a Foreground Service:</p>
<p><strong>Service Class (ForegroundService.kt):</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ForegroundService</span> : <span class="hljs-type">Service</span></span>() {
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> TAG = <span class="hljs-string">"ForegroundService"</span>
    <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-keyword">var</span> isServiceRunning = <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">onCreate</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.onCreate()
        showToast(<span class="hljs-string">"Service is being created"</span>)
    }

    <span class="hljs-meta">@RequiresApi(Build.VERSION_CODES.O)</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> {
        showToast(<span class="hljs-string">"Service is starting"</span>)
        isServiceRunning = <span class="hljs-literal">true</span>
        <span class="hljs-keyword">val</span> notificationManager =
            <span class="hljs-keyword">this</span>.getSystemService(Context.NOTIFICATION_SERVICE) <span class="hljs-keyword">as</span> NotificationManager

        <span class="hljs-comment">// Create a notification channel</span>
        <span class="hljs-keyword">val</span> channel = NotificationChannel(
            <span class="hljs-string">"notification-channel-id"</span>,
            <span class="hljs-string">"notification-channel-name"</span>,
            NotificationManager.IMPORTANCE_DEFAULT
        )
        notificationManager.createNotificationChannel(channel)

        <span class="hljs-comment">// Build the notification</span>
        <span class="hljs-keyword">val</span> notification =
            NotificationCompat.Builder(<span class="hljs-keyword">this</span>, <span class="hljs-string">"notification-channel-id"</span>)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentText(<span class="hljs-string">"Foreground Service Running!"</span>)
                .setContentTitle(<span class="hljs-string">"Foreground Service"</span>)
                .build()

        <span class="hljs-comment">// Start the service in the foreground with the notification   </span>
        startForeground(<span class="hljs-number">1</span>, notification)

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onStartCommand(intent, flags, startId)
    }

    <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> {
        isServiceRunning = <span class="hljs-literal">false</span>
        showToast(<span class="hljs-string">"Service is being destroyed"</span>)
        <span class="hljs-keyword">super</span>.onDestroy()
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onBind</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>?)</span></span>: IBinder? {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showToast</span><span class="hljs-params">(message: <span class="hljs-type">String</span>)</span></span> {
        Toast.makeText(<span class="hljs-keyword">this</span>, message, Toast.LENGTH_SHORT).show()
    }
}
</code></pre>
<p><strong>Activity Class (ServiceActivity.kt):</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServiceActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: Activity2serviceBinding
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> foregroundIntent: Intent

    <span class="hljs-meta">@RequiresApi(Build.VERSION_CODES.O)</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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        binding = Activity2serviceBinding.inflate(layoutInflater)
        setContentView(binding.root)

        <span class="hljs-comment">// Create an intent to start ForegroundService</span>
        foregroundIntent= Intent(<span class="hljs-keyword">this</span>, ForegroundService::<span class="hljs-keyword">class</span>.java)

        binding.startService.setOnClickListener {
             // Check <span class="hljs-keyword">if</span> ForegroundService <span class="hljs-keyword">is</span> already running
            <span class="hljs-keyword">if</span> (ForegroundService.isServiceRunning) {
                Toast.makeText(this, <span class="hljs-string">"Service is already running"</span>, Toast.LENGTH_SHORT).show()
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">// Start the ForegroundService if not already running</span>
                startService(foregroundIntent)
            }
        }
        binding.stopService.setOnClickListener {
            <span class="hljs-comment">// Stop the ForegroundService</span>
            stopService(foregroundIntent)
        }  
    }
}
</code></pre>
<p><strong>Manifest File (AndroidManifest.kt):</strong></p>
<pre><code class="lang-kotlin">&lt;manifest xmlns:android=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
    xmlns:tools=<span class="hljs-string">"http://schemas.android.com/tools"</span> &gt;

&lt;!-- Permission to post notifications. Required <span class="hljs-keyword">for</span> foreground services to show notifications. --&gt;
    &lt;uses-permission android:name=<span class="hljs-string">"android.permission.POST_NOTIFICATIONS"</span> /&gt;

&lt;!-- Permission to run foreground services. Required to start services <span class="hljs-keyword">in</span> the foreground. --&gt;
    &lt;uses-permission android:name=<span class="hljs-string">"android.permission.FOREGROUND_SERVICE"</span> /&gt;

&lt;application&gt;
        &lt;!-- Other application components like activities and receivers --&gt;
...


&lt;!-- Declaration of the ForegroundService. This tells the system about the service so it can be started and used <span class="hljs-keyword">by</span> the app. --&gt;
&lt;service android:name=<span class="hljs-string">".ForegroundService"</span>/&gt;
&lt;/application&gt;
&lt;/manifest&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716491243134/647d02e2-ea03-4732-97ed-0be381b99cac.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-background-services">Background Services</h2>
<p>Background Services are those that perform tasks without directly notifying the users or requiring interaction from users. These services work in the background, i.e., they can continue running even when the app is not actively visible on the screen or when the device is locked. However, it's important to note that if the app is stopped or no longer running, background services associated with that app will also stop running, as they are tied to the lifecycle of the app. Example use cases:</p>
<ol>
<li><p>A backup app initiates background services for scheduled backups of user data to cloud storage.</p>
</li>
<li><p>A news app uses background services to fetch and update news feeds at set intervals.</p>
</li>
<li><p>An app that syncs data with a server uses background services for periodic synchronization without user intervention.</p>
</li>
</ol>
<p>Here is a simple example code for a Background Service:</p>
<p><strong>Service Class (BackgroundService.kt):</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BackgroundService</span> : <span class="hljs-type">Service</span></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">()</span></span> {
        <span class="hljs-keyword">super</span>.onCreate()
        showToast(<span class="hljs-string">"Service is being created"</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> {
        showToast(<span class="hljs-string">"Service is starting"</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onStartCommand(intent, flags, startId)
    }

    <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> {
        showToast(<span class="hljs-string">"Service is being destroyed"</span>)
        <span class="hljs-keyword">super</span>.onDestroy()
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onBind</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>?)</span></span>: IBinder? {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showToast</span><span class="hljs-params">(message: <span class="hljs-type">String</span>)</span></span> {
        Toast.makeText(<span class="hljs-keyword">this</span>, message, Toast.LENGTH_SHORT).show()
    }
}
</code></pre>
<p><strong>Activity Class (ServiceActivity.kt):</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServiceActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: Activity2serviceBinding
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> backgroundIntent: Intent

    <span class="hljs-meta">@RequiresApi(Build.VERSION_CODES.O)</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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        binding = Activity2serviceBinding.inflate(layoutInflater)
        setContentView(binding.root)

        <span class="hljs-comment">// Create an intent to start BackgroundService</span>
        backgroundIntent = Intent(<span class="hljs-keyword">this</span>, BackgroundService::<span class="hljs-keyword">class</span>.java)

        binding.startService.setOnClickListener {     
            <span class="hljs-comment">// Start the BackgroundService if not already running</span>
            startService(backgroundIntent)          
        }
        binding.stopService.setOnClickListener {
            <span class="hljs-comment">// Stop the BackgroundService </span>
            stopService(backgroundIntent)
        }  
    }

    <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-comment">// Stop the BackgroundService (prevent memory leaks)</span>
        stopService(backgroundIntent)
        <span class="hljs-keyword">super</span>.onDestroy()
    }
}
</code></pre>
<p><strong>Manifest File (AndroidManifest.kt):</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">application</span>&gt;</span>
...
<span class="hljs-tag">&lt;<span class="hljs-name">service</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">".BackgroundService"</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716491025688/cdfb3bc4-e7bf-451b-9b22-860d4a669e96.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-bound-services">Bound Services</h2>
<p>Bound Services allows app components like activities to bind themselves to the service. These services perform the task as long as the component is bound to it. Multiple components can bind themselves with a service at a time. To bind a service to the component <code>bindService()</code> method is used and components should unbind from the service when they no longer require its functionality to release resources and avoid memory leaks. Example use cases:</p>
<ol>
<li><p>A messaging app binds to a service for message delivery and synchronization across devices.</p>
</li>
<li><p>A fitness tracker app binds to a service for real-time location tracking during workouts.</p>
</li>
<li><p>A file transfer app binds to a service for managing file uploads and downloads in the background.</p>
</li>
</ol>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">All the services run on the main thread or the UI thread by default. So, if you are performing some long-running tasks make sure to create a background thread for that or simply use Coroutines if working in kotlin.</div>
</div>

<h1 id="heading-lifecycle-of-a-service">Lifecycle of a Service</h1>
<p>In Android, there are two categories of services bound services and started services and each of these has a different lifecycle.</p>
<h3 id="heading-started-service-lifecycle">Started Service Lifecycle</h3>
<p>This service will start when an app component calls the <code>startService()</code> method. After that, the service can keep on running even if the component that started the service is destroyed. To stop a running service we can use the <code>stopService()</code> method or the service can stop itself using the <code>stopSelf()</code> method.</p>
<ol>
<li><p>onCreate(): This method gets called when the service is first created using <code>startService()</code> method. It is used to perform one-time setup procedures such as initializing resources that will be used by the service.</p>
</li>
<li><p>onStartCommand(): This method gets called every time when the service is started using <code>startService()</code> method. If the service is running already, this method will be called again with a new intent. This is where you define what the service should do in response to the intent passed by <code>startService()</code>.</p>
</li>
<li><p>onDestroy(): The <code>onDestroy()</code> method is called when the service is no longer used and is destroyed. The service is destroyed using the <code>stopService()</code> method which is called by the app component that was used to start the service or the service can stop itself using the <code>stopSelf()</code> method. This is where we should clean up all the resources that are used in the service like removing listeners, unregistering receivers etc.</p>
</li>
</ol>
<p>You can check the Foreground Service or Background Service for examples.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716504224733/3c940e53-38d8-4222-b666-87c4bb18b10f.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-bound-service-lifecycle">Bound Service Lifecycle</h3>
<ol>
<li><p>onCreate(): This method gets called when the service is first created using <code>startService()</code> method or <code>bindService()</code> method.</p>
</li>
<li><p>onStartCommand(): [same as in started service]. It won't get called if <code>bindService()</code> is used to start the service.</p>
</li>
<li><p>onBind(): The <code>onBind()</code> method is called when a component binds to the service using the <code>bindService()</code> method. If the service is not running already then <code>onCreate()</code> will be called first then <code>onBind()</code> else the <code>onBind()</code> will be called directly. It returns an <strong>IBinder</strong> instance that is used by the component to communicate with the service. The <strong>IBinder</strong> acts as an interface for the component to call method within the service.</p>
<p> What binding really means here is that a component (for example, an activity) establishes a connection with the Service class to call its methods for performing some actions or retrieving data.</p>
</li>
<li><p>onUnbind(): The <code>onUnbind()</code> method is called when the service is unbound from the component using the <code>unBindServce()</code> method. This is where we can clean up the resources related to binding that are no longer needed. It returns a boolean value that decides if you want to call the <code>onRebind(</code>) method, returns true if you want to call <code>onRebind()</code> else return false.</p>
</li>
<li><p>onRebind(): The <code>onRebind()</code> method is called only if <code>onUnbind()</code> returns true. This method is used to handle new binding requests after the service has been unbound or to reinitialize the resources that have been cleaned up in the <code>onUnbind()</code> method.</p>
</li>
<li><p>onDestroy(): [same as in started service]</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716506560217/90e031b5-6056-4dc8-8790-494c9f50ff71.png" alt class="image--center mx-auto" /></p>
<p>Here is a simple example code for a Background Service:</p>
<p><strong>Service Class (BoundService.kt):</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BoundService</span>: <span class="hljs-type">Service</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> TAG = <span class="hljs-string">"BoundService"</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> binder = LocalBinder()

    <span class="hljs-keyword">inner</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LocalBinder</span> : <span class="hljs-type">Binder</span></span>() {
        <span class="hljs-comment">// Return this instance of MyBoundService so clients can call public methods</span>
        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getService</span><span class="hljs-params">()</span></span>: BoundService = <span class="hljs-keyword">this</span><span class="hljs-symbol">@BoundService</span>
    }

    <span class="hljs-comment">// Called when the service is first created.</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">()</span></span> {
        <span class="hljs-keyword">super</span>.onCreate()
        showToast(<span class="hljs-string">"Service is being created"</span>)
    }

    <span class="hljs-comment">// Called every time a component explicitly starts the service using startService()</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> {
        showToast(<span class="hljs-string">"Service is starting"</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onStartCommand(intent, flags, startId)
    }

    <span class="hljs-comment">// Called when a component binds to the service using bindService()</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onBind</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>?)</span></span>: IBinder? {
        showToast(<span class="hljs-string">"Service is being bound"</span>)
        <span class="hljs-keyword">return</span> binder
    }

    <span class="hljs-comment">// Called when all components have unbound from the service</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onUnbind</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>?)</span></span>: <span class="hljs-built_in">Boolean</span> {
        showToast(<span class="hljs-string">"Service is being unbound"</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onUnbind(intent)
    }

    <span class="hljs-comment">// Called when a client re-binds to the service after it had previously unbound</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onRebind</span><span class="hljs-params">(intent: <span class="hljs-type">Intent</span>?)</span></span> {
        showToast(<span class="hljs-string">"Service is being re-bound"</span>)
        <span class="hljs-keyword">super</span>.onRebind(intent)
    }

    <span class="hljs-comment">// Called when the service is no longer used and is being destroyed</span>
    <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> {
        showToast(<span class="hljs-string">"Service is being destroyed"</span>)
        <span class="hljs-keyword">super</span>.onDestroy()
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showToast</span><span class="hljs-params">(message: <span class="hljs-type">String</span>)</span></span> {
        Toast.makeText(<span class="hljs-keyword">this</span>, message, Toast.LENGTH_SHORT).show()
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getData</span><span class="hljs-params">()</span></span>: String {
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Data from Bound Service"</span>
    }
}
</code></pre>
<p><strong>Activity Class (ServiceActivity.kt):</strong></p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServiceActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: Activity2serviceBinding
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> boundIntent: Intent
    <span class="hljs-comment">// Reference to the bound service</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> boundService: BoundService? = <span class="hljs-literal">null</span> 
    <span class="hljs-comment">// Flag to track if the service is bound</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> isBound: <span class="hljs-built_in">Boolean</span> = <span class="hljs-literal">false</span>

    <span class="hljs-comment">// ServiceConnection to manage connection with the BoundService</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> connection = <span class="hljs-keyword">object</span> : ServiceConnection {
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onServiceConnected</span><span class="hljs-params">(className: <span class="hljs-type">ComponentName</span>, service: <span class="hljs-type">IBinder</span>)</span></span> {
            <span class="hljs-keyword">val</span> binder = service <span class="hljs-keyword">as</span> BoundService.LocalBinder
            boundService = binder.getService()
            isBound = <span class="hljs-literal">true</span>
            Log.d(TAG, <span class="hljs-string">"Service Connected"</span>)
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onServiceDisconnected</span><span class="hljs-params">(arg0: <span class="hljs-type">ComponentName</span>)</span></span> {
            boundService = <span class="hljs-literal">null</span>
            isBound = <span class="hljs-literal">false</span>
            Log.d(TAG, <span class="hljs-string">"Service Disconnected"</span>)
        }
    }

    <span class="hljs-meta">@RequiresApi(Build.VERSION_CODES.O)</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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        binding = Activity2serviceBinding.inflate(layoutInflater)
        setContentView(binding.root)

        <span class="hljs-comment">// Create an intent to start BoundService</span>
        boundIntent = Intent(<span class="hljs-keyword">this</span>, BoundService::<span class="hljs-keyword">class</span>.java)

        binding.startService.setOnClickListener {
            // Start the BoundService
            startService(boundIntent)
        }

        binding.stopService.setOnClickListener {
            // Stop the BoundService
            stopService(boundIntent)
        }

        binding.bindService.setOnClickListener {
            // Bind to the BoundService
            bindService(boundIntent, connection, BIND_AUTO_CREATE)
        }

        binding.unBindService.setOnClickListener {
            <span class="hljs-keyword">if</span> (isBound) {
                // Unbind from the BoundService
                unbindService(connection)
                isBound = <span class="hljs-literal">false</span>
            } <span class="hljs-keyword">else</span>
                Toast.makeText(this, <span class="hljs-string">"Service is not bound"</span>, Toast.LENGTH_SHORT).show()
        }

        binding.dataFromBoundService.setOnClickListener {
            <span class="hljs-keyword">if</span> (isBound) {
                <span class="hljs-comment">// Get data from the bound service</span>
                <span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span> = boundService?.getData()
                binding.textView.text = <span class="hljs-keyword">data</span>
            } <span class="hljs-keyword">else</span>
                Toast.makeText(<span class="hljs-keyword">this</span>, <span class="hljs-string">"Service is not bound"</span>, Toast.LENGTH_SHORT).show()
        }
    }

    <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-comment">// Stop the BoundService (prevent memory leaks)</span>
        stopService(boundIntent)
        <span class="hljs-keyword">super</span>.onDestroy()
    }
}
</code></pre>
<p><strong>Manifest File (AndroidManifest.xml):</strong></p>
<pre><code class="lang-kotlin">&lt;manifest&gt;
&lt;application&gt;
...
&lt;service android:name=<span class="hljs-string">".BoundService"</span>/&gt;
&lt;/application&gt;
&lt;/manifest&gt;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716491010012/77b31574-f6ab-4cc1-8f41-c47d64ed010a.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Services in Android let apps do tasks in the background, keeping the app responsive. There are different types of services: background services run until stopped, bound services let other parts of the app interact with them, and foreground services show notifications to keep users informed. Managing the lifecycle of services (like creating, starting, and destroying them) is important to use resources wisely and avoid issues such as memory leaks. Using threads for long-running tasks prevents the app from freezing. Understanding these concepts helps build better, smoother-running apps.</p>
]]></content:encoded></item><item><title><![CDATA[Broadcasts and Broadcast Receivers in Android: A Comprehensive Guide]]></title><description><![CDATA[Introduction
Broadcasts in Android are system-wide messages sent by the system or other apps to signal events like battery changes or incoming messages. Broadcast receivers are components that listen for these broadcasts and respond accordingly, enab...]]></description><link>https://blog.yashraj.dev/broadcasts-and-broadcast-receivers-in-android-a-comprehensive-guide</link><guid isPermaLink="true">https://blog.yashraj.dev/broadcasts-and-broadcast-receivers-in-android-a-comprehensive-guide</guid><category><![CDATA[android app development]]></category><category><![CDATA[android development]]></category><category><![CDATA[Android]]></category><category><![CDATA[broadcast receiver]]></category><dc:creator><![CDATA[Yashraj Singh Jadon]]></dc:creator><pubDate>Sat, 18 May 2024 22:21:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GQwy-axAHBE/upload/bb52ecf02cb0cac6cf3685e9e5957db7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Broadcasts in Android are system-wide messages sent by the system or other apps to signal events like battery changes or incoming messages. Broadcast receivers are components that listen for these broadcasts and respond accordingly, enabling apps to react to various events dynamically.</p>
<h1 id="heading-what-are-broadcasts">What are Broadcasts?</h1>
<p>Broadcasts are messaging components used to communicate between different applications and the Android system when an event of interest occurs. For example, the Android system sends a broadcast event when the system boots, when the phone is connected to a charger, or when headphones are plugged in or unplugged. Broadcasts can be sent either globally or locally, and any app that has registered to receive them can act on these broadcasts. Additionally, Android applications can send broadcasts to notify other apps or components about events, such as when new data is downloaded.</p>
<h2 id="heading-types-of-broadcasts">Types of Broadcasts:</h2>
<ul>
<li><p>System or Implicit broadcasts that are delivered by the system.</p>
</li>
<li><p>Custom or Explicit broadcasts that are delivered by your app.</p>
</li>
</ul>
<h3 id="heading-systemimplicit-broadcasts">System(Implicit) Broadcasts</h3>
<p>System broadcasts in Android are messages sent by the Android system to inform applications about various events. They are wrapped in an Intent object whose action string identifies the event that occurred. Applications can register to receive these broadcasts either statically in the manifest file or dynamically at runtime.</p>
<p>For example, android.intent.action.HEADSET_PLUG, which is sent when a wired headset is connected or disconnected.</p>
<h3 id="heading-customexplicit-broadcasts">Custom(Explicit) Broadcasts</h3>
<p>Custom broadcasts are the events that are sent by your app. Use a custom broadcast when you want your app to trigger certain behaviours or notify other apps about specific events without needing to launch an activity.</p>
<p>For example, if your app downloads new data from the internet, you can send a custom broadcast to inform other apps that the data is available.</p>
<blockquote>
<p>When a system broadcast is sent, any broadcast receiver registered to listen for that specific event will receive it. This registration can be done either statically in the manifest file or dynamically in the code.</p>
</blockquote>
<h2 id="heading-different-ways-to-send-a-broadcast"><strong>Different Ways to Send a Broadcast:</strong></h2>
<h3 id="heading-normal-broadcast">Normal Broadcast</h3>
<p>The <code>sendBroadcast()</code> method sends broadcasts to all the registered receivers at the same time, in an undefined order.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> intent = Intent()
intent.setAction(<span class="hljs-string">"com.example.blogs.CUSTOM_BROADCAST"</span>)
<span class="hljs-comment">// Set the optional additional information in extra field.</span>
intent.putExtra(<span class="hljs-string">"message"</span>, <span class="hljs-string">"This is a custom broadcast"</span>)
sendBroadcast(intent)
</code></pre>
<h3 id="heading-ordered-broadcast">Ordered Broadcast</h3>
<p>The <code>sendOrderedBroadcast()</code> is used to send broadcasts to one receiver at a time. Let's explore it with the help of an example:</p>
<p>Define your Broadcast Receiver classes:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Receiver1</span> : <span class="hljs-type">BroadcastReceiver</span></span>() {
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onReceive</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, intent: <span class="hljs-type">Intent</span>)</span></span> {
        <span class="hljs-comment">// Modify the received data</span>
        <span class="hljs-keyword">var</span> message = intent.getStringExtra(<span class="hljs-string">"message"</span>)
        message = <span class="hljs-string">"<span class="hljs-variable">$message</span> -&gt; Sent by Receiver1"</span>

        <span class="hljs-keyword">val</span> resultExtras = getResultExtras(<span class="hljs-literal">true</span>)
        resultExtras.putString(<span class="hljs-string">"data"</span>, message)

        Log.d(<span class="hljs-string">"Receiver1"</span>, <span class="hljs-string">"Received broadcast and modified message"</span>)
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Receiver2</span> : <span class="hljs-type">BroadcastReceiver</span></span>() {
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onReceive</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, intent: <span class="hljs-type">Intent</span>)</span></span> {

        <span class="hljs-comment">// Read the modified data </span>
        <span class="hljs-keyword">val</span> resultExtras = getResultExtras(<span class="hljs-literal">true</span>)
        <span class="hljs-keyword">val</span> <span class="hljs-keyword">data</span> = resultExtras.getString(<span class="hljs-string">"data"</span>)

        Log.d(<span class="hljs-string">"Receiver2"</span>, <span class="hljs-string">"Received broadcast with message: <span class="hljs-variable">$data</span>"</span>)
    }
}
</code></pre>
<p>Register the Broadcast receivers(will be explained later) in the Manifest file of the receiver app.</p>
<pre><code class="lang-kotlin">&lt;application&gt;
...

    &lt;receiver android:name=<span class="hljs-string">"com.example.blogs.Receiver1"</span> android:priority=<span class="hljs-string">"2"</span>&gt;
        &lt;intent-filter&gt;
            &lt;action android:name=<span class="hljs-string">"com.example.blogs.ORDERED_BROADCAST"</span> /&gt;
        &lt;/intent-filter&gt;
    &lt;/receiver&gt;

    &lt;receiver android:name=<span class="hljs-string">"com.example.blogs.Receiver2"</span> android:priority=<span class="hljs-string">"1"</span>&gt;
        &lt;intent-filter&gt;
            &lt;action android:name=<span class="hljs-string">"com.example.blogs.ORDERED_BROADCAST"</span> /&gt;
        &lt;/intent-filter&gt;
    &lt;/receiver&gt;

&lt;/application&gt;
</code></pre>
<ul>
<li><p>The <code>android:priority</code> attribute that's specified in the intent filter determines the order in which the broadcast is sent.</p>
</li>
<li><p><strong>Receiver1</strong>: This receiver has a higher priority (2). It receives the broadcast first, modifies the message, and logs the action.</p>
</li>
<li><p><strong>Receiver2</strong>: This receiver has a lower priority (1). It receives the broadcast after <code>Receiver1</code> and logs the modified message.</p>
</li>
<li><p>If more than one receiver with the same priority is present, the sending order is random.</p>
</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> intent = Intent(<span class="hljs-string">"com.example.blogs.ORDERED_BROADCAST"</span>)
<span class="hljs-comment">// set the package name of receiver app</span>
intent.setPackage(<span class="hljs-string">"com.example.blogs"</span>)
<span class="hljs-comment">// Set a unique action string prefixed by your app package name.</span>
intent.putExtra(<span class="hljs-string">"message"</span>, <span class="hljs-string">"Broadcast Message."</span>);
<span class="hljs-comment">// Deliver the Intent.</span>
sendOrderedBroadcast(intent, <span class="hljs-literal">null</span>)
</code></pre>
<p>In the Logcat:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716159024918/9656993c-143f-4671-bb85-4461f987091a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-local-broadcast">Local Broadcast</h3>
<p>The <code>LocalBroadcastManager.sendBroadcast()</code> method is used to send broadcasts to receivers within your app and not outside the scope of your app.</p>
<p>How to send a local broadcast?</p>
<ul>
<li><p>Get an instance of LocalBroadcastManager, by calling <code>getInstance()</code> and pass in the application context.</p>
</li>
<li><p>Call sendBroadcast() on the instance. Pass in the intent that you want to broadcast.</p>
</li>
</ul>
<pre><code class="lang-kotlin"> <span class="hljs-keyword">val</span> intent = Intent(<span class="hljs-string">"local-broadcast"</span>)
 intent.putExtra(<span class="hljs-string">"message"</span>, <span class="hljs-string">"Local Broadcast Received!"</span>)
 LocalBroadcastManager.getInstance(<span class="hljs-keyword">this</span>).sendBroadcast(intent );
</code></pre>
<p>Although LocalBroadcastManager is deprecated, it is still usable. However, it is recommended to use LiveData, RxJava, or Flows (if working in Kotlin) as alternatives.</p>
<h1 id="heading-what-are-broadcast-receivers">What are Broadcast Receivers?</h1>
<p>Broadcast receivers are app components that listen for broadcast events from your app, other apps, or the system itself. When an event occurs, the registered broadcast receivers are notified through an Intent.</p>
<p>Use broadcast receivers to respond to messages that broadcast from apps or the Android system.</p>
<p>To create a custom broadcast receiver extend the BroadcastReceiver class and override the <code>onReceive()</code> method:</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">//Subclass of the BroadcastReceiver class.</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomReceiver</span> : <span class="hljs-type">BroadcastReceiver</span></span>() {
    <span class="hljs-comment">// Override the onReceive method to receive the broadcasts</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onReceive</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, intent: <span class="hljs-type">Intent</span>)</span></span> {
       <span class="hljs-comment">//Check the Intent action and perform the required operation</span>
       <span class="hljs-keyword">if</span> (intent.action == <span class="hljs-string">"com.example.blogs.CUSTOM_BROADCAST"</span>) {
      Toast.makeText(context, <span class="hljs-string">"Broadcast Received!"</span>, Toast.LENGTH_SHORT).show()
     }
   }
}
</code></pre>
<p>We can register this broadcast either statically in the manifest file or dynamically in your Java or Kotlin code.</p>
<p>In this example, the CustomReceiver class is a subclass of BroadcastReceiver. If the incoming broadcast intent has the <strong>com.example.blogs.CUSTOM_BROADCAST</strong> action, the CustomReceiver class shows a toast message.</p>
<p>If you need to perform a long-running operation inside BroadcastReceiver, use WorkManager to schedule a job. When you schedule a task with WorkManager, the task is guaranteed to run. WorkManager chooses the appropriate way to run your task, based on such factors as the device API level and the app state.</p>
<hr />
<p><strong><em>Previously, we discussed how to send a LocalBroadcast. Now, let's explore how to register a LocalBroadcast receiver.</em></strong></p>
<p>Broadcast Receiver registered with LocalBroadcastManager can only receive broadcasts sent with LocalBroacastManager. If the broadcast is sent with an Activity or Service <code>sendBroacast()</code> method, it won't be received by the LocalBroadcast Receiver.</p>
<p>To register a receiver for local broadcasts:</p>
<ol>
<li><p>Get an instance of <strong>LocalBroadcastManager</strong> by calling the <code>getInstance()</code> method.</p>
</li>
<li><p>Call <code>registerReceiver()</code>, passing in the receiver and an IntentFilter object.</p>
</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BlogActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

   <span class="hljs-comment">// Declare an instance of the custom broadcast receiver</span>
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> localReceiver = MyLocalBroadcastReceiver()
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> binding: ActivityBlogBinding

    <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">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)

        binding = ActivityBlogBinding.inflate(layoutInflater)
        setContentView(binding.root)

        <span class="hljs-comment">// Register the local receiver with the LocalBroadcastManager to </span>
        <span class="hljs-comment">// listen for "local-broadcast" intents</span>
        LocalBroadcastManager.getInstance(<span class="hljs-keyword">this</span>).registerReceiver(
                localReceiver,
                IntentFilter(<span class="hljs-string">"local-broadcast"</span>)
            )

        binding.button.setOnClickListener {
           <span class="hljs-comment">// Create a new intent with the action "local-broadcast"</span>
            <span class="hljs-keyword">val</span> intent = Intent(<span class="hljs-string">"local-broadcast"</span>)
            intent.putExtra(<span class="hljs-string">"message"</span>, <span class="hljs-string">"Local Broadcast Received!"</span>)
            <span class="hljs-comment">// Send the broadcast using the LocalBroadcastManager</span>
            LocalBroadcastManager.getInstance(<span class="hljs-keyword">this</span>).sendBroadcast(intent)
        }
    }

    <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">// Unregister the local receiver when the activity is destroyed</span>
        <span class="hljs-comment">// to prevent memory leaks</span>
        unregisterReceiver(localReceiver)
    }
}
</code></pre>
<p>Define the receiver class:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyLocalBroadcastReceiver</span> : <span class="hljs-type">BroadcastReceiver</span></span>() {
    <span class="hljs-comment">// Override the onReceive method to receive the broadcasts</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onReceive</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, intent: <span class="hljs-type">Intent</span>)</span></span> {
        <span class="hljs-comment">//Check the Intent action and perform the required operation</span>
        <span class="hljs-keyword">if</span> (intent.action == <span class="hljs-string">"local-broadcast"</span>) {
            Toast.makeText(context, intent.getStringExtra(<span class="hljs-string">"message"</span>),
                 Toast.LENGTH_LONG).show()
        }
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716114314484/90689272-f99c-4ff3-9c24-8b8533775476.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-types-of-broadcast-receivers">Types of broadcast receivers:</h2>
<ul>
<li><p>Static receivers, which you register in the Android manifest file.</p>
</li>
<li><p>Dynamic receivers, which you register using a context.</p>
</li>
</ul>
<h3 id="heading-static-broadcast-receivers">Static Broadcast receivers</h3>
<p>Static receivers are also called manifest-declared receivers. They can respond to system-wide events even when the app is not running. To register a static receiver, include the following attributes inside the element in your AndroidManifest.xml file:</p>
<p>The following code snippet shows static registration of a broadcast receiver that listens for a system broadcast Intent with the action "ACTION_POWER_CONNECTED":</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">receiver</span>
     <span class="hljs-attr">android:name</span>=<span class="hljs-string">".NotificationReceiver"</span>
     <span class="hljs-attr">android:exported</span>=<span class="hljs-string">"false"</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.intent.action.ACTION_POWER_CONNECTED"</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">receiver</span>&gt;</span>
</code></pre>
<ul>
<li><p>The receiver's name is the name of the BroadcastReceiver subclass (.NotificationReceiver).</p>
</li>
<li><p>The receiver is not exported, meaning that no other apps can deliver broadcasts to this app.</p>
</li>
<li><p>The intent filter checks whether incoming intents include an action named ACTION_POWER_CONNECTED, which is a system Intent action indicating that the device is connected to power.</p>
</li>
</ul>
<p>In our receiver class, we'll send a notification when our device connects to a power source.</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationReceiver</span>: <span class="hljs-type">BroadcastReceiver</span></span>() {
    <span class="hljs-comment">// Override the onReceive method to receive the broadcasts</span>
    <span class="hljs-meta">@RequiresApi(Build.VERSION_CODES.O)</span>
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onReceive</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>, intent: <span class="hljs-type">Intent</span>)</span></span> {
        <span class="hljs-comment">//Check the Intent action and perform the required operation</span>
        <span class="hljs-keyword">if</span> (intent.action == Intent.ACTION_POWER_CONNECTED) {
            <span class="hljs-keyword">val</span> notificationManager =
                context.getSystemService(Context.NOTIFICATION_SERVICE) <span class="hljs-keyword">as</span> NotificationManager

            <span class="hljs-comment">// Create a notification channel</span>
            <span class="hljs-keyword">val</span> channel = NotificationChannel(
                <span class="hljs-string">"notification-channel-id"</span>,
                <span class="hljs-string">"notification-channel-name"</span>,
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)

            <span class="hljs-comment">// Build the notification</span>
            <span class="hljs-keyword">val</span> notification =
                NotificationCompat.Builder(context, <span class="hljs-string">"notification-channel-id"</span>)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentText(<span class="hljs-string">"Dynamic Broadcast Received!"</span>)
                    .setContentTitle(<span class="hljs-string">"Notification Broadcast"</span>)
                    .build()

            notificationManager.notify(<span class="hljs-number">1</span>, notification)
        }
    }
}
</code></pre>
<p>Note: Make sure to add the push notifications permission in the manifest file to send notifications.</p>
<pre><code class="lang-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">uses-permission</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.permission.POST_NOTIFICATIONS"</span> /&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716112084000/2767c9c9-6c67-4074-aa08-d60a5b49b7b4.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-dynamic-broadcast-receivers">Dynamic Broadcast Receivers</h3>
<p>Dynamic receivers enable an application to register for system or app-level events at runtime instead of in the manifest file. They can only respond to events when the app is running. They are also called context-registered receivers and are registered using either an application context or an Activity context. These receivers continue to receive broadcasts as long as the context used for registration remains valid.</p>
<ol>
<li>Create an IntentFilter and add the Intent actions that you want your app to listen for. You can add more than one action to the same IntentFilter object.</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
</code></pre>
<ol start="2">
<li>Register the receiver by calling the <code>registerReceiver()</code> method on the context. Pass in the BroadcastReceiver object and the IntentFilter object.</li>
</ol>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> airplaneModeReceiver = AirplaneModeReceiver()

<span class="hljs-comment">// Register it in the onCreate() method</span>
<span class="hljs-keyword">this</span>.registerReceiver(airplaneModeReceiver, intentFilter)
</code></pre>
<p>Define the receiver class:</p>
<pre><code class="lang-kotlin"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AirplaneModeReceiver</span> : <span class="hljs-type">BroadcastReceiver</span></span>() {
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onReceive</span><span class="hljs-params">(context: <span class="hljs-type">Context</span>?, intent: <span class="hljs-type">Intent</span>?)</span></span> {
        <span class="hljs-keyword">if</span> (intent?.action == Intent.ACTION_AIRPLANE_MODE_CHANGED) {
            <span class="hljs-keyword">val</span> isAirplaneModeEnabled = Settings.Global.getInt(
                context?.contentResolver,
                Settings.Global.AIRPLANE_MODE_ON
            ) != <span class="hljs-number">0</span>
            <span class="hljs-keyword">if</span>(isAirplaneModeEnabled) {
                Toast.makeText(context, <span class="hljs-string">"Airplane mode enabled"</span>, Toast.LENGTH_LONG).show()
            } <span class="hljs-keyword">else</span> {
                Toast.makeText(context, <span class="hljs-string">"Airplane mode disabled"</span>, Toast.LENGTH_LONG).show()
            }
        }
    }
}
</code></pre>
<p>Note: When working with dynamic broadcast receivers, make sure to unregister the receivers to prevent them from registering multiple times.</p>
<pre><code class="lang-kotlin"><span class="hljs-comment">// In onDestroy() method</span>
unregisterReceiver(airplaneModeReceiver)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716114361830/26ed24cd-45ed-4be4-ba05-83f023b0eb62.gif" alt class="image--center mx-auto" /></p>
<p>The placement of unregisterReceiver() calls depends on the intended lifecycle of your BroadcastReceiver object:</p>
<p>If the receiver is only required when your activity is visible, such as for disabling a network function when the network isn't available, then register the receiver in onResume() and unregister it in onPause(). Alternatively, you can opt for the onStart()/onStop() or onCreate()/onDestroy() method pairs if they better suit your specific use case.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Broadcasts in Android are like messages that apps can send and receive to know about important events. For example, when your phone's battery is low, or when you start playing music on an app. These messages are received by components called broadcast receivers, which help applications react to these events. By using broadcast receivers, apps can stay updated and respond to changes in the system or user actions, making them more interactive and useful.</p>
]]></content:encoded></item></channel></rss>