379

Trying to call a method in my activity from a fragment. I want the fragment to give the method data and to get the data when the method return. I want to achieve similar to call on a static method, but without the use of static because it create problems in the activity.

New to fragments so I need an easy and pedagogic explanation!

Thanks!

Ridcully
  • 23,362
  • 7
  • 71
  • 86
Joakim Ericsson
  • 4,616
  • 3
  • 21
  • 29

18 Answers18

936

From fragment to activty:

((YourActivityClassName)getActivity()).yourPublicMethod();

From activity to fragment:

FragmentManager fm = getSupportFragmentManager();

//if you added fragment via layout xml
YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentById(R.id.your_fragment_id);
fragment.yourPublicMethod();

If you added fragment via code and used a tag string when you added your fragment, use findFragmentByTag instead:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");
Richard
  • 14,427
  • 9
  • 57
  • 85
  • 10
    BE careful cause unexpected things happen if cast doesn't work.. :S – Ewoks Dec 14 '12 at 12:34
  • 57
    To avoid the cast problem use: Activity act = getActivity(); if (act instanceof YourActivityClassName) ((YourActivityClassName) act).yourPublicMethod(); } – ericharlow Sep 09 '13 at 20:59
  • @Richard : How can we perform opposite action, like, if we have to perform a fragment's method inside the Activity? – Himanshu Oct 04 '13 at 07:31
  • Could you explain the cast ((YourActivityClassName)getActivity()) and/or direct my to some documentation how this is working under the hood in Java? – powder366 Jun 05 '14 at 09:51
  • what is "your tag" means? and how to set tag? – Santosh Pandey Jan 02 '15 at 07:22
  • @SantoshPandey "yourTag" is just a string to identify your fragment with. Think if it as a fragment id. – Richard Jan 09 '15 at 13:51
  • 17
    It's bad design and unsafe to cast an Activity. A Fragment is not limited to a specific Activity. – Aviv Ben Shabat Mar 01 '15 at 08:36
  • 2
    Fragments are meant to be reused and set in any Activity. What if I have 5 activities using same Fragment? Marco's answer is the correct one and a good practice for inter-fragment and Activity-Fragment communication. – Karan Apr 05 '15 at 11:54
  • 3
    @Kay Not necessarily. Fragments can be used as "fragments" of any larger activities broken apart. To create responsive UIs for instance. I rarely use the same fragment and attach it to different activity hosts. – Richard Apr 05 '15 at 17:31
  • 1
    @Richard In my use case it wasn't the same. I have made a library full of fragments and I would never know which developer will be attaching them to which activity and I do need the callbacks for effective navigation. I might have exaggerated in my comment saying the correct answer, but its a good practice. – Karan Apr 05 '15 at 17:40
  • hey guys I was wondering which is faster accessing an activity like this ((MainActivity) getActivity()) or getting an instance of the activity like this MainActivity mainActivity = (MainActivity) getActivity(); – Doug Ray Feb 24 '17 at 18:43
  • 1
    Ideally you don't want to access activity methods via casting because it couples your fragment with your activity and makes it difficult to write unit tests for your fragment with the new Roboelectrics launchFragment() test APIs (you;ll get ClassCastExceptions) https://developer.android.com/training/basics/fragments/testing – Cody Nov 01 '19 at 21:10
  • This is bad practice. Refer to Marco RS's answer for better architecture. – kc_dev Dec 06 '21 at 06:52
231

You should probably try to decouple the fragment from the activity in case you want to use it somewhere else. You can do this by creating a interface that your activity implements.

So you would define an interface like the following:

Suppose for example you wanted to give the activity a String and have it return a Integer:

public interface MyStringListener{
    public Integer computeSomething(String myString);
}

This can be defined in the fragment or a separate file.

Then you would have your activity implement the interface.

public class MyActivity extends FragmentActivity implements MyStringListener{

  @Override
  public Integer computeSomething(String myString){
   /** Do something with the string and return your Integer instead of 0 **/ 
   return 0;
  }

}

Then in your fragment you would have a MyStringListener variable and you would set the listener in fragment onAttach(Activity activity) method.

public class MyFragment {

        private MyStringListener listener;

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            try {
                listener = (MyStringListener) context;
            } catch (ClassCastException castException) {
                /** The activity does not implement the listener. */
            }
        }

    }

edit(17.12.2015):onAttach(Activity activity) is deprecated, use onAttach(Context context) instead, it works as intended

The first answer definitely works but it couples your current fragment with the host activity. Its good practice to keep the fragment decoupled from the host activity in case you want to use it in another acitivity.

Kerem
  • 2,867
  • 24
  • 35
Marco RS
  • 8,145
  • 3
  • 37
  • 45
  • 71
    For anyone else looking at this, while the accepted answer obviously does work, this is the better, and safer, approach from a design perspective. – Paul Richter Sep 03 '13 at 20:12
  • 10
    this answer is so much better in terms of code design. also it wouldn't cause crashes if the activity is casted wrong – David T. Apr 04 '14 at 04:51
  • 3
    +1 but I wouldn't use a try-catch in the onAttach. Let it fail. If the listener is optional (that is, failing is not appropriate), add a set/addListener method to the fragment. – ataulm Sep 03 '14 at 23:32
  • For the opposite side communication please see:http://developer.android.com/training/basics/fragments/communicating.html. Using the fragment's interface(which is also the safe way to do fragment->activity comm as explained above) you can call a method that's in your fragment from your activity as well if you want to take an action based on your fragment->activity comm. – Kerem Nov 21 '14 at 02:01
  • Fragments are meant to be reused and set in any Activity. What if I have 5 activities using same Fragment? Marco's answer is the correct one and a good practice for inter-fragment and Activity-Fragment communication – Karan Apr 05 '15 at 11:55
  • On the MyFragment.OnAttach, you do a casting to the activity. For the case that mentioned by @Kay, let's say I have 5 activities using same fragment, I think, the casting code should be changed, right? How should the code in the OnAttach looks like in order to support multiple activities? Should I use switch-case for each activity? – Raymond Lukanta Aug 18 '15 at 16:25
  • If your fragment needs other Activity methods, instead of the interface you can use an abstract class which extends Activity. – Geekarist Feb 29 '16 at 13:11
  • I point out that ***IN SOME CASES*** again this is only ***IN SOME CASES*** it's the perfect use case for a singleton. Have your manager singleton hold the current "where to go back to" interface instance (if any). Much as you would do in a typical game in a game engine milieu. – Fattie Nov 28 '16 at 00:06
  • 1
    I think it'd also be important for `MyFragment` to override `onDetach` and set the listener to null in order to avoid memory leaks. – Mateus Gondim May 15 '17 at 17:40
  • Just a note: it will be safer to do the call to the Activity in fragment's `onActivityCreated`, or make sure it will be after that, to avoid the Activity not being initialized yet. – Francesco Gabbrielli Aug 26 '18 at 00:09
  • I'm new and this is tough for me. Can someone break down what's happening in the try{}? Appreciated :) – Nathaniel Hoyt Nov 09 '20 at 04:55
  • @ataulm I like your comment. I have a similar use case. Can you post an answer that includes your recommendation to add a set/addListener method to the fragment? – AJW Mar 04 '21 at 19:25
96

For Kotlin developers

(activity as YourActivityClassName).methodName()

For Java developers

((YourActivityClassName) getActivity()).methodName();
Wasim K. Memon
  • 5,979
  • 4
  • 40
  • 55
  • it gives error in kotlin if we run this code.. is there another way ? – Jakegarbo Nov 20 '18 at 23:03
  • 1
    When I run it. I get null value of ActivityClass, I think this is not the proper way doing this in kotlin even no error. or maybe a bug? – Jakegarbo Nov 21 '18 at 10:38
  • @JakeGarbo Its proper way otherwise 12 people have not voted for it. second thing some time **getActivity()** returns null check those question on SO. – Wasim K. Memon Nov 22 '18 at 05:34
  • there is an important thing here. You can just call parent activity in your fragments. if you try to call other activities (non-parent activities) methods in your fragment, you may get null reference error or can't cast error. – Abdullah Feb 11 '23 at 15:33
16

Update after I understand more how fragments work. Each fragment belongs to a parent activity. So just use:

getActivity().whatever

From within the fragment. It is a better answer because you avoid superflous casts. If you cannot avoid the casts with this solution use the one below.

============

what you have to do is to cast to the outer activity

((MainActivity) getActivity()).Method();

creating a new instance will be confusing the android frame and it will not be able to recognize it. see also :

https://stackoverflow.com/a/12014834/1984636

https://stackoverflow.com/a/2042829/1984636

Community
  • 1
  • 1
sivi
  • 10,654
  • 2
  • 52
  • 51
10

Although i completely like Marco's Answer i think it is fair to point out that you can also use a publish/subscribe based framework to achieve the same result for example if you go with the event bus you can do the following

fragment :

EventBus.getDefault().post(new DoSomeActionEvent()); 

Activity:

 @Subscribe
onSomeActionEventRecieved(DoSomeActionEvent doSomeActionEvent){
//Do something

}
A.Alqadomi
  • 1,529
  • 3
  • 25
  • 33
  • Using the singleton pattern (relying on any dependency injection library) plus making that class extend `DefaultLifecycleObserver` and attaching it to the activity to subscribe/unsubscribe it `onResume()` or `onPause()` that "event bus" can be any class you want. – Eduardo Jul 13 '22 at 07:57
8

Here is how I did this:

first make interface

interface NavigationInterface {
    fun closeActivity()
}

next make sure activity implements interface and overrides interface method(s)

class NotesActivity : AppCompatActivity(), NavigationInterface {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_notes)
        setSupportActionBar(findViewById(R.id.toolbar))
    }

    override fun closeActivity() {
        this.finish()
    }
}

then make sure to create interface listener in fragment

private lateinit var navigationInterface: NavigationInterface

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    //establish interface communication
    activity?.let {
        instantiateNavigationInterface(it)
    }
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_notes_info, container, false)
}

private fun instantiateNavigationInterface(context: FragmentActivity) {
    navigationInterface = context as NavigationInterface
}

then you can make calls like such:

view.findViewById<Button>(R.id.button_second).setOnClickListener {
    navigationInterface.closeActivity()
}
Droid Chris
  • 3,455
  • 28
  • 31
6

In kotlin you can call activity method from fragment like below:

var mainActivity: MainActivity = activity as MainActivity
        mainActivity.showToast() //Calling show toast method of activity
Maya Mohite
  • 675
  • 6
  • 8
6

Best way to call the activity method from their respective fragment

(activity as YourActivity).activtiyMethod()

use this line from your activity. For example

Suppose You have Activity A and method add() and your fragment ABC and you want to call the method add from Fragment ABC,

(activity as A).add()
Peter
  • 587
  • 6
  • 16
4

Thanks @BIJAY_JHA and @Manaus. I used the Kotlin version to call my signIn() method that lives in the Activity and that I'm calling from a Fragment. I'm using Navigation Architecture in Android so the Listener interface pattern isn't in the Fragment:

 (activity as MainActivity).signIn() 
Lucy
  • 436
  • 5
  • 8
3

For accessing a function declared in your Activity via your fragment please use an interface, as shown in the answer by marco.

For accessing a function declared in your Fragment via your activity you can use this if you don't have a tag or an id

private void setupViewPager(ViewPager viewPager) {
    //fragmentOne,fragmentTwo and fragmentThree are all global variables
    fragmentOne= new FragmentOne();
    fragmentTwo= new FragmentTwo();
    fragmentThree = new FragmentThree();

    viewPagerAdapteradapter = new ViewPagerAdapter(getSupportFragmentManager());
    viewPagerAdapteradapter.addFragment(fragmentOne, "Frag1");
    viewPagerAdapteradapter.addFragment(fragmentTwo, "Frag2");
    viewPagerAdapteradapter.addFragment(fragmentThree, "Frag3");

    //viewPager has to be instantiated when you create the activity:
    //ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
    //setupViewPager(viewPager);
    //Where R.id.pager is the id of the viewPager defined in your activity's xml page.

    viewPager.setAdapter(viewPagerAdapteradapter);


    //frag1 and frag2 are also global variables
    frag1 = (FragmentOne)viewPagerAdapteradapter.mFragmentList.get(0);
    frag2 = (FragmentTwo)viewPagerAdapteradapter.mFragmentList.get(1);;


    //You can use the variable fragmentOne or frag1 to access functions declared in FragmentOne


}

This is the ViewpagerAdapterClass

    class ViewPagerAdapter extends FragmentPagerAdapter {
    public final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

This answer is for noobs like me. Have a good day.

hispeed
  • 171
  • 1
  • 8
2

This is From Fragment class...

((KidsStoryDashboard)getActivity()).values(title_txt,bannerImgUrl);

This Code From Activity Class...

 public void values(String title_txts, String bannerImgUrl) {
    if (!title_txts.isEmpty()) {

//Do something to set text 
    }
    imageLoader.displayImage(bannerImgUrl, htab_header_image, doption);
}
Mathan Chinna
  • 587
  • 6
  • 22
2
((your_activity) getActivity).method_name()

Where your_activity is the name of your activity and method_name() is the name of the method you want to call.

Manaus
  • 407
  • 5
  • 9
BIJAY_JHA
  • 21
  • 3
1

I have been looking for the best way to do that since not every method we want to call is located in Fragment with same Activity Parent.

In your Fragment

public void methodExemple(View view){

        // your code here

        Toast.makeText(view.getContext(), "Clicked clicked",Toast.LENGTH_LONG).show();
    }

In your Activity

new ExempleFragment().methodExemple(context); 
Maravilho Singa
  • 224
  • 3
  • 12
1

I have tried with all the methods shown in this thread and none worked for me, try this one. It worked for me.

((MainActivity) getContext().getApplicationContext()).Method();
1

For Kotlin try it out

class DataForm : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Tasks(this).getData()
    }

    fun getResponse(response: String) {
        // code
    }
}

class Tasks(private val context: Any) {
    fun getData() {

        val getContext = (context as DataForm).activity
        val getFragment = (context as DataForm)

        val responseListener = Response.Listener<String> { response ->
            getFragment.getResponse(response)
        }

        val errorListener = Response.ErrorListener { error ->
            error.printStackTrace();
        }

        val stringRequest = StringRequest(Request.Method.GET, url, responseListener, errorListener)
        Volley.newRequestQueue(getContext).add(stringRequest)
    }
}
Infomaster
  • 793
  • 7
  • 8
  • I like this since it removes a level of knowledge that the child has of the parent. Fragments should not directly call parent methods. – Droid Chris Jan 05 '21 at 15:38
0

((YourActivityName)getActivity()).functionName();

Example : ((SessionActivity)getActivity()).changeFragment();

Note : class name should be in public

0

From fragment to activity:

((YourActivityClassName)requireActivity()).yourPublicMethod();

0

I think it would be a better approach to pass the activity instance on fragment initialization. I passed the instance like below:

class FragmentSignUp : Fragment() {

    private lateinit var authActivity: AuthenticateActivity

    ...
    
    companion object {

        fun newInstance(a: AuthenticateActivity): FragmentSignUp {
            val fragment = FragmentSignUp()
            fragment.authActivity = a
            return fragment
        }
    }
}

Now you can initialize the fragment with the activity instance passed on and also can call any public method in your activity. Like below:

val fragmentManager = supportFragmentManager
val fragment = FragmentSignUp.newInstance(this)

fragmentManager.beginTransaction().replace(R.id.authenticate_fragment, fragment, FragmentSignUp::class.java.simpleName)
            .commit()

You can now access your activity public method in your fragment; like in my case:

authactivity.goToLogInFragment()

In Java your fragment class should be:

public class FragmentSignUp extends Fragment {

    private AuthenticateActivity authActivity;

    public static FragmentSignUp newInstance(AuthenticateActivity a) {
        FragmentSignUp fragment = new FragmentSignUp();
        fragment.authActivity = a;
        return fragment;
    }
}

Note: We can also inject the activity directly into the fragment constructor. But in most cases we should avoid that since it can cause some runtime issues.

Ronnie
  • 207
  • 4
  • 11