Angelo Immediata
Angelo Immediata

Reputation: 6954

Android - Fragments and Tabs communication

I'm pretty new to Android.

This is my scenario: I have a simple app with 3 tabs. In each tab i want to use one or more fragments. This is the situation:

  1. Tab 1:
    • Fragment A
  2. Tab 2:
    • Fragment B
    • Fragment C
    • Fragment D
  3. Tab 3:
    • Fragment E
    • Fragment F

In "Tab 1" I have no issue. All works pretty good. Issues arise when I need to move in "Tab 2" and "Tab 3".

In Tab 2 I have to propagate some parameters from "Fragment B" to "Fragment C" and from "Fragment C" to "Fragment D".

Then it can happen that when user clicks on some button in "Fragment D" I have to pass to "Tab 3" and I have to propagate some parameters from "Fragment D" to "Fragment E".

In my main Activity for Tab handling I'm using these components:

My very simple FragmentStatePagerAdapter extension is:

public class MyOwnPageAdapter extends FragmentStatePagerAdapter {
    private int numeroTab;
    public MyOwnPageAdapter(FragmentManager fm, int numeroTab) {
        super(fm);
        this.numeroTab = numeroTab;
    }
    @Override
    public Fragment getItem(int position) {
        switch (position){
            case 0:
                return new FragmentA() ;
            case 1:
                return new FragmentB() ;
            case 2:
                return new FragmentC() ;
            default:
                return null;
        }
    }
    @Override
    public int getCount() {
        return numeroTab;
    }
}

My very simple TabLayout.OnTabSelectedListener extension is:

public class TabSelectedListener implements TabLayout.OnTabSelectedListener {
    private ViewPager viewPager;
    public TabSelectedListener(ViewPager viewPager){

        this.viewPager = viewPager;
    }
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        viewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
}

I'm able in switching fragments inside tabs that is in Tab 2 i can switch from Fragment B to Fragment C and so on. I'm having issues in passing parameters between fragments and above all from Fragment D in Tab 2 to Fragment E in Tab 3

In my Fragments implementation byt using the android.support.v4.app.FragmentManager I can add and remove views (e.g. fragments) by doing something like this:

mFragmentManager.beginTransaction().add(rootView.getId(),mListaEdificiFragment, "BUILDS").addToBackStack(null).commit();

The problem is the param propagation that since the FragmentStatePagerAdapter seems to cache views it happens that the fragment constructor is called but the onCreate and onCreateView are no more called so I can't handle the propagated parameters.

Is there any solution to this? Or am I simply wrong in my navigation pattern? I would like to avoid to collapse Fragment B,Fragment C and Fragment D in one "big view" where to hide some section (the same for Fragment E e Fragment F)

Any suggestion is more then welcome

Angelo

Upvotes: 1

Views: 805

Answers (4)

Angelo Immediata
Angelo Immediata

Reputation: 6954

Finally I got a solution. Since the main problem is the fragments communication, I followed the official documentation

Let's suppose I have Fragment A with list of articles and Fragment B where to see the selected article detail, in my Fragment A i wrote:

public class FragmentA extends Fragment {
    private OnArticleSelectionListener mCallback;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
        }
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.activityedifici, container, false);     
        return rootView;
    }



    public interface OnArticleSelectionListener {

        void onArticleSelection(String articleId);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mCallback = null;
    }


    public void setOnArticleSelectionListener(OnArticleSelectionListener mCallback) {
        this.mCallback = mCallback;
    }
}

As you can see I declared the following interface

public interface OnArticleSelectionListener {

        void onArticleSelection(String articleId);
    }

This is the article selection listener.

In my Main Activity I wrote the following:

public class MainActivity implements FragmentA.OnArticleSelectionListener{
//All my own stuffs

    @Override
    public void onAttachFragment(Fragment fragment) {
        if (fragment instanceof FragmentA){
            FragmentA ef = (FragmentA)fragment;
            ef.setOnArticleSelectionListener(this);
        }
    }
    @Override
    public void onArticleSelection(String articleId) {
        if( getSupportFragmentManager().findFragmentByTag(TAG_ARTICLE_DETAIL) != null ){
        //FragmentB is the article detail and it has already been created and cached
            FragmentB dcf = (FragmentB)getSupportFragmentManager().findFragmentByTag(TAG_ARTICLE_DETAIL);
            dcf.updateArticleDetail( articleId );
        }else{
        //FragmentB is the article detail and it has never been created I create and replace the container with this new fragment
            FragmentB dcf = new FragmentB();
        //Parameter propagation
            Bundle args = new Bundle();
            args.putString(FragmentB.ARG_ARTICLE_ID, articleId);
            dcf.setArguments(args);
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.container_articles, dcf, TAG_ARTICLE_DETAIL);
            transaction.addToBackStack(null);
            transaction.commit();
        }
    }
}

In this way I'm able in intercepting events in FragmentA and propagate them to the FragmentB; when I need to open a Tab all remains the same and finally (after transaction.commit() or the dcf.updateArticleDetail( articleId )) I do the following tabLayout.getTabAt(2).select(); and the third tab (tab index starts from 0) is open and the Detail is showed.

I hope this can be useful

Angelo

Upvotes: 0

Mitesh Vanaliya
Mitesh Vanaliya

Reputation: 2611

I have faced a similar issue in my project. In my case, I have viewpager and each tab has multiple fragment.

So one of the simple solutions is to use LiveData and ViewModel.

In your Tab2:

Fragment B

Fragment C

Fragment D

TabTwoViewModel (with live data)

In mutable Live data observer this live data to Fragment B, C, and D.

When you update live data object, Live data notify automatically all fragment.

Upvotes: 0

Charan M
Charan M

Reputation: 489

I write my Fragment like this for passing data to it.

public class MyFragment extends Fragment {
    private static String ARG_PARAM1 = "data";
    private String data;

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

    public static MyFragment newInstance(String data) {
        MyFragment fragment = new MyFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, data);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            data = getArguments().getString(ARG_PARAM1);
        }
    }
}

Now data can be passed to the Fragment by calling MyFragment.newInstance("Hello"). I hope this helps.

Upvotes: 0

Karthic Srinivasan
Karthic Srinivasan

Reputation: 525

One simple solution to transfer a variable value from one fragment to another is shared preferences (can also be used to transfer values from one activity to another too). Shared preference will save data against variables that will persist across all the activities and fragments in an android app.

Now in your case, lets assume you want to transfer a value name = angelo from your fragment A to fragment B. In your fragment A, write this code:

 Button updateName = findViewById(R.id.btnupdateTeamName);
 updateTeamName .setOnClickListener(new View.OnClickListener() {
 @Override
    public void onClick(View v) {
        SharedPreferences.Editor editor = sharedpreferences.edit();
        editor.putString("name", "angelo");
        editor.commit();
    }
 });

When executed, the above code will update a value name with angelo in shared preferences. This will be available throughout your app.

For more info about shared preference, check out this official document.

Upvotes: 0

Related Questions