Wednesday, January 22, 2020

How to Pass Data to a Fragment Using Bundle and Factory Method in Android

No comments email this post Edit Post

Passing data between Activities and Fragments is one of the most common tasks in Android development.

However, many beginners incorrectly pass values using custom Fragment constructors, which can cause runtime issues and lifecycle problems.

Modern Android development recommends using:

  • Bundle arguments
  • Factory methods
  • setArguments()

In this tutorial, we will learn:

  • Why overloaded Fragment constructors are dangerous
  • How to pass values using Bundle
  • How to create a factory method
  • Modern Android Fragment best practices

Why Custom Fragment Constructors Are Not Recommended

Android recreates Fragments automatically during:

  • Screen rotation
  • Configuration changes
  • Process recreation
  • Low memory recovery

During recreation, Android uses the default no-argument constructor.

If developers create custom constructors like:


public ExampleFragment(String text) {

}

Android may throw:


InstantiationException

or lifecycle restoration problems.


Correct Way to Pass Data to Fragments

Modern Android recommends:

  1. Create a Bundle
  2. Add values into Bundle
  3. Call setArguments()
  4. Retrieve values using getArguments()

What Is a Factory Method?

A Factory Method is a static method used to safely create Fragment instances with arguments.

Benefits:

  • Cleaner code
  • Better lifecycle handling
  • Avoids constructor issues
  • Improves reusability

What We Will Build

In this Android example:

  • MainActivity creates a Fragment
  • Bundle values are passed safely
  • Fragment retrieves arguments
  • UI displays passed values

Step 1 — Create activity_main.xml

Create:


res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout
    xmlns:android=
    "http://schemas.android.com/apk/res/android"

    android:id="@+id/container"

    android:layout_width="match_parent"

    android:layout_height="match_parent"/>

Step 2 — Create MainActivity.java

Create:


MainActivity.java

package com.example.fragmentarguments;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity
        extends AppCompatActivity {

    @Override
    protected void onCreate(
            Bundle savedInstanceState
    ) {

        super.onCreate(savedInstanceState);

        setContentView(
                R.layout.activity_main
        );

        ExampleFragment fragment =
                ExampleFragment.newInstance(
                        "Example Text",
                        123
                );

        getSupportFragmentManager()
                .beginTransaction()
                .replace(
                        R.id.container,
                        fragment
                )
                .commit();
    }
}

Step 3 — Create ExampleFragment.java

Create:


ExampleFragment.java

package com.example.fragmentarguments;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class ExampleFragment
        extends Fragment {

    private static final String ARG_TEXT =
            "argText";

    private static final String ARG_NUMBER =
            "argNumber";

    private String text;

    private int number;

    public ExampleFragment() {

        // Required empty constructor
    }

    public static ExampleFragment newInstance(
            String text,
            int number
    ) {

        ExampleFragment fragment =
                new ExampleFragment();

        Bundle args = new Bundle();

        args.putString(
                ARG_TEXT,
                text
        );

        args.putInt(
                ARG_NUMBER,
                number
        );

        fragment.setArguments(args);

        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater,
            @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState
    ) {

        View view =
                inflater.inflate(
                        R.layout.example_fragment,
                        container,
                        false
                );

        TextView textView =
                view.findViewById(
                        R.id.text_view_fragment
                );

        if (getArguments() != null) {

            text =
                    getArguments().getString(
                            ARG_TEXT
                    );

            number =
                    getArguments().getInt(
                            ARG_NUMBER
                    );
        }

        textView.setText(
                text + " " + number
        );

        return view;
    }
}

Step 4 — Create example_fragment.xml

Create:


res/layout/example_fragment.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android=
    "http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    android:gravity="center"

    android:background=
    "@android:color/holo_green_light">

    <TextView
        android:id=
        "@+id/text_view_fragment"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="Fragment Text"

        android:textSize="22sp"/>

</LinearLayout>

How This Implementation Works

The workflow is:

  1. MainActivity creates Fragment using factory method
  2. Bundle stores arguments safely
  3. Fragment receives arguments using setArguments()
  4. getArguments() retrieves stored values
  5. UI displays received data

Why setArguments() Is Important

Using:


setArguments()

allows Android to automatically restore Fragment state during:

  • Configuration changes
  • Process recreation
  • Navigation restoration

Common Mistakes Developers Make

1. Using Custom Constructors

Custom Fragment constructors can break lifecycle restoration.


2. Forgetting Empty Constructor

Fragments should always have:


public ExampleFragment() {

}

3. Accessing getArguments() Without Null Check

Always check:


if (getArguments() != null)

before reading Bundle values.


Modern Android Recommendations

Modern Android applications often use:

  • Safe Args Navigation Component
  • Shared ViewModel
  • Jetpack Compose navigation
  • StateFlow
  • Parcelable data transfer

Bundle vs Shared ViewModel

Bundle Arguments Shared ViewModel
Good for initial data Good for shared state
Lifecycle restoration friendly Reactive UI updates
Simple implementation Better for complex apps

Modern Navigation Alternative

Modern Android apps commonly use:

  • Navigation Component
  • Safe Args Plugin
  • Compose Navigation

These provide type-safe argument passing with better lifecycle handling.


FAQ

Why should Fragments avoid constructors with parameters?

Android recreates Fragments automatically using the default constructor.

Can Bundle store objects?

Yes. Bundle supports Serializable and Parcelable objects.

What is the modern recommended approach?

Navigation Component with Safe Args is the modern recommended solution for Fragment argument passing.


Conclusion

Passing data to Fragments using Bundle arguments and factory methods is the safest and most lifecycle-aware approach in Android development.

This pattern improves:

  • Lifecycle safety
  • Fragment restoration
  • Code readability
  • Reusability

Modern Android applications should combine Bundle arguments with Navigation Component, Shared ViewModel, and lifecycle-aware architecture for scalable Fragment communication.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Friday, January 17, 2020

How to Send Data Between Two Fragments in Android

No comments email this post Edit Post

Fragments are reusable UI components commonly used in modern Android applications.

Many Android applications require communication between fragments for:

  • Form updates
  • Search filters
  • Chat interfaces
  • Dashboard synchronization
  • Master-detail layouts

Since fragments should remain modular and reusable, direct fragment-to-fragment communication is not recommended.

Instead, communication usually happens through:

  • Activity interfaces
  • Shared ViewModel
  • Fragment Result API

In this tutorial, we will learn how to send data between two fragments using interfaces and the hosting Activity.


What We Will Build

In this Android example:

  • Fragment A sends text to Fragment B
  • Fragment B sends text to Fragment A
  • Activity acts as communication bridge
  • Fragments remain reusable and modular

How Fragment Communication Works

The workflow is:

  1. User enters text in Fragment A
  2. Fragment A sends data to Activity using interface
  3. Activity forwards data to Fragment B
  4. Fragment B updates UI

The same process works in reverse direction.


Step 1 — Create activity_main.xml

Create the main Activity layout:


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/containerA"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <FrameLayout
        android:id="@+id/containerB"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

Step 2 — Create MainActivity.java


package com.example.fragmentcommunication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity
        extends AppCompatActivity
        implements FragmentA.FragmentAListener,
                   FragmentB.FragmentBListener {

    private FragmentA fragmentA;

    private FragmentB fragmentB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        fragmentA = new FragmentA();

        fragmentB = new FragmentB();

        getSupportFragmentManager()
                .beginTransaction()
                .replace(
                        R.id.containerA,
                        fragmentA
                )
                .replace(
                        R.id.containerB,
                        fragmentB
                )
                .commit();
    }

    @Override
    public void onInputASent(CharSequence input) {

        fragmentB.updateEditText(input);
    }

    @Override
    public void onInputBSent(CharSequence input) {

        fragmentA.updateEditText(input);
    }
}

Step 3 — Create FragmentA.java


package com.example.fragmentcommunication;

import android.content.Context;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

public class FragmentA extends Fragment {

    private FragmentAListener listener;

    private EditText editText;

    public interface FragmentAListener {

        void onInputASent(CharSequence input);
    }

    @Nullable
    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater,
            @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState
    ) {

        View view = inflater.inflate(
                R.layout.fragment_a,
                container,
                false
        );

        editText =
                view.findViewById(R.id.editText);

        Button button =
                view.findViewById(R.id.buttonOk);

        button.setOnClickListener(
                new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {

                        listener.onInputASent(
                                editText.getText()
                        );
                    }
                });

        return view;
    }

    public void updateEditText(
            CharSequence newText
    ) {

        editText.setText(newText);
    }

    @Override
    public void onAttach(
            @NonNull Context context
    ) {

        super.onAttach(context);

        if (context instanceof FragmentAListener) {

            listener =
                    (FragmentAListener) context;

        } else {

            throw new RuntimeException(
                    context.toString()
                            + " must implement FragmentAListener"
            );
        }
    }
}

Step 4 — Create FragmentB.java


package com.example.fragmentcommunication;

import android.content.Context;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

public class FragmentB extends Fragment {

    private FragmentBListener listener;

    private EditText editText;

    public interface FragmentBListener {

        void onInputBSent(CharSequence input);
    }

    @Nullable
    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater,
            @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState
    ) {

        View view = inflater.inflate(
                R.layout.fragment_b,
                container,
                false
        );

        editText =
                view.findViewById(R.id.editText);

        Button button =
                view.findViewById(R.id.buttonOk);

        button.setOnClickListener(
                new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {

                        listener.onInputBSent(
                                editText.getText()
                        );
                    }
                });

        return view;
    }

    public void updateEditText(
            CharSequence newText
    ) {

        editText.setText(newText);
    }

    @Override
    public void onAttach(
            @NonNull Context context
    ) {

        super.onAttach(context);

        if (context instanceof FragmentBListener) {

            listener =
                    (FragmentBListener) context;

        } else {

            throw new RuntimeException(
                    context.toString()
                            + " must implement FragmentBListener"
            );
        }
    }
}

Step 5 — Create fragment_a.xml


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp"
    android:background="#A5D6A7">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/buttonOk"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send"/>

</LinearLayout>

Step 6 — Create fragment_b.xml


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp"
    android:background="#90CAF9">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/buttonOk"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send"/>

</LinearLayout>

Why Interfaces Are Used

Interfaces help:

  • Reduce tight coupling
  • Improve modularity
  • Make fragments reusable
  • Separate responsibilities cleanly

Common Mistakes Developers Make

1. Direct Fragment References

Direct fragment communication creates tightly coupled code.


2. Forgetting Interface Implementation

Activity must implement fragment listener interfaces.


3. Updating Views Before Initialization

Always ensure fragment views are initialized before updating UI.


Modern Android Alternatives

Modern Android development usually prefers:

  • Shared ViewModel
  • LiveData
  • StateFlow
  • Fragment Result API
  • Jetpack Compose state management

Shared ViewModel vs Interface Communication

Interface Communication Shared ViewModel
Good for simple communication Better for scalable apps
Activity acts as bridge Lifecycle-aware state sharing
More manual implementation Cleaner architecture

FAQ

Can fragments communicate directly?

Technically yes, but it is not recommended because it increases coupling.

What is the modern recommended approach?

Shared ViewModel with LiveData or StateFlow is the modern recommended solution.

Why use fragments instead of multiple activities?

Fragments provide better UI flexibility and reusable modular components.


Conclusion

Fragment communication is an important part of Android application architecture.

Using interfaces allows fragments to remain modular while communicating safely through the hosting Activity.

Modern Android applications should combine fragment communication with lifecycle-aware architecture patterns such as Shared ViewModel and StateFlow.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Tuesday, January 14, 2020

Android Notification Channels Tutorial — Modern Push Notification System

No comments email this post Edit Post

Notifications are one of the most important features in Android applications.

Modern Android apps use notifications for:

  • Messages and chats
  • Order updates
  • Downloads
  • Media playback
  • Reminders and alerts
  • Background services

Since Android Oreo (API 26), Notification Channels became mandatory for displaying notifications.

In this tutorial, we will learn:

  • What Notification Channels are
  • How to create notification channels
  • How to send notifications
  • Modern notification best practices
  • Notification priorities and importance levels

What Are Notification Channels?

Notification Channels allow Android users to control notification behavior for different categories inside an app.

Examples:

  • Chat messages
  • Promotions
  • Order alerts
  • Download progress

Users can individually control:

  • Sound
  • Vibration
  • Priority
  • Popup behavior
  • Lockscreen visibility

Why Notification Channels Are Important

Android 8.0 (API level 26) requires every notification to belong to a notification channel.

Without channels:

  • Notifications will not appear
  • Users lose notification customization control
  • Apps may behave inconsistently across Android versions

What We Will Build

In this Android example:

  • Create two notification channels
  • Send notifications on different channels
  • Use NotificationCompat
  • Support modern Android versions

Step 1 — Configure AndroidManifest.xml

Inside:


AndroidManifest.xml

Add custom Application class:


<application
    android:name=".App"
    android:allowBackup="true"
    android:theme="@style/Theme.App">

    <activity
        android:name=".MainActivity">

        <intent-filter>

            <action
                android:name=
                "android.intent.action.MAIN" />

            <category
                android:name=
                "android.intent.category.LAUNCHER" />

        </intent-filter>

    </activity>

</application>

Step 2 — Create Notification Channels

Create:


App.java

Add the following code:


package com.example.notifications;

import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;

public class App extends Application {

    public static final String CHANNEL_1_ID =
            "channel1";

    public static final String CHANNEL_2_ID =
            "channel2";

    @Override
    public void onCreate() {

        super.onCreate();

        createNotificationChannels();
    }

    private void createNotificationChannels() {

        if (Build.VERSION.SDK_INT
                >= Build.VERSION_CODES.O) {

            NotificationChannel channel1 =
                    new NotificationChannel(
                            CHANNEL_1_ID,
                            "Important Notifications",
                            NotificationManager
                                    .IMPORTANCE_HIGH
                    );

            channel1.setDescription(
                    "High priority notifications"
            );

            NotificationChannel channel2 =
                    new NotificationChannel(
                            CHANNEL_2_ID,
                            "General Notifications",
                            NotificationManager
                                    .IMPORTANCE_LOW
                    );

            channel2.setDescription(
                    "Low priority notifications"
            );

            NotificationManager manager =
                    getSystemService(
                            NotificationManager.class
                    );

            manager.createNotificationChannel(
                    channel1
            );

            manager.createNotificationChannel(
                    channel2
            );
        }
    }
}

Step 3 — Create activity_main.xml


<LinearLayout
    xmlns:android=
    "http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/editTextTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Title" />

    <EditText
        android:id="@+id/editTextMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Message" />

    <Button
        android:id="@+id/buttonChannel1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send High Priority" />

    <Button
        android:id="@+id/buttonChannel2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Low Priority" />

</LinearLayout>

Step 4 — Create MainActivity.java


package com.example.notifications;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

import android.app.Notification;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity
        extends AppCompatActivity {

    private EditText editTextTitle;

    private EditText editTextMessage;

    private NotificationManagerCompat
            notificationManager;

    @Override
    protected void onCreate(
            Bundle savedInstanceState
    ) {

        super.onCreate(savedInstanceState);

        setContentView(
                R.layout.activity_main
        );

        notificationManager =
                NotificationManagerCompat
                        .from(this);

        editTextTitle =
                findViewById(
                        R.id.editTextTitle
                );

        editTextMessage =
                findViewById(
                        R.id.editTextMessage
                );

        Button buttonChannel1 =
                findViewById(
                        R.id.buttonChannel1
                );

        Button buttonChannel2 =
                findViewById(
                        R.id.buttonChannel2
                );

        buttonChannel1.setOnClickListener(v -> {

            sendNotificationChannel1();
        });

        buttonChannel2.setOnClickListener(v -> {

            sendNotificationChannel2();
        });
    }

    private void sendNotificationChannel1() {

        Notification notification =
                new NotificationCompat.Builder(
                        this,
                        App.CHANNEL_1_ID
                )

                .setSmallIcon(
                        R.drawable.ic_notification
                )

                .setContentTitle(
                        editTextTitle
                                .getText()
                                .toString()
                )

                .setContentText(
                        editTextMessage
                                .getText()
                                .toString()
                )

                .setPriority(
                        NotificationCompat
                                .PRIORITY_HIGH
                )

                .build();

        notificationManager.notify(
                1,
                notification
        );
    }

    private void sendNotificationChannel2() {

        Notification notification =
                new NotificationCompat.Builder(
                        this,
                        App.CHANNEL_2_ID
                )

                .setSmallIcon(
                        R.drawable.ic_notification
                )

                .setContentTitle(
                        editTextTitle
                                .getText()
                                .toString()
                )

                .setContentText(
                        editTextMessage
                                .getText()
                                .toString()
                )

                .setPriority(
                        NotificationCompat
                                .PRIORITY_LOW
                )

                .build();

        notificationManager.notify(
                2,
                notification
        );
    }
}

Understanding Notification Importance Levels

Importance Behavior
IMPORTANCE_HIGH Popup + sound + heads-up
IMPORTANCE_DEFAULT Sound only
IMPORTANCE_LOW Silent notification
IMPORTANCE_MIN Background only

NotificationCompat vs Notification

Modern Android apps should use:


NotificationCompat

because it provides:

  • Backward compatibility
  • Better feature support
  • Consistent behavior across devices

Modern Android Notification Features

Android notifications now support:

  • Action buttons
  • Direct reply
  • Progress bars
  • Media controls
  • MessagingStyle
  • BigPictureStyle
  • Grouped notifications
  • Foreground services

Common Notification Mistakes

1. Forgetting Notification Channels

Notifications will not appear on Android Oreo+ without channels.


2. Using High Priority Everywhere

Overusing high-priority notifications annoys users.


3. Missing Notification Permission

Android 13+ requires runtime notification permission:


POST_NOTIFICATIONS

Android 13 Notification Permission

For Android 13 and above:


<uses-permission
    android:name=
    "android.permission.POST_NOTIFICATIONS" />

Runtime permission request is also required.


Best Practices for Notifications

  • Use meaningful notification channels
  • Avoid spam notifications
  • Provide user customization
  • Use proper priorities
  • Group related notifications
  • Use deep links for navigation

FAQ

Why are notification channels required?

Android Oreo introduced channels to give users more control over notification behavior.

Can notification settings be changed later?

Once created, some channel settings become user-controlled and cannot be changed programmatically.

Should every notification have its own channel?

No. Channels should represent categories of notifications.


Conclusion

Notification Channels are a core part of modern Android notification systems.

Proper notification architecture improves:

  • User engagement
  • Notification management
  • Application usability
  • Android compatibility

Modern Android applications should combine NotificationCompat, runtime permissions, proper channel grouping, and user-friendly notification design for scalable notification experiences.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Monday, January 13, 2020

How to Create a Contextual Action Mode Menu in Android

No comments email this post Edit Post

Contextual Action Mode in Android provides a temporary action bar that appears when users perform specific actions such as long-pressing an item.

It is commonly used in:

  • File managers
  • Gallery applications
  • Email apps
  • Chat applications
  • RecyclerView item selection

Unlike a floating context menu, Contextual Action Mode displays actions directly inside the top app bar for a cleaner and more modern user experience.

In this tutorial, we will learn:

  • What ActionMode is
  • How to activate contextual action mode
  • How to handle menu clicks
  • How to customize ActionMode appearance
  • Modern Android best practices

What Is Contextual Action Mode?

Contextual Action Mode is a temporary toolbar overlay that appears when the user selects or long-presses content.

It allows users to perform contextual operations such as:

  • Delete
  • Share
  • Edit
  • Copy
  • Select multiple items

What We Will Build

In this Android example:

  • User long-presses a TextView
  • Contextual Action Bar appears
  • Custom menu options are shown
  • Click events are handled
  • Toolbar overlay customization is applied

Step 1 — Create activity_main.xml

Create:


res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android=
    "http://schemas.android.com/apk/res/android"

    xmlns:app=
    "http://schemas.android.com/apk/res-auto"

    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Long Press Me"
        android:textSize="30sp"

        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Step 2 — Create Menu Resource

Create:


res/menu/example_menu.xml

<?xml version="1.0" encoding="utf-8"?>

<menu
    xmlns:android=
    "http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/option_1"
        android:icon="@drawable/ic_delete"
        android:title="Delete"
        android:showAsAction="ifRoom"/>

    <item
        android:id="@+id/option_2"
        android:icon="@drawable/ic_share"
        android:title="Share"
        android:showAsAction="ifRoom"/>

</menu>

Step 3 — Implement MainActivity.java


package com.example.contextualactionmode;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ActionMode;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity
        extends AppCompatActivity {

    private ActionMode actionMode;

    @Override
    protected void onCreate(
            Bundle savedInstanceState
    ) {

        super.onCreate(savedInstanceState);

        setContentView(
                R.layout.activity_main
        );

        TextView textView =
                findViewById(R.id.text_view);

        textView.setOnLongClickListener(v -> {

            if (actionMode != null) {

                return false;
            }

            actionMode =
                    startSupportActionMode(
                            actionModeCallback
                    );

            return true;
        });
    }

    private final ActionMode.Callback
            actionModeCallback =
            new ActionMode.Callback() {

        @Override
        public boolean onCreateActionMode(
                ActionMode mode,
                Menu menu
        ) {

            mode.getMenuInflater().inflate(
                    R.menu.example_menu,
                    menu
            );

            mode.setTitle(
                    "Choose Action"
            );

            return true;
        }

        @Override
        public boolean onPrepareActionMode(
                ActionMode mode,
                Menu menu
        ) {

            return false;
        }

        @Override
        public boolean onActionItemClicked(
                ActionMode mode,
                MenuItem item
        ) {

            int id = item.getItemId();

            if (id == R.id.option_1) {

                Toast.makeText(
                        MainActivity.this,
                        "Delete clicked",
                        Toast.LENGTH_SHORT
                ).show();

                mode.finish();

                return true;
            }

            if (id == R.id.option_2) {

                Toast.makeText(
                        MainActivity.this,
                        "Share clicked",
                        Toast.LENGTH_SHORT
                ).show();

                mode.finish();

                return true;
            }

            return false;
        }

        @Override
        public void onDestroyActionMode(
                ActionMode mode
        ) {

            actionMode = null;
        }
    };
}

How Contextual Action Mode Works

The workflow is:

  1. User long-presses a View
  2. ActionMode starts
  3. Custom contextual toolbar appears
  4. Menu options are displayed
  5. User selects action
  6. ActionMode closes automatically

Why ActionMode Is Useful

Contextual Action Mode improves user experience because:

  • Actions appear only when needed
  • UI stays clean
  • Selection-based actions become intuitive
  • Supports multi-selection workflows

Customizing ActionMode Appearance

Inside:


res/values/themes.xml

Add:


<style
    name="Theme.MyApp"
    parent="Theme.Material3.DayNight.NoActionBar">

    <item
        name="actionModeBackground">
        @color/purple_500
    </item>

    <item
        name="windowActionBarOverlay">
        true
    </item>

</style>

What Does windowActionBarOverlay Do?

When enabled:


windowActionBarOverlay = true

the contextual toolbar appears on top of the existing Toolbar instead of pushing the layout downward.


Modern Android Improvements

Modern Android applications often use Contextual Action Mode with:

  • RecyclerView selection
  • SelectionTracker API
  • Material Design 3
  • Jetpack Compose
  • Toolbar integration

Common Mistakes Developers Make

1. Using Deprecated Support Libraries

Always use:


androidx

instead of old:


android.support

2. Forgetting to Finish ActionMode

Always call:


mode.finish()

after action completion.


3. Not Handling Multiple Selections Properly

RecyclerView contextual actions should properly track selected items.


ActionMode vs PopupMenu

ActionMode PopupMenu
Toolbar overlay UI Floating popup menu
Best for selections Best for quick actions
Supports multi-select Usually single-item actions

Modern Alternative in Jetpack Compose

Jetpack Compose applications can implement contextual toolbars using:

  • TopAppBar
  • Selection containers
  • Compose state management

FAQ

What triggers Contextual Action Mode?

Usually long-click events or item selection.

Can ActionMode work with RecyclerView?

Yes. RecyclerView multi-selection is one of the most common ActionMode use cases.

Should modern apps still use ActionMode?

Yes. Contextual Action Mode is still widely used in Android applications for selection-based actions.


Conclusion

Contextual Action Mode provides a clean and modern way to perform temporary selection-based actions in Android applications.

Using ActionMode improves:

  • User experience
  • Toolbar interaction
  • Selection workflows
  • UI organization

Modern Android applications should combine ActionMode with RecyclerView selection systems, Material Design components, and lifecycle-aware architecture for scalable implementations.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Saturday, January 4, 2020

Understanding Activities, Fragments, and Intents in Android

No comments email this post Edit Post

Activities, Fragments, and Intents are some of the most important building blocks of Android application development.

Every Android developer must understand how these components work together to build scalable and responsive mobile applications.

In this guide, we will learn:

  • What Activities are
  • Activity lifecycle methods
  • What Fragments are
  • How Intents work
  • Modern Android development best practices

What Is an Activity in Android?

An Activity represents a single user interface screen in an Android application.

Examples:

  • Login screen
  • Home screen
  • Profile screen
  • Settings page

Activities are responsible for:

  • Displaying UI
  • Handling user interaction
  • Managing lifecycle events
  • Launching other screens

Why Activities Are Important

Activities act as the entry point for user interaction in Android applications.

Every Android app usually contains multiple activities connected together through navigation flows.


Declaring Activities in AndroidManifest.xml

Every Activity must be declared inside:


AndroidManifest.xml

Example:


<activity
    android:name=".MainActivity" />

Android Activity Lifecycle

Android manages Activities using lifecycle methods.

These lifecycle callbacks help developers:

  • Manage memory
  • Handle app state
  • Pause background tasks
  • Restore UI state

Main Activity Lifecycle Methods

Method Purpose
onCreate() Initialize Activity
onStart() Activity becomes visible
onResume() Activity enters foreground
onPause() Activity partially hidden
onStop() Activity no longer visible
onRestart() Restarting stopped Activity
onDestroy() Cleanup before destruction

Typical Activity Launch Flow

When the app starts:


onCreate()
onStart()
onResume()

Back Button Lifecycle Flow

When user presses Back:


onPause()
onStop()
onDestroy()

Example Activity Lifecycle Logging


public class MainActivity
        extends AppCompatActivity {

    @Override
    protected void onCreate(
            Bundle savedInstanceState
    ) {

        super.onCreate(savedInstanceState);

        Log.d(
                "Lifecycle",
                "onCreate invoked"
        );
    }

    @Override
    protected void onStart() {

        super.onStart();

        Log.d(
                "Lifecycle",
                "onStart invoked"
        );
    }

    @Override
    protected void onResume() {

        super.onResume();

        Log.d(
                "Lifecycle",
                "onResume invoked"
        );
    }

    @Override
    protected void onPause() {

        super.onPause();

        Log.d(
                "Lifecycle",
                "onPause invoked"
        );
    }

    @Override
    protected void onStop() {

        super.onStop();

        Log.d(
                "Lifecycle",
                "onStop invoked"
        );
    }

    @Override
    protected void onDestroy() {

        super.onDestroy();

        Log.d(
                "Lifecycle",
                "onDestroy invoked"
        );
    }
}

Important Lifecycle Concepts

Foreground State

Activity is interactive during:


onResume()

Visible State

Activity is visible between:


onStart() → onStop()

Entire Lifetime

Activity exists between:


onCreate() → onDestroy()

What Is a Fragment?

A Fragment is a reusable UI component hosted inside an Activity.

Fragments help developers:

  • Create modular UI
  • Support tablets and foldables
  • Reuse components
  • Improve navigation flexibility

Why Modern Apps Use Fragments

Modern Android devices have multiple screen sizes and orientations.

Fragments allow applications to adapt dynamically across:

  • Phones
  • Tablets
  • Foldables
  • Large screens

Fragment Lifecycle

Fragments have their own lifecycle separate from Activities.

Important Fragment methods:

  • onAttach()
  • onCreate()
  • onCreateView()
  • onViewCreated()
  • onStart()
  • onResume()
  • onPause()
  • onDestroyView()
  • onDestroy()

What Is an Intent in Android?

Intent is a messaging object used for communication between Android components.

Intents are used to:

  • Open Activities
  • Start Services
  • Send Broadcasts
  • Launch external applications

Types of Intents


1. Explicit Intent

Explicit Intent directly specifies the target Activity or component.

Example:


Intent intent =
    new Intent(
        MainActivity.this,
        SecondActivity.class
    );

startActivity(intent);

2. Implicit Intent

Implicit Intent specifies an action instead of a class name.

Android automatically finds applications capable of handling the action.

Examples:

  • Opening camera
  • Sending email
  • Opening maps
  • Sharing content

Example — Open Browser Using Implicit Intent


Intent intent =
    new Intent(
        Intent.ACTION_VIEW,
        Uri.parse("https://developer.android.com")
    );

startActivity(intent);

Modern Android Architecture Recommendations

Modern Android development now prefers:

  • Single Activity Architecture
  • Navigation Component
  • Jetpack Compose
  • MVVM Architecture
  • ViewModel
  • StateFlow
  • Coroutines

Common Mistakes Beginners Make

1. Forgetting Activity Declaration

Undeclared Activities cause runtime crashes.


2. Heavy Work in onCreate()

Avoid heavy database or network operations inside:


onCreate()

3. Misusing Fragments

Fragments should remain modular and reusable.


4. Memory Leaks Through Context References

Improper lifecycle handling may cause memory leaks.


Activity vs Fragment

Activity Fragment
Independent screen Reusable UI component
Declared in Manifest Attached to Activity
Own window Shares Activity window
Lifecycle managed by Android Lifecycle tied to Activity

FAQ

Can an app have multiple Activities?

Yes. Most Android applications contain multiple Activities.

Can Fragments exist without Activities?

No. Fragments must be hosted inside Activities.

What is the modern navigation approach?

Navigation Component with Single Activity Architecture is the modern recommended approach.


Conclusion

Activities, Fragments, and Intents form the foundation of Android application architecture.

Understanding lifecycle management and component communication is essential for building scalable and responsive Android applications.

Modern Android development combines these components with lifecycle-aware architecture, Kotlin, Jetpack libraries, and reactive state management for production-grade applications.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Sunday, November 10, 2019

How to Create a Video Intro Splash Screen in Android Using VideoView

No comments email this post Edit Post

Many modern Android applications display an intro video or animated splash screen before opening the main application interface.

Video splash screens are commonly used for:

  • Brand introductions
  • Gaming applications
  • Media applications
  • Startup animations
  • Promotional app launches

In this tutorial, we will learn how to create a fullscreen video intro splash screen in Android using:

  • VideoView
  • MediaPlayer listeners
  • Raw resource videos
  • Automatic screen navigation

What We Will Build

In this Android example:

  • Application launches with fullscreen video
  • Video automatically starts playing
  • Next screen opens after video completion
  • Error handling is implemented
  • Video is loaded from raw resources

Step 1 — Create activity_main.xml

Create:


res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    xmlns:android=
    "http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@android:color/black">

    <VideoView
        android:id="@+id/videoView"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:layout_alignParentTop="true"

        android:layout_alignParentBottom="true"

        android:layout_alignParentStart="true"

        android:layout_alignParentEnd="true"/>

</RelativeLayout>

Step 2 — Add Video File

Inside:


res/

create a new folder named:


raw

Add your intro video file inside:


res/raw/

Example:


intro_video.mp4

Step 3 — Create MainActivity.java

Create:


MainActivity.java

package com.example.videosplash;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;
import android.widget.VideoView;

public class MainActivity
        extends AppCompatActivity {

    private VideoView videoView;

    @Override
    protected void onCreate(
            Bundle savedInstanceState
    ) {

        super.onCreate(savedInstanceState);

        setContentView(
                R.layout.activity_main
        );

        videoView =
                findViewById(R.id.videoView);

        String videoPath =
                "android.resource://"
                        + getPackageName()
                        + "/"
                        + R.raw.intro_video;

        Uri uri = Uri.parse(videoPath);

        videoView.setVideoURI(uri);

        videoView.start();

        videoView.setOnCompletionListener(
                new MediaPlayer
                        .OnCompletionListener() {

            @Override
            public void onCompletion(
                    MediaPlayer mp
            ) {

                Intent intent =
                        new Intent(
                                MainActivity.this,
                                HomeActivity.class
                        );

                startActivity(intent);

                finish();
            }
        });

        videoView.setOnErrorListener(
                new MediaPlayer
                        .OnErrorListener() {

            @Override
            public boolean onError(
                    MediaPlayer mp,
                    int what,
                    int extra
            ) {

                Toast.makeText(
                        MainActivity.this,
                        "Error while playing video",
                        Toast.LENGTH_LONG
                ).show();

                return true;
            }
        });
    }

    @Override
    protected void onPause() {

        super.onPause();

        if (videoView != null) {

            videoView.pause();
        }
    }

    @Override
    protected void onResume() {

        super.onResume();

        if (videoView != null) {

            videoView.start();
        }
    }

    @Override
    protected void onDestroy() {

        super.onDestroy();

        if (videoView != null) {

            videoView.stopPlayback();
        }
    }
}

Step 4 — Create HomeActivity.java

Create:


HomeActivity.java

package com.example.videosplash;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class HomeActivity
        extends AppCompatActivity {

    @Override
    protected void onCreate(
            Bundle savedInstanceState
    ) {

        super.onCreate(savedInstanceState);

        setContentView(
                R.layout.activity_home
        );
    }
}

Step 5 — Create activity_home.xml


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android=
    "http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:gravity="center"

    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="Home Screen"

        android:textSize="28sp"/>

</LinearLayout>

Step 6 — Update AndroidManifest.xml

Inside:


AndroidManifest.xml

Add:


<application>

    <activity
        android:name=".HomeActivity"/>

    <activity
        android:name=".MainActivity">

        <intent-filter>

            <action
                android:name=
                "android.intent.action.MAIN"/>

            <category
                android:name=
                "android.intent.category.LAUNCHER"/>

        </intent-filter>

    </activity>

</application>

How This Video Splash Screen Works

The workflow is:

  1. App launches MainActivity
  2. VideoView loads intro video
  3. Video starts automatically
  4. Completion listener detects video end
  5. HomeActivity opens automatically

Why Use VideoView?

VideoView provides:

  • Simple video playback
  • Built-in MediaPlayer integration
  • Easy lifecycle handling
  • Minimal setup

Common Beginner Mistakes

1. Placing Video Outside raw Folder

Videos must be inside:


res/raw/

2. Using Large Video Files

Huge videos increase:

  • APK size
  • Loading time
  • Memory usage

3. Forgetting Lifecycle Handling

Always pause and release VideoView properly during lifecycle changes.


Modern Android Recommendations

Modern Android applications often prefer:

  • Lottie animations
  • MotionLayout
  • Jetpack Compose animations
  • Animated logos
  • Lightweight startup screens

VideoView vs ExoPlayer

VideoView ExoPlayer
Simple implementation Advanced media features
Good for splash videos Best for streaming apps
Basic playback controls Professional media engine

Performance Optimization Tips

  • Use compressed MP4 videos
  • Keep intro short
  • Avoid very high resolutions
  • Release media resources properly
  • Use splash screen API for lightweight startups

FAQ

Can VideoView stream online videos?

Yes, VideoView can stream videos using network URLs.

What is the modern alternative to VideoView?

ExoPlayer is the modern recommended media playback library for advanced applications.

Should apps use long intro videos?

No. Long intro videos may negatively affect user experience and app startup performance.


Conclusion

Video splash screens can create visually engaging application startup experiences when implemented correctly.

Using VideoView with MediaPlayer listeners allows developers to build simple intro video systems with minimal code.

Modern Android applications should balance branding animations with startup performance, smooth navigation, and user experience optimization.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.

Sunday, November 3, 2019

Android Architecture Components Tutorial — MVVM, Room, LiveData & ViewModel

No comments email this post Edit Post

Modern Android development focuses heavily on scalable architecture, lifecycle awareness, and maintainable code structures.

Google introduced Android Architecture Components to solve common Android development problems such as:

  • Configuration changes
  • Memory leaks
  • Lifecycle issues
  • Bloated Activities and Fragments
  • Difficult state management

In this tutorial series, we will build a complete Note Taking Application using:

  • Room Database
  • ViewModel
  • LiveData
  • RecyclerView
  • Repository Pattern
  • MVVM Architecture
  • Java

Complete Tutorial Series

  • Part 1 — Introduction
  • Part 2 — Entity
  • Part 3 — DAO & RoomDatabase
  • Part 4 — Repository
  • Part 5 — ViewModel
  • Part 6 — RecyclerView + Adapter
  • Part 7 — Add Note Activity
  • Part 8 — Swipe to Delete
  • Part 9 — Update Functionality
  • Part 10 — ListAdapter

Part 1 — Introduction

In this tutorial series, we will build a complete Note Taking App using Android Architecture Components and modern Android development practices.

The application will support:

  • Insert Notes
  • Read Notes
  • Update Notes
  • Delete Notes
  • Persistent SQLite storage

We will follow Google’s officially recommended Android app architecture principles.


What Are Android Architecture Components?

Android Architecture Components are libraries provided by Google to help developers build:

  • Lifecycle-aware applications
  • Maintainable codebases
  • Scalable app structures
  • Testable applications

These components reduce boilerplate code and simplify state management in Android applications.


Why Traditional Android Apps Become Problematic

In older Android applications:

  • Activities become too large
  • Fragments handle too much logic
  • Database code mixes with UI code
  • Configuration changes destroy UI state
  • Memory leaks become common

This creates tightly coupled and difficult-to-maintain applications.


What Problems Do ViewModel and LiveData Solve?

ViewModel

ViewModel stores and manages UI-related data in a lifecycle-conscious way.

Benefits:

  • Survives screen rotations
  • Preserves UI data
  • Separates UI from business logic
  • Reduces Activity complexity

LiveData

LiveData is an observable data holder class that is lifecycle-aware.

It automatically updates UI components only when they are active.

Benefits:

  • Automatic UI updates
  • Lifecycle awareness
  • Prevents crashes
  • Avoids memory leaks

What Is Room Persistence Library?

Room is a database abstraction layer built on top of SQLite.

Instead of manually handling SQLiteOpenHelper and SQL boilerplate code, Room uses:

  • Annotations
  • Entities
  • DAO interfaces
  • Compile-time query validation

Why Room Is Better Than Raw SQLite

Raw SQLite Room Database
Large boilerplate code Minimal code
Manual cursor handling Automatic object mapping
Runtime SQL errors Compile-time query validation
Difficult maintenance Cleaner architecture

What Is DAO?

DAO stands for:


Data Access Object

DAO contains all database operations such as:

  • Insert
  • Update
  • Delete
  • Read queries

What Is Repository Pattern?

Repository acts as an abstraction layer between:

  • ViewModel
  • Data sources

Benefits:

  • Cleaner architecture
  • Single source of truth
  • Easy testing
  • Better scalability

Understanding MVVM Architecture

The architecture used in this tutorial is:


MVVM

which stands for:

  • Model
  • View
  • ViewModel

MVVM Architecture Flow


UI (Activity / Fragment)
        ↓
ViewModel
        ↓
Repository
        ↓
Room Database

Benefits of MVVM

  • Separation of concerns
  • Scalable architecture
  • Easy maintenance
  • Lifecycle awareness
  • Better testing support
  • Cleaner codebase

Technologies Used in This Series

  • Java
  • AndroidX
  • RecyclerView
  • Room Database
  • LiveData
  • ViewModel
  • MVVM

Modern Android Recommendations

Modern Android development now commonly uses:

  • Kotlin
  • Jetpack Compose
  • StateFlow
  • Coroutines
  • Hilt Dependency Injection
  • Navigation Component

However, understanding MVVM with Java and XML layouts is still extremely important for Android fundamentals and legacy projects.


What We Will Build in This Series

The final Note App will include:

  • SQLite local storage
  • Modern RecyclerView UI
  • CRUD operations
  • Swipe-to-delete
  • Update note functionality
  • Lifecycle-aware architecture
  • MVVM implementation

Official Android Architecture Guide

Google Official Guide:

developer.android.com/jetpack/docs/guide


Common Beginner Mistakes

1. Putting Database Logic Inside Activity

Database operations should be separated using Repository and ViewModel.


2. Ignoring Lifecycle Awareness

Configuration changes can destroy Activities and cause data loss.


3. Using AsyncTask

Modern Android development now prefers:

  • Coroutines
  • Executors
  • WorkManager

FAQ

Why use MVVM in Android?

MVVM creates scalable, maintainable, and lifecycle-aware Android applications.

Is Room better than SQLiteOpenHelper?

Yes. Room reduces boilerplate code and provides compile-time SQL validation.

Can ViewModel survive screen rotation?

Yes. ViewModel survives configuration changes like screen rotations.


Conclusion

Android Architecture Components help developers build scalable, maintainable, and lifecycle-aware applications.

Using MVVM, Room, ViewModel, and LiveData significantly improves code quality and application stability.

In the next part of this series, we will create our first Room Entity class and start building the Note Database.


About the Author

Salil Jha is a Full Stack and Mobile Developer specializing in Android, React Native, fintech systems, scalable SaaS platforms, and developer tooling products.

CodeChain Dev — Build Modern Products. Solve Real Problems.