Rufen Sie eine Aktivitätsmethode aus einem Fragment auf

318

Ich versuche, eine Methode in meiner Aktivität aus einem Fragment aufzurufen. Ich möchte, dass das Fragment die Methodendaten angibt und die Daten abruft, wenn die Methode zurückkehrt. Ich möchte ähnlich wie beim Aufrufen einer statischen Methode erreichen, jedoch ohne die Verwendung von statischen, da dies zu Problemen bei der Aktivität führt.

Neu in Fragmenten, daher brauche ich eine einfache und pädagogische Erklärung!

Vielen Dank!

Joakim Ericsson
quelle

Antworten:

820

Vom Fragment zur Aktivität:

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

Von der Aktivität zum Fragment:

FragmentManager fm = getSupportFragmentManager();

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

Wenn Sie Fragment über Code hinzugefügt und tagbeim Hinzufügen Ihres Fragments eine Zeichenfolge verwendet haben , verwenden Sie findFragmentByTagstattdessen:

YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");
Richard
quelle
5
Seien Sie vorsichtig, da unerwartete Dinge passieren, wenn die Besetzung nicht funktioniert ..: S
Ewoks
48
Um das Besetzungsproblem zu vermeiden, verwenden Sie: Activity act = getActivity (); if (act instanceof YourActivityClassName) ((YourActivityClassName) act) .yourPublicMethod (); }
Ericharlow
@Richard: Wie können wir eine entgegengesetzte Aktion ausführen, wenn wir die Methode eines Fragments innerhalb der Aktivität ausführen müssen?
Himanshu
5
Es ist schlechtes Design und unsicher, eine Aktivität auszuführen. Ein Fragment ist nicht auf eine bestimmte Aktivität beschränkt.
Aviv Ben Shabat
3
@ Kay Nicht unbedingt. Fragmente können als "Fragmente" größerer Aktivitäten verwendet werden, die auseinandergebrochen sind. Zum Beispiel um reaktionsfähige Benutzeroberflächen zu erstellen. Ich verwende selten dasselbe Fragment und hänge es an verschiedene Aktivitätshosts an.
Richard
201

Sie sollten wahrscheinlich versuchen, das Fragment von der Aktivität zu entkoppeln, falls Sie es woanders verwenden möchten. Sie können dies tun, indem Sie eine Schnittstelle erstellen, die Ihre Aktivität implementiert.

Sie würden also eine Schnittstelle wie die folgende definieren:

Angenommen, Sie möchten der Aktivität einen String geben und eine Ganzzahl zurückgeben:

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

Dies kann im Fragment oder in einer separaten Datei definiert werden.

Dann würden Sie Ihre Aktivität die Schnittstelle implementieren lassen.

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

}

Dann hätten Sie in Ihrem Fragment eine MyStringListener-Variable und würden den Listener in der Methode fragment onAttach (Activity activity) festlegen.

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

    }

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

Die erste Antwort funktioniert definitiv, aber sie koppelt Ihr aktuelles Fragment mit der Hostaktivität. Es empfiehlt sich, das Fragment von der Hostaktivität zu entkoppeln, falls Sie es für eine andere Aktivität verwenden möchten.

Marco RS
quelle
58
Für alle anderen, die dies betrachten, funktioniert die akzeptierte Antwort offensichtlich, aber dies ist aus gestalterischer Sicht der bessere und sicherere Ansatz.
Paul Richter
7
Diese Antwort ist in Bezug auf das Code-Design viel besser. Außerdem würde es keine Abstürze verursachen, wenn die Aktivität falsch gewirkt wird
David T.
3
+1, aber ich würde keinen Try-Catch im onAttach verwenden. Lass es scheitern. Wenn der Listener optional ist (dh ein Fehler ist nicht angemessen), fügen Sie dem Fragment eine set / addListener-Methode hinzu.
Ataulm
Informationen zur Kommunikation auf der Gegenseite finden Sie unter: developer.android.com/training/basics/fragments/… . Über die Benutzeroberfläche des Fragments (dies ist auch die sichere Methode, um Fragment-> Aktivitätskommunikation auszuführen, wie oben erläutert) können Sie eine Methode, die sich in Ihrem Fragment befindet, auch aus Ihrer Aktivität heraus aufrufen, wenn Sie eine Aktion basierend auf Ihrer Fragment-> Aktivität ausführen möchten comm.
Kerem
Fragmente sollen in jeder Aktivität wiederverwendet und gesetzt werden. Was ist, wenn ich 5 Aktivitäten mit demselben Fragment habe? Marcos Antwort ist die richtige und eine gute Praxis für die Kommunikation zwischen Fragmenten und Aktivitätsfragmenten
Blockwala
50

Für Kotlin- Entwickler

(activity as YourActivityClassName).methodName()

Für Java- Entwickler

((YourActivityClassName) getActivity()).methodName();
Wasim K. Memon
quelle
Es gibt einen Fehler in Kotlin, wenn wir diesen Code ausführen. Gibt es einen anderen Weg?
Jake Garbo
1
Wenn ich es laufen lasse. Ich bekomme den Nullwert von ActivityClass, ich denke, dies ist nicht der richtige Weg, dies in Kotlin zu tun, auch ohne Fehler. oder vielleicht ein Bug?
Jake Garbo
@JakeGarbo Es ist richtig, sonst haben 12 Leute nicht dafür gestimmt. zweite , was einige Zeit getActivity () den Wert null zurück jene Frage auf SO überprüfen.
Wasim K. Memon
@ JakeGarbo Ya sie haben es dir gesagt. WENN es für Sie funktioniert hat, dann schätzen Sie es oder finden Sie einen anderen Weg oder lernen Sie zuerst, wie man programmiert.
Wasim K. Memon
13

Update, nachdem ich mehr verstanden habe, wie Fragmente funktionieren. Jedes Fragment gehört zu einer übergeordneten Aktivität. Also benutze einfach:

getActivity().whatever

Aus dem Fragment heraus. Es ist eine bessere Antwort, weil Sie überflüssige Würfe vermeiden. Wenn Sie die Abgüsse mit dieser Lösung nicht vermeiden können, verwenden Sie die folgende.

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

Was Sie tun müssen, ist, auf die äußere Aktivität zu werfen

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

Das Erstellen einer neuen Instanz verwirrt den Android-Frame und kann ihn nicht erkennen. siehe auch :

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

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

sivi
quelle
9

Obwohl ich Marcos Antwort völlig mag, denke ich, dass es fair ist, darauf hinzuweisen, dass Sie auch ein Publish / Subscribe-basiertes Framework verwenden können, um das gleiche Ergebnis zu erzielen. Wenn Sie beispielsweise mit dem Event-Bus fahren, können Sie Folgendes tun

Fragment :

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

Aktivität:

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

}
A. Alqadomi
quelle
5

In Kotlin können Sie die Aktivitätsmethode wie folgt aus einem Fragment aufrufen:

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

Für den Zugriff auf eine in Ihrer Aktivität deklarierte Funktion über Ihr Fragment verwenden Sie bitte eine Schnittstelle, wie in der Antwort von marco gezeigt.

Für den Zugriff auf eine in Ihrem Fragment deklarierte Funktion über Ihre Aktivität können Sie diese verwenden, wenn Sie kein Tag oder keine ID haben

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


}

Dies ist die 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);
    }
}

Diese Antwort ist für Noobs wie mich. Haben Sie einen guten Tag.

hispeed
quelle
1

Dies ist aus der Fragment-Klasse ...

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

Dieser Code aus der Aktivitätsklasse ...

 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
quelle
1

Ich habe es mit allen in diesem Thread gezeigten Methoden versucht und keine hat für mich funktioniert. Probieren Sie diese aus. Es hat bei mir funktioniert.

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

Ich habe nach dem besten Weg gesucht, dies zu tun, da sich nicht jede Methode, die wir aufrufen möchten, in Fragment mit demselben übergeordneten Aktivitätselement befindet.

In deinem Fragment

public void methodExemple(View view){

        // your code here

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

In Ihrer Aktivität

new ExempleFragment().methodExemple(context); 
Maravilho Singa
quelle
0

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

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

Hinweis: Der Klassenname sollte öffentlich sein

Harsha Vardhan Reddy N.
quelle
0
((your_activity) getActivity).method_name()

Wo your_activityist der Name Ihrer Aktivität und method_name()der Name der Methode, die Sie aufrufen möchten.

BIJAY_JHA
quelle
0

Für Kotlin probieren Sie es aus

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
quelle