So implementieren Sie OnFragmentInteractionListener

151

Ich habe eine vom Assistenten generierte App mit Navigationsschublade in Android Studio 0.8.2

Ich habe ein Fragment erstellt und es mit newInstance () hinzugefügt und erhalte folgende Fehlermeldung:

com.domain.myapp E / AndroidRuntime ﹕ FATAL EXCEPTION: main java.lang.ClassCastException: com.domain.myapp.MainActivity@422fb8f0 muss OnFragmentInteractionListener implementieren

Ich kann nirgendwo finden, wie ich diesen OnFragmentInteractionListener implementieren soll? Es kann nicht einmal in der Android SDK-Dokumentation gefunden werden!

MainActivity.java

import android.app.Activity;

import android.app.ActionBar;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.widget.DrawerLayout;


public class MainActivity extends Activity
    implements NavigationDrawerFragment.NavigationDrawerCallbacks {

/**
 * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
 */
private NavigationDrawerFragment mNavigationDrawerFragment;

/**
 * Used to store the last screen title. For use in {@link #restoreActionBar()}.
 */
private CharSequence mTitle;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getFragmentManager().findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));
}

@Override
public void onNavigationDrawerItemSelected(int position) {
    // update the main content by replacing fragments
    FragmentManager fragmentManager = getFragmentManager();

    switch (position) {
        case 0: fragmentManager.beginTransaction()
                .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
                .commit(); break; 
        case 1: fragmentManager.beginTransaction() 
                .replace(R.id.container, AboutFragment.newInstance("test1", "test2"))
                .commit(); break; // this crashes the app
        case 2: fragmentManager.beginTransaction()
                .replace(R.id.container, BrowseQuotesFragment.newInstance("test1", "test2"))
                .commit(); break; // this crashes the app
    }
}


public void onSectionAttached(int number) {
    switch (number) {
        case 1:
            mTitle = getString(R.string.title_section1);
            break;
        case 2:
            mTitle = getString(R.string.title_section2);
            break;
        case 3:
            mTitle = getString(R.string.title_section3);
            break;
    }
}

public void restoreActionBar() {
    ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setTitle(mTitle);
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (!mNavigationDrawerFragment.isDrawerOpen()) {
        // Only show items in the action bar relevant to this screen
        // if the drawer is not showing. Otherwise, let the drawer
        // decide what to show in the action bar.
        getMenuInflater().inflate(R.menu.main, menu);
        restoreActionBar();
        return true;
    }
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

/**
 * A placeholder fragment containing a simple view.
 */
public static class PlaceholderFragment extends Fragment {
    /**
     * The fragment argument representing the section number for this
     * fragment.
     */
    private static final String ARG_SECTION_NUMBER = "section_number";

    /**
     * Returns a new instance of this fragment for the given section
     * number.
     */
    public static PlaceholderFragment newInstance(int sectionNumber) {
        PlaceholderFragment fragment = new PlaceholderFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_SECTION_NUMBER, sectionNumber);
        fragment.setArguments(args);
        return fragment;
    }

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        return rootView;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        ((MainActivity) activity).onSectionAttached(
                getArguments().getInt(ARG_SECTION_NUMBER));
    }
}

}}

Mario M.
quelle

Antworten:

120

Die hier geposteten Antworten haben nicht geholfen, aber der folgende Link hat geholfen:

http://developer.android.com/training/basics/fragments/communicating.html

Definieren Sie eine Schnittstelle

public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;

    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    ...
}

Die folgende Methode im Fragment wird beispielsweise aufgerufen, wenn der Benutzer auf ein Listenelement klickt. Das Fragment verwendet die Rückrufschnittstelle, um das Ereignis an die übergeordnete Aktivität zu übermitteln.

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    // Send the event to the host activity
    mCallback.onArticleSelected(position);
}

Implementieren Sie die Schnittstelle

Die folgende Aktivität implementiert beispielsweise die Schnittstelle aus dem obigen Beispiel.

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...

    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article
    }
}

Update für API 23: 31.08.2015

Die überschriebene Methode onAttach(Activity activity)ist jetzt veraltet android.app.Fragment. Der Code sollte auf aktualisiert werdenonAttach(Context context)

@Override
public void onAttach(Context context) {
    super.onAttach(context);
}


@Override
public void onStart() {
    super.onStart();
    try {
        mListener = (OnFragmentInteractionListener) getActivity();
    } catch (ClassCastException e) {
        throw new ClassCastException(getActivity().toString()
                + " must implement OnFragmentInteractionListener");
    }
}
meda
quelle
7
Bitte beachten Sie, dass onAttach(Activity activity);veraltet und ersetzt durchonAttach(Context context)
EpicPandaForce
1
@EpicPandaForce In der Tat haben Sie Recht, ich habe meinen Beitrag aktualisiert, um dies widerzuspiegeln
meda
1
Gibt es einen Grund, warum es von onAttach zu onStart wechselt? Kann ich es trotzdem in onAttach einfügen, indem ich nur den Kontext anstelle der Aktivität verwende?
Louis Tsai
Ich denke, nur mit onAttach(context)würde gut funktionieren
EpicPandaForce
212

Für diejenigen unter Ihnen, die nach dem Lesen der @ meda-Antwort immer noch nichts verstehen, ist hier meine kurze und vollständige Erklärung für dieses Problem:

Angenommen , Sie haben zwei Fragmente haben, Fragment_Aund Fragment_Bdas sind automatisch generiert aus der App. Im unteren Teil Ihrer generierten Fragmente finden Sie diesen Code:

public class Fragment_A extends Fragment {

    //rest of the code is omitted

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(Uri uri);
    }
}

public class Fragment_B extends Fragment {

    //rest of the code is omitted

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(Uri uri);
    }
}

Um das Problem zu beheben, müssen Sie onFragmentInteractionIhrer Aktivität eine Methode hinzufügen , die in meinem Fall benannt ist MainActivity2. Danach müssen Sie implementsalle Fragmente MainActivitywie folgt bearbeiten:

public class MainActivity2 extends ActionBarActivity
        implements Fragment_A.OnFragmentInteractionListener, 
                   Fragment_B.OnFragmentInteractionListener, 
                   NavigationDrawerFragment.NavigationDrawerCallbacks {
    //rest code is omitted

    @Override
    public void onFragmentInteraction(Uri uri){
        //you can leave it empty
    }
}

PS: Kurz gesagt, diese Methode könnte für die Kommunikation zwischen Fragmenten verwendet werden. Für diejenigen unter Ihnen, die mehr über diese Methode erfahren möchten, klicken Sie bitte auf diesen Link .

Bla ...
quelle
10
Bei der aktuellen Version des SDK in Android Studio müssen Sie die onFragmentIntereactior(Uri)Methode implementieren , die in keiner der anderen Antworten erwähnt wird. +1
2
Vielen Dank!
ofir_aghai
Vielen Dank, dass Sie dies erwähnt haben. Hat mir viel geholfen.
Hablema
2
Benötigt? Sie können einfach den Code löschen, der sich auf die Listener bezieht ... Wenn Sie Fragmente haben, die nicht mit anderen Fragmenten interagieren müssen, sind diese Listener nutzlos.
Trace
4
Viel einfacher zu folgen und zu verstehen als die akzeptierte Antwort.
Jerrythebum
44

Sehen Sie sich Ihre automatisch generierte Fragment, von Android Studio erstellte Version an. Als Sie das neue erstellt haben Fragment, hat Studio eine Menge Code für Sie erstellt. Am unteren Rand der automatisch generierten Vorlage befindet sich eine innere Schnittstellendefinition namens OnFragmentInteractionListener. Sie Activitymüssen diese Schnittstelle implementieren. Dies ist das empfohlene Muster, mit dem Sie FragmentIhre ActivityEreignisse benachrichtigen können , damit sie geeignete Maßnahmen ergreifen können, z. B. ein anderes laden Fragment. Weitere Informationen finden Sie auf dieser Seite im Abschnitt "Erstellen von Ereignisrückrufen für die Aktivität": http://developer.android.com/guide/components/fragments.html

Larry Schiefer
quelle
In der Dokumentation wird gezeigt, wie der Listener in dem Fragment implementiert wird (das bereits vom Assistenten generiert wurde), jedoch nicht in der Hauptaktivität, die zum Absturz der App führt.
Mario M
3
Nicht genau. Das Dokument (und der generierte Code) definieren die Schnittstelle und prüfen sie, wenn sie an die Activityangehängt ist Fragment. Der Absturz, den Sie sehen, ist, weil Sie Activitydie Schnittstelle nicht implementiert haben. Sie müssen in Ihre gehen Activityund eine implements YourFragment.OnFragmentInteractionListenerhinzufügen und dann eine Implementierung der in der Schnittstelle definierten Methode hinzufügen.
Larry Schiefer
ok, aber ich weiß nicht, wie ich diese Implementierung hinzufügen soll, weil es nirgends in der Android SDK-Dokumentation steht
Mario M
1
Es ist nicht Teil des SDK, sondern eine bewährte Methode. Der vom Assistenten erstellte Vorlagencode bildet lediglich die Grundlage für Sie. Die Schnittstelle onFragmentInteraction(Uri uri)ist nur ein Stich. Sie können diese Methode beliebig gestalten und Activitymüssen sie implementieren. Sehen Sie, ob dies hilft.
Larry Schiefer
3
Dieser Hinweis sparte viele Stunden. Während der Erstellung des Fragments UN-Check "Include Fragment Factory Methoden" und "Include Interface Callbacks". Und Sie müssen OnFragmentInteractionListener nicht implementieren. Ich benutze Android Studio 1.3.2 mit Java SDK 8. Android 6.0 (API 23) und SDK-Plattform 23 ist. Vielen Dank, Larry Schiefer.
Lerner
28

Für diejenigen unter Ihnen, die diese Seite besuchen und nach weiteren Erläuterungen zu diesem Fehler suchen, musste in meinem Fall die Aktivität, mit der das Fragment aufgerufen wird, in diesem Fall über zwei Geräte verfügen:

public class MyActivity extends Activity implements 
    MyFragment.OnFragmentInteractionListener, 
    NavigationDrawerFragment.NaviationDrawerCallbacks {
    ...// rest of the code
}
Bwvolleyball
quelle
9

Sie sollten versuchen, den folgenden Code aus Ihren Fragmenten zu entfernen

    try {
        mListener = (OnFragmentInteractionListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnFragmentInteractionListener");
    }

Die Schnittstelle / der Listener ist eine Standardeinstellung, die erstellt wurde, damit Ihre Aktivitäten und Fragmente einfacher kommunizieren können

Joe Plante
quelle
2
Dies ist ein sehr guter Punkt, da dieser Listener in den meisten Anfänger-Apps nicht benötigt wird.
Code-Lehrling
5

Zusätzlich zur Antwort von @ user26409021 lautet die Meldung im ItemFragment: Wenn Sie ein ItemFragment hinzugefügt haben;

Activities containing this fragment MUST implement the {@link OnListFragmentInteractionListener} interface.

Und Sie sollten in Ihrer Aktivität hinzufügen;

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener, ItemFragment.OnListFragmentInteractionListener {

//the code is omitted

 public void onListFragmentInteraction(DummyContent.DummyItem uri){
    //you can leave it empty
}

Hier ist der Dummy-Gegenstand das, was Sie unten in Ihrem ItemFragment haben

oneNiceFriend
quelle
5

Bei mir hat es geklappt diesen Code zu löschen:

@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

So enden:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
}
Vinicius Petrachin
quelle
4

OnFragmentInteractionListenerist die Standardimplementierung für die Verarbeitung der Kommunikation zwischen Fragmenten und Aktivitäten. Dies kann je nach Bedarf implementiert werden. Angenommen, Sie benötigen eine Funktion in Ihrer Aktivität, die während einer bestimmten Aktion in Ihrem Fragment ausgeführt werden soll, und können diese Rückrufmethode verwenden. Wenn Sie diese Interaktion zwischen Ihrem Hosting activityund nicht benötigen fragment, können Sie diese Implementierung entfernen.

Kurz gesagt, Sie sollten implementden Listener in Ihrer Fragment-Hosting-Aktivität, wenn Sie die Fragment-Aktivitäts-Interaktion wie diese benötigen

public class MainActivity extends Activity implements 
YourFragment.OnFragmentInteractionListener {..}

und Ihr Fragment sollte es so definiert haben

public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
}

Geben Sie auch eine Definition für void onFragmentInteraction(Uri uri);Ihre Aktivität an

Oder entfernen Sie einfach die listenerInitialisierung aus Ihrem Fragment, onAttachwenn Sie keine Interaktion zwischen Fragment und Aktivität haben

Navneet Krishna
quelle
3

Verwenden Sie anstelle von Aktivität den Kontext. Es funktioniert für mich.

@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            mListener = (OnFragmentInteractionListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
}
KCN
quelle
3

Nur ein Nachtrag:

OnFragmentInteractionListener verwaltet die Kommunikation zwischen Aktivität und Fragment über eine Schnittstelle (OnFragmentInteractionListener) und wird standardmäßig von Android Studio erstellt. Wenn Sie jedoch nicht mit Ihrer Aktivität kommunizieren müssen, können Sie einfach loslegen .

Das Ziel ist, dass Sie Ihr Fragment an mehrere Aktivitäten anhängen und dennoch denselben Kommunikationsansatz wiederverwenden können (jede Aktivität kann für jedes Fragment einen eigenen OnFragmentInteractionListener haben).

Aber und wenn ich sicher bin, dass mein Fragment nur an eine Art von Aktivität gebunden ist und ich mit dieser Aktivität kommunizieren möchte?

Wenn Sie OnFragmentInteractionListener aufgrund seiner Ausführlichkeit nicht verwenden möchten, können Sie auf Ihre Aktivitätsmethoden zugreifen, indem Sie:

((MyActivityClass) getActivity()).someMethod()
Sagits
quelle
Obwohl dies in den meisten Fällen funktionieren würde, kann getActivity () manchmal null zurückgeben, wenn sich die Fragmente während des Aufrufs von der Aktivität gelöst haben, z. B. in der postExecute-Methode einer Asynctask, wenn Sie get activity aufrufen, das Fragment jedoch bereits verlassen haben Bevor die asyncTask abgeschlossen ist, erhalten Sie eine Nullzeigerausnahme. Aus diesem Grund sagen die Android-Dokumente ausdrücklich, dass sie eine Fragment Interaction Listener-Schnittstelle verwenden sollen
MichaelStoddart
2

Gehen Sie einfach zu Ihrer Fragmentaktivität und entfernen Sie alle Methoden ..... stattdessen auf createview-Methode.

Ihr Fragment hat nur die Methode oncreateview, die es ist.

// Nur diese Methode implementiert eine andere Methode zum Löschen

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);
    return rootView;
}

und stellen Sie sicher, dass Ihr Layout eine Demo für Sie ist.

Kalpesh A. Nikam
quelle
Vielen Dank ... Wenn Sie etwas brauchen [email protected] Drop-Mail
Kalpesh A. Nikam
1

Ich möchte die Zerstörung des Listeners hinzufügen, wenn das Fragment von der Aktivität getrennt oder zerstört wird.

@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}

und bei Verwendung der neuen onStart () -Methode mit Context

@Override
public void onDestroy() {
    super.onDestroy();
    mListener = null;
}
rexxar
quelle