Come implementare OnFragmentInteractionListener


151

Ho un'app guidata guidata con il cassetto di navigazione in Android Studio 0.8.2

Ho creato un frammento e l'ho aggiunto con newInstance () e ottengo questo errore:

com.domain.myapp E / AndroidRuntime ﹕ ECCEZIONE FATALE: main java.lang.ClassCastException: com.domain.myapp.MainActivity@422fb8f0 deve implementare OnFragmentInteractionListener

Non riesco a trovare da nessuna parte come implementare questo OnFragmentInteractionListener ?? Non può essere trovato nemmeno nella documentazione di Android SDK!

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

}

Risposte:


120

Le risposte pubblicate qui non sono state di aiuto, ma il seguente link ha fatto:

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

Definire un'interfaccia

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

    ...
}

Ad esempio, il seguente metodo nel frammento viene chiamato quando l'utente fa clic su un elemento dell'elenco. Il frammento utilizza l'interfaccia di callback per recapitare l'evento all'attività padre.

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

Implementa l'interfaccia

Ad esempio, la seguente attività implementa l'interfaccia dall'esempio sopra.

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

Aggiornamento per API 23: 31/08/2015

Il metodo ignorato onAttach(Activity activity)è ora obsoleto android.app.Fragment, il codice deve essere aggiornato aonAttach(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");
    }
}

7
si prega di notare che onAttach(Activity activity);è deprecato e sostituito cononAttach(Context context)
EpicPandaForce

1
@EpicPandaForce In effetti hai ragione, ho aggiornato il mio post per riflettere quello
meda

1
C'è qualche motivo per cui si sposta da onAttach a onStart? posso ancora inserirlo in Attach solo usando il contesto anziché l'attività?
Louis Tsai,

Penso che solo usando onAttach(context)funzionerebbe benissimo
EpicPandaForce

212

Per quelli di voi che ancora non capiscono dopo aver letto la risposta di @meda, ecco la mia spiegazione concisa e completa per questo problema:

Supponiamo che tu abbia 2 frammenti Fragment_Ae Fragment_Bche vengono generati automaticamente dall'app. Nella parte inferiore dei frammenti generati, troverai questo codice:

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

Per superare il problema, devi aggiungere un onFragmentInteractionmetodo alla tua attività, che nel mio caso è denominata MainActivity2. Successivamente, è necessario implementstutti i frammenti in MainActivityquesto modo:

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: in breve, questo metodo potrebbe essere usato per comunicare tra frammenti. Per quelli di voi che vogliono saperne di più su questo metodo, fare riferimento a questo link .


10
Con l'attuale versione dell'SDK in Android Studio, è necessario implementare il onFragmentIntereactior(Uri)metodo, che non è menzionato in nessuna delle altre risposte. +1

2
Grazie mille!
ofir_aghai,

Grazie per averlo menzionato. Mi ha aiutato molto
hablema,

2
Richiede? Puoi semplicemente cancellare il codice relativo agli ascoltatori ... Se ti capita di avere frammenti che non hanno bisogno di interagire con altri frammenti, quegli ascoltatori sono inutili.
Traccia il

4
Molto più facile da seguire e capire della risposta accettata.
jerrythebum,

44

Guarda il tuo generato automaticamente Fragmentcreato da Android Studio. Quando hai creato il nuovo Fragment, Studio ha creato un mucchio di codice per te. Nella parte inferiore del modello generato automaticamente è presente una definizione di interfaccia interna chiamata OnFragmentInteractionListener. È Activitynecessario implementare questa interfaccia. Questo è lo schema consigliato per la Fragmentnotifica Activitydegli eventi in modo che possa quindi intraprendere le azioni appropriate, come caricarne un altro Fragment. Vedere questa pagina per i dettagli, cercare la sezione "Creazione di callback di eventi per l'attività": http://developer.android.com/guide/components/fragments.html


Nella documentazione mostra come implementare l'ascoltatore nel frammento (che è già generato dalla procedura guidata), ma non nella mainattività che causa l'arresto anomalo dell'app.
Mario M,

3
Non esattamente. Il documento (e il codice generato) definiscono l'interfaccia e la controllano quando Activityè collegata a Fragment. Il crash che stai vedendo è perché Activitynon hai implementato l'interfaccia. Devi andare nel tuo Activitye aggiungere un implements YourFragment.OnFragmentInteractionListenerquindi aggiungere un'implementazione del metodo definito nell'interfaccia.
Larry Schiefer,

ok, ma non so come aggiungere questa implementazione perché non è presente nella documentazione di Android SDK
Mario M

1
Non fa parte dell'SDK, ma è una buona pratica. Il codice modello prodotto dalla procedura guidata sta semplicemente ponendo le basi per te. L'interfaccia onFragmentInteraction(Uri uri)è solo uno stub. Puoi rendere questo metodo tutto ciò che desideri e le tue Activityesigenze per implementarlo. Vedi se questo aiuta.
Larry Schiefer,

3
Questo suggerimento ha risparmiato molte ore. Durante la creazione del frammento UN-check "include metodi di framment factory" e "include callbacks di interfaccia". E non è necessario implementare OnFragmentInteractionListener. Sto usando Android Studio 1.3.2 con Java SDK 8. Android 6.0 (API 23) e la piattaforma SDK 23 è. Grazie Larry Schiefer.
studente

28

Per quelli di voi che visitano questa pagina in cerca di ulteriori chiarimenti su questo errore, nel mio caso l'attività che ha effettuato la chiamata al frammento aveva bisogno di avere 2 strumenti in questo caso, come questo:

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

9

Dovresti provare a rimuovere il seguente codice dai tuoi frammenti

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

L'interfaccia / listener è un valore predefinito creato in modo che l'attività e i frammenti possano comunicare più facilmente


2
Questo è un ottimo punto poiché questo ascoltatore non è necessario nella maggior parte delle app per principianti.
Apprendista di codice

5

Oltre alla risposta di @ user26409021, se hai aggiunto ItemFragment, il messaggio in ItemFragment è;

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

E dovresti aggiungere la tua attività;

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
}

Qui l'oggetto fittizio è quello che hai nella parte inferiore del tuo ItemFragment


5

Con me ha funzionato eliminare questo codice:

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

Finendo così:

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

4

OnFragmentInteractionListenerè l'implementazione predefinita per la gestione della comunicazione frammento-attività. Questo può essere implementato in base alle tue esigenze. Supponiamo che se hai bisogno di una funzione nella tua attività da eseguire durante una determinata azione all'interno del tuo frammento, puoi utilizzare questo metodo di callback. Se non hai bisogno di avere questa interazione tra il tuo hosting activitye fragment, puoi rimuovere questa implementazione.

In breve, dovresti implementascoltare l'ascoltatore nella tua attività di hosting dei frammenti se hai bisogno dell'interazione frammento-attività come questa

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

e il tuo frammento dovrebbe averlo definito in questo modo

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

fornisci anche la definizione per void onFragmentInteraction(Uri uri);nella tua attività

oppure rimuovi l' listenerinizializzazione dai frammenti onAttachse non hai interazioni frammento-attività


3

Invece di Activity usa il contesto. Funziona per me.

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

3

Solo un addendum:

OnFragmentInteractionListener gestisce la comunicazione tra Activity e Fragment utilizzando un'interfaccia (OnFragmentInteractionListener) ed è creato per impostazione predefinita da Android Studio, ma se non hai bisogno di comunicare con la tua attività, puoi semplicemente cavartela.

L'obiettivo è che puoi collegare il tuo frammento a più attività e riutilizzare ancora lo stesso approccio comunicativo (ogni attività potrebbe avere il proprio OnFragmentInteractionListener per ogni frammento).

Ma e se sono sicuro che il mio frammento sarà collegato a un solo tipo di attività e voglio comunicare con quell'attività?

Quindi, se non si desidera utilizzare OnFragmentInteractionListener a causa della sua verbosità, è possibile accedere ai metodi di attività utilizzando:

((MyActivityClass) getActivity()).someMethod()

Sebbene ciò funzionerebbe nella maggior parte dei casi, a volte getActivity () può restituire null se i frammenti si sono staccati dall'attività mentre viene chiamato, ad esempio nel metodo postExecute di un asynctask, se chiami get attività ma hai già lasciato il frammento prima che asyncTask sia completato, si otterrà un'eccezione puntatore null. Per questo motivo i documenti Android affermano specificamente di utilizzare un'interfaccia di ascolto di interazione di frammenti
MichaelStoddart,

2

Vai al tuo frammento Attività e rimuovi tutti i metodi ..... invece sul metodo createview.

il tuo frammento ha solo il metodo oncreateview questo è tutto.

// solo questo metodo implementa l'eliminazione dell'altro metodo

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

e assicurati che il tuo layout sia demo per te.


Grazie ... Se ha bisogno di qualcosa kalpeshnikam1080@gmail.com drop mail
Kalpesh A. Nikam

1

Vorrei aggiungere la distruzione dell'ascoltatore quando il frammento viene staccato dall'attività o distrutto.

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

e quando si utilizza il nuovo metodo onStart () con Context

@Override
public void onDestroy() {
    super.onDestroy();
    mListener = null;
}
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.