Robert
Robert

Reputation: 1192

How to call method on Fragment from ViewPager?

I have 4 types of fragments : OpenTextFragment, SingleRadioButtonFragment, DropdownSelectFragment and MultipleCheckboxesFragment

Those fragments are displaying in the ViewPager depending on the element type that I am using. Inside those fragments are a specific function (unique for each fragment) that I need to use from my MainActivity.

ViewPager can have N numbers of the different fragments mentioned above

WHAT I NEED

I need to get the current fragment that is in my ViewPager and use that specific function that is in it.

WHAT I AM DOING

The way that I am displaying those fragments in the ViewPager is using a FragmentPagerAdapter:

public class QuestionsAdapter extends FragmentPagerAdapter {
        private ArrayList<SurveyElement> mSurveyElements;
        private int mAdapterSize = 0;

        public QuestionsAdapter(FragmentManager fm) {
            super(fm);
        }

        public void updateFragmentAdapter(ArrayList<SurveyElement> fragmentList) {
            mSurveyElements = fragmentList;
            mAdapterSize = fragmentList.size();
            this.notifyDataSetChanged();

        }

        @Override
        public Fragment getItem(int position) {
            SurveyElement surveyElement = mSurveyElements.get(position);
            switch (surveyElement.getElementType()) {
                case SurveyElement.OPEN_TEXT:
                    return OpenTextFragment.newInstance(surveyElement, position + 1);
                case SurveyElement.SINGLE_RADIOBUTTON:
                    return  SingleRadioButtonFragment.newInstance(surveyElement, position + 1);
                case SurveyElement.DROPDOWN_SELECT:
                    return DropdownSelectFragment.newInstance(surveyElement, position + 1);
                case SurveyElement.MULTIPLE_CHECKBOXES:
                    return MultipleCheckboxesFragment.newInstance(surveyElement, position + 1);
                default:
                    return OpenTextFragment.newInstance(surveyElement, position + 1);

            }
        }

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

I was trying to get the current fragment using this function in MainAcitivity

private boolean canIGoToNextQuestion(int position){ // mMyViewPager.getCurrentItem()

        if (mQuestionsAdapter.getItem(position) instanceof OpenTextFragment){
            OpenTextFragment openTextFragment =  (OpenTextFragment) mQuestionsAdapter.getItem(position);
            return openTextFragment.attemptAnswerQuestion();
        }

        // here goes the validations for the others fragments types
        return false;
    }

I'M STUCK WITH

When the function attemptAnswerQuestion() is called, all the elements inside this function are null.

It seems like I'm making a new instance of OpenTextFragment.

GOOD TO KNOW

I have seen several posts about this topic, but all of them you know the position of your fragments but, in my case can be like:

OpenTextFragment can be in the position 0,

DropdownSelectFragment in position 1,

MultipleCheckboxesFragment position 2,

again OpenTextFragment in position 3 and so on...

Upvotes: 2

Views: 1278

Answers (1)

Daniel Nugent
Daniel Nugent

Reputation: 43322

Use an instantiateItem() override in the FragmentPagerAdapter in order to keep a reference for the fragments in the ViewPager that have already been instantiated.

Since you have a variable amount of fragments in the ViewPager, use a Map to map the index to each fragment:

public class QuestionsAdapter extends FragmentPagerAdapter {
    private ArrayList<SurveyElement> mSurveyElements;
    private int mAdapterSize = 0;

    //Fragment container:
    Map<Integer, Fragment> mFragmentMap = new HashMap<>();

    public QuestionsAdapter(FragmentManager fm) {
        super(fm);
    }

    public void updateFragmentAdapter(ArrayList<SurveyElement> fragmentList) {
        mSurveyElements = fragmentList;
        mAdapterSize = fragmentList.size();
        this.notifyDataSetChanged();

    }

    //This populates your Fragment reference map:
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
        mFragmentMap.put(position, createdFragment);
        return createdFragment;
    }

    @Override
    public Fragment getItem(int position) {
        SurveyElement surveyElement = mSurveyElements.get(position);
        switch (surveyElement.getElementType()) {
            case SurveyElement.OPEN_TEXT:
                return OpenTextFragment.newInstance(surveyElement, position + 1);
            case SurveyElement.SINGLE_RADIOBUTTON:
                return  SingleRadioButtonFragment.newInstance(surveyElement, position + 1);
            case SurveyElement.DROPDOWN_SELECT:
                return DropdownSelectFragment.newInstance(surveyElement, position + 1);
            case SurveyElement.MULTIPLE_CHECKBOXES:
                return MultipleCheckboxesFragment.newInstance(surveyElement, position + 1);
            default:
                return OpenTextFragment.newInstance(surveyElement, position + 1);

        }
    }

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

Then, you can use the code below in the activity to call into the appropriate method for each type of fragment. The key is to reference the actual fragment that is instantiated and shown in the ViewPager:

private boolean canIGoToNextQuestion(int position){ // mMyViewPager.getCurrentItem()

    Fragment fragment = mQuestionsAdapter.mFragmentMap.get(position);
    if (fragment != null && fragment instanceof OpenTextFragment){
        return ((OpenTextFragment)fragment).attemptAnswerQuestion();
    }

    return false;
}

Upvotes: 1

Related Questions