Wywołaj metodę działania z fragmentu

318

Próbuję wywołać metodę w mojej działalności z fragmentu. Chcę, aby fragment podał dane metody i uzyskał dane po zwróceniu metody. Chcę osiągnąć podobne do wywołania metody statycznej, ale bez użycia metody statycznej, ponieważ stwarza to problemy w działaniu.

Nowość we fragmentach, dlatego potrzebuję łatwego i pedagogicznego wyjaśnienia!

Dzięki!

Joakim Ericsson
źródło

Odpowiedzi:

820

Od fragmentu do aktywności:

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

Od aktywności do fragmentu:

FragmentManager fm = getSupportFragmentManager();

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

Jeśli dodałeś fragment za pomocą kodu i użyłeś tagciągu podczas dodawania fragmentu, użyj findFragmentByTagzamiast tego:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");
Richard
źródło
5
BĄDŹ ostrożny, ponieważ nieoczekiwane rzeczy zdarzają się, jeśli obsada nie działa ..: S
Ewoks
48
Aby uniknąć problemu z rzutowaniem, użyj: Activity act = getActivity (); if (act instanceof YourActivityClassName) ((YourActivityClassName) act) .yourPublicMethod (); }
ericharlow,
@Richard: Jak możemy wykonać akcję przeciwną, na przykład, jeśli musimy wykonać metodę fragmentu wewnątrz działania?
Himanshu,
5
Rzucanie działania jest złym projektem i niebezpieczne. Fragment nie jest ograniczony do konkretnej czynności.
Aviv Ben Shabat
3
@Kay Niekoniecznie. Fragmenty można wykorzystać jako „fragmenty” każdej większej, podzielonej działalności. Aby na przykład utworzyć responsywne interfejsy użytkownika. Rzadko używam tego samego fragmentu i dołączam go do różnych hostów aktywności.
Richard
201

Prawdopodobnie powinieneś spróbować oddzielić fragment od aktywności na wypadek, gdybyś chciał użyć go gdzie indziej. Możesz to zrobić, tworząc interfejs, który implementuje Twoje działanie.

Zdefiniowałbyś więc interfejs w następujący sposób:

Załóżmy na przykład, że chcesz nadać działaniu ciąg i zwrócić mu liczbę całkowitą:

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

Można to zdefiniować we fragmencie lub oddzielnym pliku.

Wtedy twoje działanie zaimplementuje interfejs.

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

}

Następnie w swoim fragmencie miałbyś zmienną MyStringListener i ustawiłeś detektor we fragmencie na metodzie AtAttach (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. */
            }
        }

    }

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

Pierwsza odpowiedź zdecydowanie działa, ale łączy twój aktualny fragment z działalnością gospodarza. Dobrą praktyką jest utrzymywanie fragmentu niezwiązanego z działalnością gospodarza na wypadek, gdybyś chciał użyć go przy innej aktywności.

Marco RS
źródło
58
Dla każdego, kto na to patrzy, choć zaakceptowana odpowiedź oczywiście działa, jest to lepsze i bezpieczniejsze podejście z punktu widzenia projektowania.
Paul Richter,
7
ta odpowiedź jest o wiele lepsza pod względem projektowania kodu. również nie spowodowałoby to awarii, jeśli aktywność zostałaby źle wyrzucona
David T.
3
+1, ale nie użyłbym try-catch w onAttach. Niech to zawiedzie. Jeśli detektor jest opcjonalny (tzn. Niepowodzenie nie jest właściwe), dodaj metodę set / addListener do fragmentu.
ataulm
Informacje na temat komunikacji po drugiej stronie można znaleźć na stronie: developer.android.com/training/basics/fragments/… . Korzystając z interfejsu fragmentu (który jest również bezpiecznym sposobem wykonywania fragmentu -> aktywności comm, jak wyjaśniono powyżej), możesz wywołać metodę, która jest w twoim fragmencie, z twojej aktywności, jeśli chcesz podjąć działanie na podstawie swojego fragmentu -> aktywności comm.
Kerem
Fragmenty mają być ponownie użyte i ustawione w dowolnej Aktywności. Co się stanie, jeśli mam 5 działań wykorzystujących ten sam fragment? Odpowiedź Marco jest poprawna i stanowi dobrą praktykę w komunikacji między fragmentami i komunikacji fragmentu aktywności
blockwala
51

Dla programistów Kotlin

(activity as YourActivityClassName).methodName()

Dla programistów Java

((YourActivityClassName) getActivity()).methodName();
Wasim K. Memon
źródło
daje błąd w kotlin, jeśli uruchomimy ten kod .. czy jest inny sposób?
Jake Garbo,
1
Kiedy to uruchomię. Otrzymuję zerową wartość ActivityClass, myślę, że to nie jest właściwy sposób, aby to zrobić w kotlin, nawet bez błędu. a może błąd?
Jake Garbo
@JakeGarbo Właściwie, inaczej 12 osób nie zagłosowało na to. po drugie, getActivity () zwraca null sprawdź te pytania na SO.
Wasim K. Memon
@JakeGarbo Ya, powiedzieli ci. JEŚLI to zadziałało, doceń to, znajdź inny sposób lub naucz się najpierw kodować.
Wasim K. Memon
13

Zaktualizuj po tym, jak lepiej zrozumiem, jak działają fragmenty. Każdy fragment należy do działania rodzica. Więc po prostu użyj:

getActivity().whatever

Z fragmentu. To lepsza odpowiedź, ponieważ unikasz zbędnych rzutów. Jeśli nie możesz uniknąć rzutów za pomocą tego rozwiązania, skorzystaj z poniższego.

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

musicie rzucić na zewnętrzną aktywność

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

utworzenie nowej instancji będzie dezorientować ramkę Androida i nie będzie w stanie jej rozpoznać. Zobacz też :

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

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

sivi
źródło
9

Chociaż całkowicie podoba mi się odpowiedź Marco, myślę, że to sprawiedliwe, aby wskazać, że możesz również użyć frameworku opartego na publikowaniu / subskrybowaniu, aby osiągnąć ten sam wynik, na przykład jeśli wybierzesz magistralę zdarzeń, możesz wykonać następujące czynności

fragment:

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

Czynność:

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

}
A.Alqadomi
źródło
5

W kotlin możesz wywołać metodę aktywności z fragmentu jak poniżej:

var mainActivity: MainActivity = activity as MainActivity
        mainActivity.showToast() //Calling show toast method of activity
Maya Mohite
źródło
2

Aby uzyskać dostęp do funkcji zadeklarowanej w twojej aktywności poprzez swój fragment, użyj interfejsu, jak pokazano w odpowiedzi marco.

Aby uzyskać dostęp do funkcji zadeklarowanej we fragmencie za pośrednictwem aktywności, możesz jej użyć, jeśli nie masz tagu ani identyfikatora

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


}

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

Ta odpowiedź jest dla noobów takich jak ja. Miłego dnia.

hispeed
źródło
1

To klasa From Fragment ...

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

Ten kod z klasy aktywności ...

 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
źródło
1

Próbowałem ze wszystkimi metodami pokazanymi w tym wątku i żadna nie działała dla mnie, spróbuj tego. To zadziałało dla mnie.

((MainActivity) getContext().getApplicationContext()).Method();
Sergio Velásquez
źródło
0

Szukałem najlepszego sposobu, aby to zrobić, ponieważ nie każda metoda, którą chcemy wywołać, znajduje się we fragmencie z tym samym rodzicem aktywności.

W twoim fragmencie

public void methodExemple(View view){

        // your code here

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

W twojej działalności

new ExempleFragment().methodExemple(context); 
Maravilho Singa
źródło
0

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

Przykład: ((SessionActivity)getActivity()).changeFragment();

Uwaga: nazwa klasy powinna być publiczna

Harsha Vardhan Reddy N.
źródło
0
((your_activity) getActivity).method_name()

Gdzie your_activityjest nazwa twojej aktywności i method_name()nazwa metody, którą chcesz wywołać.

BIJAY_JHA
źródło
0

Dla Kotlina wypróbuj to

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
źródło