Appeler une méthode d'activité à partir d'un fragment

318

Essayer d'appeler une méthode dans mon activité à partir d'un fragment. Je veux que le fragment donne les données de la méthode et obtienne les données lorsque la méthode revient. Je veux réaliser similaire à faire appel à une méthode statique, mais sans utiliser de statique car cela crée des problèmes dans l'activité.

Nouveau sur les fragments donc j'ai besoin d'une explication simple et pédagogique!

Merci!

Joakim Ericsson
la source

Réponses:

821

Du fragment à l'activité:

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

De l'activité au fragment:

FragmentManager fm = getSupportFragmentManager();

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

Si vous avez ajouté un fragment via du code et utilisé une tagchaîne lorsque vous avez ajouté votre fragment, utilisez findFragmentByTagplutôt:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");
Richard
la source
5
Soyez prudent, car des événements inattendus se produisent si le casting ne fonctionne pas ..: S
Ewoks
48
Pour éviter le problème de transtypage, utilisez: Activity act = getActivity (); if (act instanceof YourActivityClassName) ((YourActivityClassName) act) .yourPublicMethod (); }
ericharlow
@ Richard: Comment pouvons-nous effectuer une action opposée, comme si nous devions effectuer la méthode d'un fragment à l'intérieur de l'activité?
Himanshu
5
C'est une mauvaise conception et dangereux de lancer une activité. Un fragment n'est pas limité à une activité spécifique.
Aviv Ben Shabat
3
@Kay Pas nécessairement. Les fragments peuvent être utilisés comme des "fragments" de toute activité plus vaste éclatée. Pour créer des interfaces utilisateur réactives, par exemple. J'utilise rarement le même fragment et je l'attache à différents hôtes d'activité.
Richard
201

Vous devriez probablement essayer de découpler le fragment de l'activité au cas où vous voudriez l'utiliser ailleurs. Vous pouvez le faire en créant une interface que votre activité implémente.

Vous définiriez donc une interface comme celle-ci:

Supposons par exemple que vous vouliez donner à l'activité une chaîne et lui faire retourner un entier:

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

Cela peut être défini dans le fragment ou dans un fichier séparé.

Ensuite, votre activité implémenterait l'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;
  }

}

Ensuite, dans votre fragment, vous auriez une variable MyStringListener et vous définiriez l'écouteur dans la méthode fragment onAttach (activité d'activité).

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. */
            }
        }

    }

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

La première réponse fonctionne certainement, mais elle associe votre fragment actuel à l'activité de l'hôte. Il est recommandé de conserver le fragment découplé de l'activité hôte au cas où vous souhaiteriez l'utiliser dans une autre activité.

Marco RS
la source
58
Pour quiconque regarde cela, bien que la réponse acceptée fonctionne évidemment, c'est la meilleure approche et la plus sûre du point de vue de la conception.
Paul Richter
7
cette réponse est tellement meilleure en termes de conception de code. cela ne causerait pas non plus de plantages si l'activité était mal lancée
David T.
3
+1 mais je n'utiliserais pas de try-catch dans onAttach. Laissez-le échouer. Si l'écouteur est facultatif (autrement dit, l'échec n'est pas approprié), ajoutez une méthode set / addListener au fragment.
ataulm
Pour la communication du côté opposé, veuillez consulter: developer.android.com/training/basics/fragments/… . En utilisant l'interface du fragment (qui est également le moyen sûr de comm fragment-> activité comm comme expliqué ci-dessus), vous pouvez également appeler une méthode qui est dans votre fragment de votre activité si vous voulez prendre une action basée sur votre fragment-> activité comm.
Kerem
Les fragments sont destinés à être réutilisés et placés dans n'importe quelle activité. Et si j'ai 5 activités en utilisant le même fragment? La réponse de Marco est la bonne et une bonne pratique pour la communication inter-fragments et activité-fragment
blockwala
51

Pour les développeurs Kotlin

(activity as YourActivityClassName).methodName()

Pour les développeurs Java

((YourActivityClassName) getActivity()).methodName();
Wasim K. Memon
la source
cela donne une erreur dans kotlin si nous exécutons ce code .. existe-t-il une autre façon?
Jake Garbo
1
Quand je l'exécute. Je reçois une valeur nulle de ActivityClass, je pense que ce n'est pas la bonne façon de le faire dans kotlin, même sans erreur. ou peut-être un bug?
Jake Garbo
@JakeGarbo C'est la bonne façon sinon 12 personnes n'ont pas voté pour. deuxième chose quelque temps getActivity () retourne null vérifier ces questions sur SO.
Wasim K. Memon
@JakeGarbo Ya, ils vous l'ont dit. SI cela a fonctionné pour vous, alors appréciez-le ou trouvez un autre moyen ou apprenez à coder en premier.
Wasim K. Memon,
13

Mettre à jour après avoir mieux compris le fonctionnement des fragments. Chaque fragment appartient à une activité parent. Il suffit donc d'utiliser:

getActivity().whatever

De l'intérieur du fragment. C'est une meilleure réponse car vous évitez les moulages superflus. Si vous ne pouvez pas éviter les lancers avec cette solution, utilisez celle ci-dessous.

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

ce que vous avez à faire est de vous lancer dans l'activité extérieure

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

créer une nouvelle instance sera source de confusion pour le cadre Android et il ne pourra pas le reconnaître. voir également :

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

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

sivi
la source
9

Bien que j'aime complètement la réponse de Marco, je pense qu'il est juste de souligner que vous pouvez également utiliser un cadre basé sur la publication / l'abonnement pour obtenir le même résultat, par exemple si vous allez avec le bus d'événements, vous pouvez faire ce qui suit

fragment:

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

Activité:

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

}
A.Alqadomi
la source
5

Dans kotlin, vous pouvez appeler la méthode d'activité à partir d'un fragment comme ci-dessous:

var mainActivity: MainActivity = activity as MainActivity
        mainActivity.showToast() //Calling show toast method of activity
Maya Mohite
la source
2

Pour accéder à une fonction déclarée dans votre Activité via votre fragment veuillez utiliser une interface, comme indiqué dans la réponse de marco.

Pour accéder à une fonction déclarée dans votre Fragment via votre activité vous pouvez l'utiliser si vous n'avez pas de tag ou d'identifiant

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


}

Ceci est le 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);
    }
}

Cette réponse est pour les noobs comme moi. Bonne journée.

hispeed
la source
1

C'est de la classe Fragment ...

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

Ce code de la classe d'activité ...

 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
la source
1

J'ai essayé avec toutes les méthodes présentées dans ce fil et aucune n'a fonctionné pour moi, essayez celle-ci. Ça a marché pour moi.

((MainActivity) getContext().getApplicationContext()).Method();
Sergio Velásquez
la source
0

Je cherchais la meilleure façon de le faire, car toutes les méthodes que nous voulons appeler ne se trouvent pas dans Fragment avec le même parent d'activité.

Dans votre fragment

public void methodExemple(View view){

        // your code here

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

Dans votre activité

new ExempleFragment().methodExemple(context); 
Maravilho Singa
la source
0

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

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

Remarque: le nom de la classe doit être public

Harsha Vardhan Reddy N
la source
0
((your_activity) getActivity).method_name()

your_activityest le nom de votre activité et method_name()le nom de la méthode que vous souhaitez appeler.

BIJAY_JHA
la source
0

Pour Kotlin, essayez-le

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
la source