Chiama un metodo di attività da un frammento


318

Sto provando a chiamare un metodo nella mia attività da un frammento. Voglio che il frammento fornisca i dati del metodo e ottenga i dati quando il metodo ritorna. Voglio ottenere simili per invocare un metodo statico, ma senza l'uso di statico perché crea problemi nell'attività.

Nuovo ai frammenti, quindi ho bisogno di una spiegazione semplice e pedagogica!

Grazie!

Risposte:


820

Dal frammento all'attività:

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

Dall'attività al frammento:

FragmentManager fm = getSupportFragmentManager();

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

Se hai aggiunto frammento tramite codice e taghai usato una stringa quando hai aggiunto il frammento, usa findFragmentByTaginvece:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");

5
ATTENZIONE perché accadono cose inaspettate se il cast non funziona ..: S
Ewoks

48
Per evitare il problema del cast, utilizzare: Activity act = getActivity (); if (act instanceof YourActivityClassName) ((YourActivityClassName) act) .yourPublicMethod (); }
ericharlow,

@Richard: come possiamo eseguire azioni opposte, come se dovessimo eseguire il metodo di un frammento all'interno dell'attività?
Himanshu

5
È cattiva progettazione e non è sicuro lanciare un'attività. Un frammento non si limita a un'attività specifica.
Aviv Ben Shabat,

3
@Kay Non necessariamente. I frammenti possono essere usati come "frammenti" di tutte le attività più grandi suddivise. Per creare UI reattive per esempio. Raramente uso lo stesso frammento e lo collego a host di attività diversi.
Richard,

201

Probabilmente dovresti provare a separare il frammento dall'attività nel caso in cui desideri usarlo da qualche altra parte. Puoi farlo creando un'interfaccia implementata dalla tua attività.

Quindi definiresti un'interfaccia come la seguente:

Supponiamo ad esempio di voler assegnare una stringa all'attività e di restituire un numero intero:

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

Questo può essere definito nel frammento o in un file separato.

Quindi la tua attività dovrebbe implementare l'interfaccia.

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

}

Quindi nel tuo frammento avresti una variabile MyStringListener e imposteresti il ​​listener nel frammento del metodo onAttach (Activity activity).

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 (2015/12/17):onAttach(Activity activity) is deprecated, use onAttach(Context context) instead, it works as intended

La prima risposta funziona sicuramente ma abbina il tuo frammento attuale all'attività dell'host. È buona norma mantenere il frammento disaccoppiato dall'attività dell'host nel caso in cui si desideri utilizzarlo in un'altra attività.


58
Per chiunque lo guardi, mentre la risposta accettata ovviamente funziona, questo è l'approccio migliore e più sicuro dal punto di vista del design.
Paul Richter,

7
questa risposta è molto migliore in termini di progettazione del codice. inoltre non causerebbe arresti anomali se l'attività viene lanciata in modo errato
David T.

3
+1 ma non userei un try-catch in onAttach. Lascialo fallire. Se il listener è facoltativo (ovvero, l'errore non è appropriato), aggiungere un metodo set / addListener al frammento.
ataulm,

Per la comunicazione sul lato opposto, consultare: developer.android.com/training/basics/fragments/… . Usando l'interfaccia del frammento (che è anche il modo sicuro per eseguire la frammentazione-> attività come spiegato sopra) puoi chiamare un metodo che è nel tuo frammento dalla tua attività e se vuoi fare un'azione in base alla tua frammentazione-> attività comm.
Kerem,

I frammenti sono pensati per essere riutilizzati e impostati in qualsiasi attività. Cosa succede se ho 5 attività usando lo stesso frammento? La risposta di Marco è quella corretta e una buona pratica per la comunicazione tra frammenti e attività-frammento
blockwala

51

Per gli sviluppatori di Kotlin

(activity as YourActivityClassName).methodName()

Per gli sviluppatori Java

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

dà errore in kotlin se eseguiamo questo codice .. c'è un altro modo?
Jake Garbo,

1
Quando lo eseguo. Ottengo un valore nullo di ActivityClass, penso che questo non sia il modo corretto di farlo in kotlin, anche senza errori. o forse un bug?
Jake Garbo,

@JakeGarbo Nel modo giusto, altrimenti 12 persone non hanno votato a favore. seconda cosa qualche volta getActivity () restituisce null controlla quelle domande su SO.
Wasim K. Memon,

@JakeGarbo Ya te l'hanno detto. Se ha funzionato per te, apprezzalo o trova un altro modo o impara come programmare prima.
Wasim K. Memon,

13

Aggiorna dopo aver capito di più come funzionano i frammenti. Ogni frammento appartiene a un'attività principale. Quindi usa solo:

getActivity().whatever

Dall'interno del frammento. È una risposta migliore perché eviti i cast superflous. Se non puoi evitare i cast con questa soluzione, usa quello qui sotto.

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

quello che devi fare è lanciare l'attività esterna

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

la creazione di una nuova istanza confonderà il frame Android e non sarà in grado di riconoscerlo. Guarda anche :

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

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


9

Anche se mi piace completamente la risposta di Marco, penso che sia giusto sottolineare che puoi anche utilizzare un framework basato su pubblicazione / abbonamento per ottenere lo stesso risultato, ad esempio se vai con il bus dell'evento puoi fare quanto segue

frammento:

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

Attività:

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

}

5

In kotlin puoi chiamare il metodo di attività dal frammento come di seguito:

var mainActivity: MainActivity = activity as MainActivity
        mainActivity.showToast() //Calling show toast method of activity

2

Per accedere a una funzione dichiarata nella tua attività tramite il tuo frammento, utilizza un'interfaccia, come mostrato nella risposta di marco.

Per accedere a una funzione dichiarata nel tuo frammento tramite la tua attività puoi usarla se non hai un tag o un 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


}

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

Questa risposta è per nessuno come me. Buona giornata.


1

Questa è la classe From Fragment ...

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

Questo codice dalla classe di attività ...

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

//Do something to set text 
    }
    imageLoader.displayImage(bannerImgUrl, htab_header_image, doption);
}

1

Ho provato con tutti i metodi mostrati in questo thread e nessuno ha funzionato per me, prova questo. Ha funzionato per me.

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

0

Ho cercato il modo migliore per farlo poiché non tutti i metodi che vogliamo chiamare si trovano in Frammento con lo stesso Parent attività.

Nel tuo frammento

public void methodExemple(View view){

        // your code here

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

Nella tua attività

new ExempleFragment().methodExemple(context); 

0

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

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

Nota: il nome della classe dovrebbe essere pubblico


0
((your_activity) getActivity).method_name()

Dov'è your_activityil nome della tua attività ed method_name()è il nome del metodo che desideri chiamare.


0

Per Kotlin provalo

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)
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.