Android & Kotlin

Fragment Communication using RxJava

Pinterest LinkedIn Tumblr

In this post, we’ll learn Fragment communication using RxJava. There are several ways of communicating two fragments. This approach is the best way of doing that and easy to implement. In my opinion, this is the best approach for communicating two fragments in Android.

This way is pretty good and easy to implement. Personally, I feel this is the best way to communicating two fragments in Android. In this technique, We use PublishSubject to create our own RxBus. This PublishSubject emits all the subsequent items of the source Observable.

1. Set up a new project

In this android app tutorial, we’ll create a ViewPager with TabLayout. Android send the data from first fragment to second fragment. For doing that we’ll use PublishSubject in RxJava. Let’s create a new project with androidx and add dependencies in app/build.gradle.

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'

  // RxJava2 Dependencies
  implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
  implementation 'io.reactivex.rxjava2:rxandroid:2.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 ViewPager with TabLayout

Open the activity_main.xml layout add below line of code. In this layout file I’m adding TabLayout and ViewPager.

<?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>

3. Create own RxBus

Generally, no default way of communicating two fragments. In this android example, we’ll use PublishSubject to create our own RxBus. First, we have to understand what is PublishSubject?

PublishSubject emits all the subsequent items of the source Observable at the time of subscription. In simple words, if a student entered late into the classroom, he just wants to listen from that point of time when he entered the classroom. So, Publish will be the best for this use-case.

For doing that create singleton java class and add below code

package com.fragmentcommunicationexample.ui.main;

import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;

public class RxBus {

  private static RxBus mInstance;

  public static RxBus getInstance() {
    if (mInstance == null) {
      mInstance = new RxBus();
    }
    return mInstance;
  }

  private RxBus() {
  }

  private PublishSubject<String> publisher = PublishSubject.create();

  void publish(String event) {
    publisher.onNext(event);
  }

  // Listen should return an Observable
  Observable<String> listen() {
    return publisher;
  }
}

As you saw above code snippet, here I have defined two methods.

  • publish(String event) -> this method this publish event
  • Observable listen() -> It return an Observable

4. Create a new Fragment named FirstFragment

I making few changes in FirstFragment layout file

<?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/textInputTextData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter Input"
        />
  </com.google.android.material.textfield.TextInputLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

5. Now open the Java file and bind the layout with source

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;

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 inputDataText = view.findViewById(R.id.textInputTextData);
    inputDataText.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) {
        RxBus.getInstance().publish(charSequence.toString());
      }

      @Override
      public void afterTextChanged(Editable editable) {
      }
    });
  }
}

Now see the highlight line code RxBus.getInstance().publish(charSequence.toString()); here we are just published the event on RxBus instance. This line will publish the event to all subscribers.

6. Create another fragment named is SecondFragment

In this fragment, we’ll listen to a published event and display the value on TextView. I’m adding a TextView in layout file

<?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/textViewName"
      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 received input data"
      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"
      />

</androidx.constraintlayout.widget.ConstraintLayout>

7. Let’s move to SecondFragment java file

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 io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

public class SecondFragment extends Fragment {

  private TextView txtName;

  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);
    txtName = view.findViewById(R.id.textViewName);

    //  listen RxJava event here
    RxBus.getInstance().listen().subscribe(getInputObserver());
  }

  // Get input observer instance
  private Observer<String> getInputObserver() {
    return new Observer<String>() {
      @Override public void onSubscribe(Disposable d) {

      }

      @Override public void onNext(String s) {
        txtName.setText(s);
      }

      @Override public void onError(Throwable e) {

      }

      @Override public void onComplete() {

      }
    };
  }
}

8. Create Pager Adapter for ViewPager

package com.fragmentcommunicationexample.ui.main;

import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import com.fragmentcommunicationexample.R;

/**
 * A [FragmentPagerAdapter] that returns a fragment corresponding to
 * one of the sections/tabs/pages.
 */
public class SectionsPagerAdapter extends FragmentPagerAdapter {

  @StringRes
  private static final int[] TAB_TITLES = new int[] { R.string.tab_text_1, R.string.tab_text_2 };
  private final Context mContext;

  public SectionsPagerAdapter(Context context, FragmentManager fm) {
    super(fm);
    mContext = context;
  }

  @Override
  public Fragment getItem(int position) {
    // getItem is called to instantiate the fragment for the given page.
    if (position == 0) {
      return FirstFragment.newInstance();
    } else {
      return SecondFragment.newInstance();
    }
  }

  @Nullable
  @Override
  public CharSequence getPageTitle(int position) {
    return mContext.getResources().getString(TAB_TITLES[position]);
  }

  @Override
  public int getCount() {
    // Show 2 total pages.
    return 2;
  }
}

9. Open MainActivity and add below code

package com.fragmentcommunicationexample;

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import com.fragmentcommunicationexample.ui.main.SectionsPagerAdapter;
import com.google.android.material.tabs.TabLayout;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    SectionsPagerAdapter sectionsPagerAdapter =
        new SectionsPagerAdapter(this, getSupportFragmentManager());
    ViewPager viewPager = findViewById(R.id.view_pager);
    viewPager.setAdapter(sectionsPagerAdapter);
    TabLayout tabs = findViewById(R.id.tabs);
    tabs.setupWithViewPager(viewPager);
  }
}

Conclusion

In this blog, we learned how to communicate between Fragments using RxJava in our application. I Hope you enjoyed this article. Help me by sharing this post with all your friends who learning android app development.

Deep drive on fragment commucation Four ways to communicate between fragments in android

Write A Comment