Core Android

Fragment Communication using EventBus

While developing an application, Communication is one of the important part of Android application development. In between fragments communication should not be done directly. There are several ways of doing it. I have explained all the ways in my previous article(Four way to communicate between fragments). In this post, we’ll learn Fragment communication using EventBus in our android application. So, let’s get started.

Fragment Overview

In Android, Fragment represents the behavior of any user Interface. A fragment is associated with Activity. It has its own life cycle. If activity is destroyed then all associated fragment as well destroy. Android System does not have any way to direct communication between fragment. So, due to this, we have to take care while sending data one fragment to another fragment.

EventBus Overview

You already know, In this sample project we’ll use EventBus for fragment communication. What is EventBus and how it works?

EventBus is a publish/subscribe event bus for Android and Java. It simplifies communication between components. EventBus makes your code simpler, faster and avoids complex and error-prone dependencies and life cycle issues.

How It works

EventBus is an implementation of publish/subscribe pattern. It is a messaging system between a subscriber and a publisher. A subscriber waits for an event to be dispatched from a publisher.

Fragment Communication in Android

Steps for Implementing Fragment Communication

The communication between fragment using EventBus is very easy to implement. So, let’s see how we can achieve fragment communication.

The idea is very simple. We can summarize all implementation step into below points

  • Add EventBus dependency in app/build.gradle file
  • Prepare Sample Project
    • Prepare TabLayout with ViewPager
    • Create FirstFragment and add InputEditText
    • Write SecondFragment and add TextView
  • Define Event
  • Prepare Subscribers
  • Register and Unregister your Subscriber
  • Post Events
  • Test the sample application

Fragment Communication using EventBus (Sample App)

After followings, all step your application behave like this video

Let’s Implement in your application

1. Add EventBus dependency in app/build.gradle file
dependencies {
  implementation fileTree(dir: 'libs', include: ['*.jar'])
  implementation 'androidx.appcompat:appcompat:1.0.2'
  implementation 'com.google.android.material:material:1.0.0'
  implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

  // Event Bus Library
  implementation 'org.greenrobot:eventbus:3.1.1'

  testImplementation 'junit:junit:4.12'
  androidTestImplementation 'androidx.test:runner:1.2.0'
  androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
2. Prepare Sample Project

This android sample app we’ll create a TabLayout with ViewPager. ViewPager will contain two fragments FirstFragment and SecondFragment. We will send data FirstFragment to SecondFragment. So let’s prepare all things

2.1 Add the TabLayout and ViewPager inside the MainActivity xml file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >

  <com.google.android.material.appbar.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay"
      >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:minHeight="?actionBarSize"
        android:padding="@dimen/appbar_padding"
        android:text="@string/app_name"
        android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
        />

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        />
  </com.google.android.material.appbar.AppBarLayout>

  <androidx.viewpager.widget.ViewPager
      android:id="@+id/view_pager"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_behavior="@string/appbar_scrolling_view_behavior"
      />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
2.2 Create a Fragment with layout file named is FirstFragment

I have added TextInputLayout with TextInputEditText in layout file, So we can take input from this fragment and send it to another fragment

<?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"
    >
  <ImageView
      android:id="@+id/imageView"
      android:layout_width="72dp"
      android:layout_height="72dp"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="24dp"
      android:src="@drawable/user_avatar"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      />
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginEnd="16dp"
      android:layout_marginLeft="16dp"
      android:layout_marginRight="16dp"
      android:layout_marginStart="16dp"
      android:layout_marginTop="24dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/imageView"
      style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textInputText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter Text "
        />
  </com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

3. Define Event

In this demo, we’ll send a string one fragment to another. So no need to define an event method.

4. Post Event

Let’s saw the highlighted line in FirstFragment class, There we are posting event using EventBus.

EventBus.getDefault().post(charSequence.toString());
5. Open the FirstFragment Java File add below code

In this fragment, we have one TextInputLayout, we’ll post the event onTextChange().

package com.fragmentcommunicationexample.ui.main;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.fragmentcommunicationexample.R;
import com.google.android.material.textfield.TextInputEditText;
import org.greenrobot.eventbus.EventBus;

public class FirstFragment extends Fragment {

  public FirstFragment() {
    // Required empty public constructor
  }

  /**
   * Create a new instance of this fragment
   *
   * @return A new instance of fragment FirstFragment.
   */

  public static FirstFragment newInstance() {
    return new FirstFragment();
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_first, container, false);
  }

  @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    TextInputEditText inputEditText = view.findViewById(R.id.textInputText);

    inputEditText.addTextChangedListener(new TextWatcher() {
      @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

      }

      @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        EventBus.getDefault().post(charSequence.toString());
      }

      @Override public void afterTextChanged(Editable editable) {

      }
    });
  }
}

6. Create another fragment named is SecondFragment

In this fragment layout, I have added one TextView for displaying data that were received from FirstFragment. One ImageView also added just for beautifying the layout.

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.main.SecondFragment"
    >

  <ImageView
      android:id="@+id/imageView2"
      android:layout_width="72dp"
      android:layout_height="72dp"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="24dp"
      android:src="@drawable/user_avatar"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      />
  <TextView
      android:id="@+id/txtResult"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginEnd="8dp"
      android:layout_marginLeft="8dp"
      android:layout_marginRight="8dp"
      android:layout_marginStart="8dp"
      android:layout_marginTop="32dp"
      android:gravity="center"
      android:hint="Display Result "
      android:textColor="@color/colorPrimaryDark"
      android:textSize="22sp"
      android:textStyle="bold"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/imageView2"
      tools:text="Morris"
      />
</androidx.constraintlayout.widget.ConstraintLayout>
7. Prepare Subscribers

In this fragment, Declare and annotate your subscribing method.

@Subscribe(threadMode = ThreadMode.MAIN)
   public void onResultReceived(String result) {
     txtResult.setText(result);
   }
8. Register and Unregister your Subscriber

We have to register and unregister your subscriber. Fragments should usually register according to their life cycle:

@Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }

Finally, EventBus related stuff is done. Add these line in SecondFragment source file. Finally, source file looks like this

9. Now open SecondFragment.java file and add below code
package com.fragmentcommunicationexample.ui.main;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.fragmentcommunicationexample.R;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class SecondFragment extends Fragment {

  private static final String TAG = "SecondFragment";

  private TextView txtResult;

  public SecondFragment() {
    // Required empty public constructor
  }

  /**
   * Use this factory method to create a new instance of this fragment.
   *
   * @return A new instance of fragment SecondFragment.
   */
  public static SecondFragment newInstance() {
    return new SecondFragment();
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_second, container, false);
  }

  @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    txtResult = view.findViewById(R.id.txtResult);
  }

  @Subscribe(threadMode = ThreadMode.MAIN)
  public void onResultReceived(String result) {
    txtResult.setText(result);
  }

  @Override public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
  }

  @Override public void onPause() {
    super.onPause();
    EventBus.getDefault().unregister(this);
  }
}

Here, in the onResultReceived method, you can perform your desired operation. This operation can be updating the text of the TextView present in the SecondFragment or any relevant action that you want to perform on the data received from the FirstFragment.

10. Now Connect both Fragments with Fr