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!

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

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.


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

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


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

}

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

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.


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

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

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

0

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

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

Uwaga: nazwa klasy powinna być publiczna


0
((your_activity) getActivity).method_name()

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


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)
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.