Cara menerapkan OnFragmentInteractionListener

151

Saya memiliki aplikasi wizard yang dihasilkan dengan laci navigasi di android studio 0.8.2

Saya telah membuat fragmen dan menambahkannya dengan newInstance () dan saya mendapatkan kesalahan ini:

com.domain.myapp E / AndroidRuntime ﹕ PENGECUALIAN FATAL: java.lang.ClassCastException utama: com.domain.myapp.MainActivity@422fb8f0 harus menerapkan OnFragmentInteractionListener

Saya tidak dapat menemukan cara menerapkan OnFragmentInteractionListener ini ?? Itu tidak dapat ditemukan bahkan dalam dokumentasi SDK android!

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
sumber

Jawaban:

120

Jawaban yang diposting di sini tidak membantu, tetapi tautan berikut berhasil:

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

Tentukan Antarmuka

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

    ...
}

Misalnya, metode berikut dalam fragmen dipanggil saat pengguna mengklik item daftar. Fragmen tersebut menggunakan antarmuka panggilan balik untuk mengirimkan acara ke aktivitas induk.

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

Implementasikan Antarmuka

Misalnya, aktivitas berikut mengimplementasikan antarmuka dari contoh di atas.

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

Pembaruan untuk API 23: 8/31/2015

Metode yang diganti onAttach(Activity activity)sekarang sudah usang android.app.Fragment, kode harus ditingkatkan keonAttach(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
sumber
7
harap dicatat bahwa onAttach(Activity activity);sudah usang, dan diganti denganonAttach(Context context)
EpicPandaForce
1
@EpicPandaForce Memang Anda benar, saya memperbarui posting saya untuk mencerminkan itu
meda
1
Apakah ada alasan mengapa ini berpindah dari onAttach ke onStart? dapatkah saya tetap menaruhnya di onAttach hanya menggunakan konteks, bukan aktivitas?
Louis Tsai
Saya pikir hanya menggunakan onAttach(context)akan bekerja dengan baik
EpicPandaForce
212

Bagi Anda yang masih belum mengerti setelah membaca jawaban @meda, berikut adalah penjelasan singkat dan lengkap saya untuk masalah ini:

Katakanlah Anda memiliki 2 Fragmen, Fragment_Adan Fragment_Byang dihasilkan secara otomatis dari aplikasi. Di bagian bawah fragmen yang dibuat, Anda akan menemukan kode ini:

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

Untuk mengatasi masalah ini, Anda harus menambahkan onFragmentInteractionmetode ke aktivitas Anda, yang dalam kasus saya dinamai MainActivity2. Setelah itu, Anda perlu implementssemua fragmen MainActivityseperti ini:

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: Singkatnya, metode ini bisa digunakan untuk berkomunikasi antar fragmen. Bagi Anda yang ingin tahu lebih banyak tentang metode ini, silakan merujuk ke tautan ini .

Bla ...
sumber
10
Dengan versi terbaru dari SDK di Android Studio, itu membutuhkan Anda untuk menerapkan onFragmentIntereactior(Uri)metode, yang tidak disebutkan dalam salah satu jawaban lainnya. +1
2
Terima kasih banyak!
ofir_aghai
Terima kasih telah menyebutkan ini. Banyak membantu saya.
hablema
2
Membutuhkan? Anda dapat menghapus kode yang terkait dengan pendengar ... Jika Anda memiliki fragmen yang tidak perlu berinteraksi dengan fragmen lain, pendengar itu tidak berguna.
Jejak
4
Jauh lebih mudah diikuti dan dipahami daripada jawaban yang diterima.
jerrythebum
44

Lihat hasil otomatis Anda Fragmentdibuat oleh Android Studio. Ketika Anda membuat yang baru Fragment, Studio stubbed sekelompok kode untuk Anda. Di bagian bawah template yang dibuat secara otomatis ada definisi antarmuka bagian dalam yang disebut OnFragmentInteractionListener. ActivityKebutuhan Anda untuk mengimplementasikan antarmuka ini. Ini adalah pola yang disarankan bagi Anda Fragmentuntuk memberi tahu Activityacara Anda sehingga dapat mengambil tindakan yang sesuai, seperti memuat lainnya Fragment. Lihat halaman ini untuk detailnya, lihat bagian "Membuat callback acara untuk Aktivitas": http://developer.android.com/guide/components/fragments.html

Larry Schiefer
sumber
Dalam dokumentasi menunjukkan bagaimana menerapkan pendengar dalam fragmen (yang sudah dihasilkan oleh penyihir), tetapi tidak dalam aktivitas utama yang menyebabkan aplikasi mogok.
Mario M
3
Tidak persis. Doc (dan kode yang dihasilkan) mendefinisikan antarmuka dan mengeceknya ketika Activitydilampirkan ke Fragment. Kecelakaan yang Anda lihat adalah karena Activityantarmuka antarmuka Anda belum diterapkan. Anda harus masuk ke Activitydan menambahkan implements YourFragment.OnFragmentInteractionListenerlalu tambahkan implementasi metode yang didefinisikan dalam antarmuka.
Larry Schiefer
ok, tapi saya tidak tahu bagaimana menambahkan implementasi itu karena tidak ada dalam dokumentasi sdk android
Mario M
1
Ini bukan bagian dari SDK, tetapi praktik terbaik. Kode template yang dihasilkan oleh wizard hanya meletakkan dasar untuk Anda. Antarmuka onFragmentInteraction(Uri uri)hanyalah sebuah rintisan. Anda dapat membuat metode ini apa pun yang Anda inginkan dan Activitykebutuhan Anda untuk mengimplementasikannya. Lihat apakah ini membantu.
Larry Schiefer
3
Petunjuk ini menghemat banyak jam. Saat membuat fragmen, periksa "sertakan metode pabrik fragmen" dan "sertakan panggilan balik antarmuka". Dan Anda tidak harus mengimplementasikan OnFragmentInteractionListener. Saya menggunakan Android studio 1.3.2 dengan Java SDK 8. Android 6.0 (API 23) dan SDK-platform 23 adalah. Terima kasih Larry Schiefer.
pelajar
28

Bagi Anda yang mengunjungi halaman ini untuk mencari klarifikasi lebih lanjut tentang kesalahan ini, dalam kasus saya, aktivitas membuat panggilan ke fragmen perlu memiliki 2 implementasi dalam kasus ini, seperti ini:

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

Anda harus mencoba menghapus kode berikut dari fragmen Anda

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

Antarmuka / pendengar adalah default yang dibuat sehingga aktivitas dan fragmen Anda dapat berkomunikasi dengan lebih mudah

Joe Plante
sumber
2
Ini adalah poin yang sangat bagus karena pendengar ini tidak diperlukan di sebagian besar aplikasi pemula.
Code-Apprentice
5

Selain jawaban @ user26409021, Jika Anda telah menambahkan ItemFragment, Pesan di ItemFragment adalah;

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

Dan Anda harus menambahkan aktivitas Anda;

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
}

Di sini item dummy adalah apa yang Anda miliki di bagian bawah ItemFragment Anda

oneNiceFriend
sumber
5

Dengan saya itu berhasil menghapus kode ini:

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

Berakhir seperti ini:

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

OnFragmentInteractionListeneradalah implementasi default untuk menangani fragmen komunikasi aktivitas. Ini dapat diimplementasikan berdasarkan kebutuhan Anda. Misalkan jika Anda memerlukan fungsi dalam aktivitas Anda untuk dieksekusi selama tindakan tertentu dalam fragmen Anda, Anda dapat menggunakan metode panggilan balik ini. Jika Anda tidak perlu memiliki interaksi antara hosting activitydan fragment, Anda dapat menghapus implementasi ini.

Singkatnya, Anda harus implementmenjadi pendengar dalam aktivitas hosting fragmen Anda jika Anda memerlukan interaksi fragmen-aktivitas seperti ini

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

dan fragmen Anda harus didefinisikan seperti ini

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

juga memberikan definisi untuk void onFragmentInteraction(Uri uri);aktivitas Anda

atau hapus saja listenerinisialisasi dari fragmen onAttachAnda jika Anda tidak memiliki interaksi fragmen-aktivitas

Navneet Krishna
sumber
3

Alih-alih menggunakan konteks Aktivitas. Ini bekerja untuk saya.

@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
sumber
3

Hanya sebuah tambahan:

OnFragmentInteractionListener menangani komunikasi antara Activity dan Fragment menggunakan antarmuka (OnFragmentInteractionListener) dan dibuat secara default oleh Android Studio, tetapi jika Anda tidak perlu berkomunikasi dengan aktivitas Anda, Anda bisa mendapatkannya.

Tujuannya adalah Anda dapat melampirkan fragmen Anda ke beberapa aktivitas dan masih menggunakan kembali pendekatan komunikasi yang sama (Setiap aktivitas dapat memiliki OnFragmentInteractionListener sendiri untuk setiap fragmen).

Tetapi dan jika saya yakin fragmen saya akan melekat hanya pada satu jenis aktivitas dan saya ingin berkomunikasi dengan aktivitas itu?

Kemudian, jika Anda tidak ingin menggunakan OnFragmentInteractionListener karena verbositasnya, Anda dapat mengakses metode aktivitas menggunakan:

((MyActivityClass) getActivity()).someMethod()
sagit
sumber
Meskipun ini akan bekerja dalam kebanyakan kasus, kadang-kadang getActivity () dapat mengembalikan nol jika fragmen telah terlepas dari aktivitas saat ini dipanggil, misalnya dalam metode postExecute dari asynctask, jika Anda memanggil get activity tetapi sudah meninggalkan fragmennya sebelum asyncTask selesai maka Anda akan mendapatkan pengecualian null pointer. Untuk alasan ini dokumen android secara khusus mengatakan untuk menggunakan antarmuka pendengar interaksi fragmen
MichaelStoddart
2

Cukup buka Aktivitas fragmen Anda dan hapus semua metode ..... alih-alih pada metode createview.

fragmen Anda hanya memiliki metode oncreateview saja.

// hanya metode ini yang menerapkan metode hapus lainnya

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

dan pastikan tata letak Anda adalah demo untuk Anda.

Kalpesh A. Nikam
sumber
Terima Kasih ... Jika perlu Sesuatu [email protected] drop mail
Kalpesh A. Nikam
1

Saya ingin menambahkan kehancuran pendengar ketika fragmen terlepas dari aktivitas atau dihancurkan.

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

dan ketika menggunakan metode onStart () baru dengan Konteks

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