Akhil
Akhil

Reputation: 329

How to pass data between tabs?

I have one activity and two tabs in that activity Tab1 and Tab2. These are the two fragments. In my Tab1 have an EditText field and a Button field and Tab2 have only one TextView Field.I want to get the value in EditText field in the Tab1 in to TextView field in Tab2 when I click the button in the Tab1 and also get value when swipe Tab1 to Tab2. I also check many websites but did't get any solution. If anyone know it please help me.

MainActivity.java

package reubro.com.fragment;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener {

TabLayout tabLayout;
ViewPager viewPager;

Tab1 t2;

EditText ed1;
Tab1 t1;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    t1 = new Tab1();
    ed1 = (EditText) findViewById(R.id.ed1);


    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    tabLayout = (TabLayout) findViewById(R.id.tab);
    viewPager = (ViewPager) findViewById(R.id.pager);

    tabLayout.addTab(tabLayout.newTab().setText("Tab1"));
    tabLayout.addTab(tabLayout.newTab().setText("Tab2"));
    tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

    Pager pager = new Pager(getSupportFragmentManager(),tabLayout.getTabCount());
    viewPager.setAdapter(pager);

    tabLayout.setOnTabSelectedListener(this);
}

public void onTabSelected(TabLayout.Tab tab){

    viewPager.setCurrentItem(tab.getPosition());
  //  ed1.setText(t1.ed.getText());
   // Log.d("cccccc",ed1.getText().toString());
}

public void onTabUnselected(TabLayout.Tab tab) {

}


public void onTabReselected(TabLayout.Tab tab) {

}
}

Tab1.java

 package reubro.com.fragment;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

/**
 * Created by pc84 on 20/1/17.
 */

public class Tab1 extends Fragment {

Button b1;
 EditText ed;
    String val;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, final Bundle bundle){
    View view = inflater.inflate(R.layout.tab1,viewGroup,false);

    b1 = (Button) view.findViewById(R.id.btn1);
    ed = (EditText) view.findViewById(R.id.ed1);

    b1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            val = ed.getText().toString().trim();
            if(!(val.isEmpty())){

                Log.d("inner",val);

                Tab2 tab2 = new Tab2();
                Bundle bundle = new Bundle();
                bundle.putString("val",val);
                tab2.setArguments(bundle);
                Toast.makeText(getActivity(),"This is value: "+val,Toast.LENGTH_LONG).show();


            }
        }
    });

    return view;
}

}

Tab2.java

package reubro.com.fragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Created by pc84 on 20/1/17.
 */

public class Tab2 extends Fragment {
TextView tv;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle){
    View view = inflater.inflate(R.layout.tab2,viewGroup,false);
    tv = (TextView) view.findViewById(R.id.tv1);

    Bundle bundle1 = this.getArguments();
    if (bundle1 != null){

        String val = bundle1.getString("val");
        tv.setText(val);
        Log.d("tttttt",val);

    }

    return view;

}


}

Pager.java

    package reubro.com.fragment;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;

/**
 * Created by pc84 on 20/1/17.
 */

public class Pager extends FragmentStatePagerAdapter {
    int tabCount;
    public Pager(FragmentManager fm, int tabCount) {
        super(fm);
        this.tabCount = tabCount;
    }

    @Override
    public Fragment getItem(int position) {
        switch (position){
            case 0:
                Tab1 tab1 = new Tab1();
                return tab1;
            case 1:
                Tab2 tab2 = new Tab2();
                return tab2;
            default:
                return null;
        }
    }

    @Override
    public int getCount() {
        return tabCount;
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

             <android.support.design.widget.TabLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
                 android:minHeight="?attr/actionBarSize"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"

            android:id="@+id/tab"
            />

        <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </LinearLayout>
</android.support.design.widget.CoordinatorLayout>

tab1.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/ed1"
        android:hint="Enter something"
        android:layout_margin="20dp"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:id="@+id/btn1"
        android:layout_below="@+id/ed1"
        android:text="Send to Next Fragment"
        android:textAllCaps="false"/>


</RelativeLayout>

tab2.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Tab2"
        android:gravity="center"/>

</RelativeLayout>

Upvotes: 1

Views: 5030

Answers (7)

j2emanue
j2emanue

Reputation: 62519

if your willing to wait until the tab is resumed:

it can be done like this: in your main activity navigation host have a function like this:

  fun moveToTabPosition(tabPosition: Int, bundle: Bundle?) {
        myFragment?.arguments?.let { it.putAll(bundle) } ?: run { myfragment?.arguments = bundle }
        binding.tablayout.setSelectedTab(tabPosition)
        binding.yourViewPager.currentItem = tabPosition
    }

then just call that with your new bundle updates.

important: in onResume of each tab fragment have a function called updateBundle() and parse the arguments you want again.

the key here is the the arguments have a method called putAll

UPDATE: I want to avoid putAll now ...i notice after Android N it cannot allow to add values to the arguments after the fragment is attached. During QA testing it passed but some users had this issue so had to remove this call.

i got an error on some devices of: java.lang.UnsupportedOperationException : ArrayMap is immutable

Now im in favor of a common interface to call to update the set the arguments data. it would take a bundle as param.

Upvotes: 0

kunal gharate
kunal gharate

Reputation: 53

Use ViewModel as a parent data sharing in the parent activity so you can use the same context as viewLifeCycleOwner so you can easily handle the data view and data

Upvotes: 1

Miguel Lasa
Miguel Lasa

Reputation: 518

I've encountered a similar scenario and came up with the following:

  1. Have the MainActivityViewModel hold any data you may need, and set it accordingly when the event you are interested in is triggered.
  2. You can then trigger the navigation to the destination tab programmatically(even if you are using the multiple-stack workaround used here https://github.com/googlesamples/android-architecture-components/tree/master/NavigationAdvancedSample), and have it get any information it may need from the MainActivityViewModel.
  3. As soon as the information is read, set it to null so it won't be used again by mistake. You should also have a default behavior, for when the tab comes up for other reasons, and that variable is null.

Honestly, I'm not sure if by doing this I've gone against some best practices or something, but it has proven useful, and doesn't feel too "hacky".

Upvotes: 0

kunal gharate
kunal gharate

Reputation: 53

You Can use Live Data object with View Model You can Implement it easily with new Android Architecture.

Doc : https://developer.android.com/topic/libraries/architecture/livedata

No need to EventBus Anymore and Interface for getting LiveData.

Upvotes: 0

Thientvse
Thientvse

Reputation: 1791

You try to use BroadcastReceiver.

In Tab1 : you send broadcast with data

In Tab2 : you get data from broadcast and set page index

Upvotes: 0

firegloves
firegloves

Reputation: 5709

You can place your data into a Singleton referenced both into Tab1 and Tab2.

A Singleton is a programming pattern that let you to use always the same and the only one instance of a class. This is an example:

public class ClassicSingleton {
   private static ClassicSingleton instance = null;
   protected ClassicSingleton() {
      // Exists only to defeat instantiation.
   }
   public static ClassicSingleton getInstance() {
      if(instance == null) {
         instance = new ClassicSingleton();
      }
      return instance;
   }
}

Take a look here to have a more detailed description:

Upvotes: 3

Charu
Charu

Reputation: 1075

To pass data from one tab to another, you can either send a broadcast or if you don't want to broadcast then first pass it to activity through callback then from activity to tab2.

Upvotes: 0

Related Questions