1

I have 2 fragments (tabs) that share some data. When one changes the data, I'd like to have that reflected on the other tab. I researched this on stackOverflow and I think the relevant answer has to do with a .notifyDataSetChanged() call, but I can't make it work. Here's the relevant code...

public class EnterCourseData extends FragmentActivity implements ActionBar.TabListener {

private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Pars", "Handicaps" };
private int courseNumber, teeNumber;
private Tee tee;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_enter_tees);
    // Initilization
    Intent mIntent = getIntent();
    courseNumber = mIntent.getIntExtra("courseNumber",0);
    Course course = Global.getCourse(courseNumber);
    teeNumber = mIntent.getIntExtra("teeNumber",0);
    tee = course.getTee(teeNumber);

    viewPager = (ViewPager) findViewById(R.id.pager);
    actionBar = getActionBar();
    mAdapter = new TabsPagerAdapter(getSupportFragmentManager(), courseNumber, teeNumber);

    viewPager.setAdapter(mAdapter);
    actionBar.setHomeButtonEnabled(false);
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);        

    // Adding Tabs
    for (String tab_name : tabs) {
        actionBar.addTab(actionBar.newTab().setText(tab_name)
                .setTabListener(this));
    }
    /**
     * on swiping the viewpager make respective tab selected
     * */
    viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    });
}

and further down, here is the onClick method that necessitates the refresh...

public void savePars(View view){
    tee.setSlope(Integer.parseInt(((EditText) findViewById(R.id.enter_tee_slope)).getText().toString()));
    tee.setRating(Double.parseDouble(((EditText) findViewById(R.id.enter_tee_rating)).getText().toString()));
    mAdapter.notifyDataSetChanged();
}

Here is the TabsPagerAdapter...

public class TabsPagerAdapter extends FragmentPagerAdapter {
int courseNumber, teeNumber;

public TabsPagerAdapter(FragmentManager fm, int courseNumber, int teeNumber) {
    super(fm);
    this.courseNumber = courseNumber;
    this.teeNumber = teeNumber;
}

@Override
public Fragment getItem(int index) {

    switch (index) {
    case 0:
        // Par Entry activity
        Fragment parFragment = new ParFragment();
        Bundle args = new Bundle();
        args.putInt(ParFragment.ARG_COURSE_NUMBER, courseNumber);
        args.putInt(ParFragment.ARG_TEE_NUMBER, teeNumber);
        parFragment.setArguments(args);
        return parFragment;
    case 1:
        // Handicap Entry fragment activity
        Fragment hcpFragment = new HandicapFragment();
        args = new Bundle();
        args.putInt(HandicapFragment.ARG_COURSE_NUMBER, courseNumber);
        args.putInt(HandicapFragment.ARG_TEE_NUMBER, teeNumber);
        hcpFragment.setArguments(args);
        return hcpFragment;
    }

    return null;
}

@Override
public int getCount() {
    // get item count - equal to number of tabs
    return 2;
}

}

Here is one Fragment...

public class ParFragment extends Fragment {
    public static final String ARG_COURSE_NUMBER = "courseNumber", ARG_TEE_NUMBER = "teeNumber";

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

        View rootView = inflater.inflate(R.layout.fragment_par, container, false);
        Bundle args = getArguments();
        Course course = Global.getCourse(args.getInt(ARG_COURSE_NUMBER));
        ((TextView) rootView.findViewById(R.id.display_course_name)).setText(course.getName());
        Tee tee = course.getTee(args.getInt(ARG_TEE_NUMBER));
        ((TextView) rootView.findViewById(R.id.display_tee_name)).setText(tee.getTeeName());
        ((TextView) rootView.findViewById(R.id.enter_tee_slope)).setText(Integer.toString(tee.getSlope()));
        ((TextView) rootView.findViewById(R.id.enter_tee_rating)).setText(Double.toString(tee.getRating()));

        return rootView;
    }
}

And here is the other...

public class HandicapFragment extends Fragment {
    public static final String ARG_COURSE_NUMBER = "courseNumber", ARG_TEE_NUMBER = "teeNumber";


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

        View rootView = inflater.inflate(R.layout.fragment_handicap, container, false);
        Bundle args = getArguments();
        Course course = Global.getCourse(args.getInt(ARG_COURSE_NUMBER));
        ((TextView) rootView.findViewById(R.id.display_course_name)).setText(course.getName());
        Tee tee = course.getTee(args.getInt(ARG_TEE_NUMBER));
        ((TextView) rootView.findViewById(R.id.display_tee_name)).setText(tee.getTeeName());
        ((TextView) rootView.findViewById(R.id.enter_tee_slope)).setText(Integer.toString(tee.getSlope()));
        ((TextView) rootView.findViewById(R.id.enter_tee_rating)).setText(Double.toString(tee.getRating()));

        return rootView;
    }

}

When the button is clicked, I want to save the values and I want these values to show up on the other fragment.

Help a noob out.

Thanks

ddk
  • 91
  • 3
  • 11
  • Where is your button in fact? In the first fragment or in the second fragment or in the activity? – Son Huy TRAN Dec 12 '13 at 20:52
  • Both fragments. In fact both fragments show the data in identical `EditText` views and both fragments have identical button handlers. (there is some fragment-specific data also displayed and entered, but I have left that out of this already too long question.) – ddk Dec 12 '13 at 21:13

2 Answers2

2

You need to communicate between fragments, but a fragment cannot directly communicate with other fragment, all the communication should be done through the activity which holds these fragments.

The steps to follow are :

  • Define an Interface in the fragment where you have implemented the onClickListener (let it be Fragment A)

  • Implement the Interface in the activity which holds these fragments

  • In the method overridden, retrieve the fragment instance from the viewpager adapter and deliver a message to Fragment B by calling it's public methods.


refer this answer to retrieve fragment instance from adapter

For more details about Communicating with Other Fragments, refer here

Community
  • 1
  • 1
Raneez Ahmed
  • 3,808
  • 3
  • 35
  • 58
  • This gets me so close... but. I pick up the button click in the fragment `ParFragment` and I notify the holding activity. I get to the method in the holding activity that gets notified by the fragment. Now I want to access methods in the 2 tab fragments from the holding activity. `ParFragment parFrag = (ParFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_par);` returns a null value. I define `@+id/fragment_par` in the header of the `fragment_par` xml. How do I get the correct fragment value in order to access the mtehod in the fragment? – ddk Dec 14 '13 at 17:43
  • I got the final answer from another post. Per @Rafa, `FragmentStatePagerAdapter` does not use tags when adding fragments to the Activity. I used `ParFragment parFrag = (ParFragment) mAdapter.instantiateItem(viewPager, 0)` and it all worked. - Thanks. – ddk Dec 15 '13 at 20:32
0

So there is a trick: just let the fragments have the object reference of one another and call the other's function to load data when you handle the onClickListener of the button. E.g:

protected void onClickListener(View view) {
    if (view == myButton) {
        // Do other stuffs here
        fragment1.reloadData();
    }
}

P/S : I re-post this as answer to have the code formatter.

Son Huy TRAN
  • 486
  • 2
  • 5
  • 16
  • What do you mean by the "object reference"? How do I get the object reference of the fragment? Do you mean to call the onCreateView, or put the guts of the onCreateView into a method and call that from the fragment OnCreateView and from the onClickListener of the button? – ddk Dec 13 '13 at 01:34
  • Nope, I meant that: public class Fragment1 extends Fragment { private Fragment2 fragment2; public Fragment2 getFragment2() { return fragment2; } public void setFragment2(Fragment2 fragment2) { this.fragment2 = fragment2; } } So the fragment1 have the reference of fragment2, so that you can call the fragment2's public functions from inside fragment1... And identically for fragment2 which keeps a reference from fragment1... – Son Huy TRAN Dec 13 '13 at 07:46
  • But where does _fragment2_ ever get a value? If I use your example and try to reference `fragment2.refreshFragment1();`, I get a run-time error because _fragment2_ is never initialized with a pointer to the actual _fragment2_ object and is therefore Null. – ddk Dec 15 '13 at 17:50
  • But you can check if (fragment1 != null) refreshFragment1();, can't you ? – Son Huy TRAN Dec 16 '13 at 01:18