Access a method of a Fragment from the ViewPager Activity

16,779

Solution 1

Best way to do this, just call

CallingFragmentName fragment = (CallingFragmentName) viewPager
                    .getAdapter()
                    .instantiateItem(viewPager, viewPager.getCurrentItem());

It will re-instantiate your calling Fragment, so that it will not throw null pointer exception.

Solution 2

I know this is a little late, but I ran into the same problem and maybe it will help others if you already solved it.

The first problem I found with ViewPager is that it is almost impossible to get a reference to a fragment. The fragments are created dynamically in getItem() and therefore you can't set an ID and they are automatically re-taged by the swicher, so you can't find it by tag either. There are some ways out there to do it, but they are all workarounds. (Update data in ListFragment as part of ViewPager)

The way I solved it was using essentially a double Callback. Fragment A has an interface implemented by the Main Activity, the Main Activity has a interface implemented by Fragment B. On e.g. a button clink in Fragment A the callback function in Main Activity is called, which than in turn calls the callback in Fragment B. Look at the code below. I hope I posted everything and it will help. btw, I have only tried this with a ViewPager, but I assume it would work with any sort of Fragment communication.

Main Avtivity java:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class MainActivity extends FragmentActivity implements FragmentA.Caller {

    SectionsPagerAdapter mSectionsPagerAdapter;
    ViewPager mViewPager;
    PassCallToB passOnToB = null;
    FragmentManager myManager = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);
    }

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
            MyManager = fm;
        }

        @Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
            if(position == 0) {
                fragment = new FragmentA();
            } else if (position == 1) {
                fragment = new FragmentB();
                passOnToB = (PassCallToB)fragment;
            }
            return fragment;
        }

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

        @Override
        public CharSequence getPageTitle(int position) {
            switch (position) {
            case 0:
                return "Frag A";
            case 1:
                return "Frag B";
            }
            return null;
        }

        public void setCallback() {
            List<Fragment> frags = myManager.getFragments();
            for(Fragment fragment : frags) {
                if(fragment instanceof FragmentB){
                    passOnToB = (PassCallToB)fragment;
                }
            }
        }
    }

    public interface PassCallToB {
        public void passItOn();
    }

    @Override
    public void CallB() {
        if(passOnToB instanceof Fragment)
            passOnToB.passItOn();
        else {
            mSectionsPagerAdapter.setCallback();
            passOnToB.passItOn();
        }
    }
}

Main Activity xml:

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <android.support.v4.view.PagerTitleStrip
        android:id="@+id/pager_title_strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:background="#33b5e5"
        android:paddingBottom="4dp"
        android:paddingTop="4dp"
        android:textColor="#fff" />

</android.support.v4.view.ViewPager>

Fragment A java:

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class FragmentA extends Fragment {

    Button btnCallB = null;

    Caller listener = null;

    public FragmentA() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) {
        View rootView = inflater.inflate(R.layout.fragment_a, container, false);

        btnCallB = (Button)rootView.findViewById(R.id.btnCallB);
        btnCallB.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View view) {
                listener.CallB();
            }

        });

        return rootView;
    }

    public interface Caller {
        public void CallB();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof FragmentActivity) {
          listener = (Caller) activity;
        } else {
          throw new ClassCastException(activity.toString() + " must implemenet listener");
        }
    }

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

Fragment A xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="This is Fragment A" />

    <Button
        android:id="@+id/btnCallB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView1"
        android:text="Call Fragment B" />

</RelativeLayout>

Fragment B Java:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class FragmentB extends Fragment implements MainActivity.PassCallToB {

    public FragmentB() {
    }

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

    @Override
    public void passItOn() {
        Toast.makeText(getActivity(), "Hello from B", Toast.LENGTH_SHORT).show();

    }
}

Fragment B xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="This is Fragment B" />

</RelativeLayout>

Solution 3

You can access public methods within the fragments held by your ViewPager. You need to either (1) store a reference to the Fragment when you create it and add it to the list that will back your pager adapter or (2) you need to get a reference to the fragment from the pager adapter itself. For example:

Fragment fragmentA = null; //instance variable

fragmenA = new Fragment(); //whereever you instantiate your fragment

If your method is

public void setName(String args){
    //do something
}

all you would do is call that method from the reference to the fragment held by your ViewPager

fragmentA.setName(args);

You pass whatever arguments you need just like calling a regular method. Note this ONLY works if you are calling a method within a fragment from its containing ViewPager or FragmentActivity. If you want to do the reverse, fragment to activity, you need to use an inerface.

Solution 4

Fragment

private static FragmentName instance;

public static synchronized FragmentName getInstance()
{
    return instance;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance=this;
....
}

public void methodName()
{...}

Activity

FragmentName.getInstance().methodName();
Share:
16,779
JZweige
Author by

JZweige

Updated on June 15, 2022

Comments

  • JZweige
    JZweige almost 2 years

    I have a Fragment with a method setName() that changes an EditText text, by means of the setText function.

    What is the best way to call that method from the activity that hosts that fragment by means of a ViewPager?

    In other words, how can I access a Fragment's methods (which change that fragment's layout, for example) from the Activity that hosts that fragment by means of a ViewPager?

    I am asking this because I have tried several ways, but always with errors.

  • JZweige
    JZweige almost 11 years
    Yes, I know this already. But what if I am trying to instantiate it using something like Frag1 fragment = (Frag1) mAppSectionsAdapter.getItem(0);? How I am supposed to use the method then without the null pointer exception?
  • JZweige
    JZweige almost 11 years
    It's like fragment.getView() is always null!
  • Rarw
    Rarw almost 11 years
    You want to get the reference from your adapter? I'm not at my computer but I can post code later if that's the issue.
  • rve
    rve over 9 years
    This does not work when you rotate. Because when you rotate the activity and fragments are recreated which also recreates your SectionsPagerAdapter but it never calls getItem (Android recreates the fragments without calling getItem) meaning passOnToB remains null.
  • ckn
    ckn over 8 years
    I edited my code so it will work after screen rotation. The trick is to set the callback not only in getItem(), but also include a custom method in the pager adapter that will search trough the fragments and set the callback manually, when the correct fragment is found. Now you only have to check if the callback is set and set it if not in the passOn method. I hope this is somewhat clear.
  • Si8
    Si8 over 7 years
  • Si8
    Si8 over 7 years
    Any help with mine please... stackoverflow.com/questions/39907625/…
  • Sumit Kumar
    Sumit Kumar almost 7 years
    Your answer always works for me in view pager thankyou man , only for you i starred the question now.. Thanx man :)
  • Yaroslav Dukal
    Yaroslav Dukal over 6 years
    this does not work . Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
  • Ron Daulagupu
    Ron Daulagupu over 5 years
    This should be the accepted answer. Thanks a lot. You are a life-saver.
  • Bipin Bharti
    Bipin Bharti about 4 years
    it's help full for me Thank you.
  • Satyam Gondhale
    Satyam Gondhale over 3 years
    You Save my hours. Thanks. Working perfect solution