[android] Call an activity method from a fragment

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!

This question is related to android android-fragments

The answer is


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.


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()
}

For Kotlin developers

(activity as YourActivityClassName).methodName()

For Java developers

((YourActivityClassName) getActivity()).methodName();

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);
}

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();

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.


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

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

Note : class name should be in public


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() 

((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.


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); 

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

}

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

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)
    }
}

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