Bagaimana menerapkan onBackPressed() dalam Fragmen?

Apakah ada cara di mana kita dapat melaksanakan onBackPressed() di Android Fragmen yang mirip dengan cara di mana kita melaksanakan di Android Aktivitas?

Sebagai Fragmen siklus hidup tidak memiliki onBackPressed(). Apakah ada alternatif lain metode untuk lebih naik onBackPressed() pada Android 3.0 fragmen?

Mengomentari pertanyaan (8)

Aku diselesaikan dengan cara ini menimpa onBackPressed dalam Kegiatan tersebut. Semua FragmentTransaction adalah addToBackStack sebelum melakukan:

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();
        //additional code
    } else {
        getSupportFragmentManager().popBackStack();
    }

}
Komentar (8)

Aku hal terbaik solusi

SOLUSI JAVA

Membuat antarmuka yang sederhana :

public interface IOnBackPressed {
    /**
     * If you return true the back press will not be taken into account, otherwise the activity will act naturally
     * @return true if your processing has priority if not false
     */
    boolean onBackPressed();
}

Dan dalam Aktivitas anda

public class MyActivity extends Activity {
    @Override public void onBackPressed() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
       if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
          super.onBackPressed();
       }
    } ...
}

Akhirnya di Fragmen:

public class MyFragment extends Fragment implements IOnBackPressed{
   @Override
   public boolean onBackPressed() {
       if (myCondition) {
            //action not popBackStack
            return true; 
        } else {
            return false;
        }
    }
}

KOTLIN SOLUSI

1 - Membuat Antarmuka

interface IOnBackPressed {
    fun onBackPressed(): Boolean
}

2 - Mempersiapkan Aktivitas anda

class MyActivity : AppCompatActivity() {
    override fun onBackPressed() {
        val fragment =
            this.supportFragmentManager.findFragmentById(R.id.main_container)
        (fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
            super.onBackPressed()
        }
    }
}

3 - Melaksanakan target anda Fragmen

class MyFragment : Fragment(), IOnBackPressed {
    override fun onBackPressed(): Boolean {
        return if (myCondition) {
            //action not popBackStack
            true
        } else {
            false
        }
    }
}
Komentar (11)

Menurut @Dipalu jawaban berikut adalah pseudocode bagaimana harus bekerja. Katakanlah bahwa aktivitas utama anda adalah yang disebut BaseActivity yang memiliki anak fragmen (seperti di SlidingMenu lib contoh). Berikut ini adalah langkah-langkahnya:

Pertama kita perlu membuat interface dan kelas yang mengimplementasikan interface-nya untuk memiliki metode generik

  1. Buat kelas antarmuka OnBackPressedListener

antarmuka publik OnBackPressedListener { public void doBack(); }

  1. Membuat class yang mengimplementasikan keterampilan OnBackPressedListener

public class BaseBackPressedListener mengimplementasikan OnBackPressedListener { private akhir FragmentActivity kegiatan;

publik BaseBackPressedListener(FragmentActivity kegiatan) { ini.kegiatan = kegiatan; }

@Override public void doBack() { kegiatan.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); } }

  1. Sejak sekarang, kami akan bekerja pada kode kita BaseActivity dan fragmen
  2. Buat pendengar di atas anda kelas BaseActivity

dilindungi OnBackPressedListener onBackPressedListener;

  1. membuat metode untuk mengatur pendengar di BaseActivity

public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) { ini.onBackPressedListener = onBackPressedListener; }

  1. di override onBackPressed melaksanakan sesuatu seperti itu

@Override public void onBackPressed() { jika (onBackPressedListener != null) onBackPressedListener.doBack(); lain super.onBackPressed();

  1. dalam fragmen di onCreateView anda harus menambahkan pendengar kami

@Override Pandangan publik onCreateView(LayoutInflater inflater, ViewGroup wadah, Bundle savedInstanceState) { kegiatan = getActivity();

((BaseActivity)kegiatan).setOnBackPressedListener(baru BaseBackPressedListener(aktivitas));

View = ... ; //hal-hal dengan melihat

kembali melihat; }

Voila, sekarang ketika anda klik kembali pada fragmen anda harus menangkap kustom anda pada metode kembali.

Komentar (6)

Ini bekerja untuk saya: https://stackoverflow.com/a/27145007/3934111

@Override
public void onResume() {
    super.onResume();

    if(getView() == null){
        return;
    }

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
                // handle back button's click listener
                return true;
            }
            return false;
        }
    });
}
Komentar (4)

Jika anda ingin semacam fungsi yang anda akan perlu untuk menimpa pada aktivitas anda, dan kemudian menambahkan YourBackPressed antarmuka untuk semua fragmen, yang anda sebut di atas relevan fragmen setiap kali tombol kembali ditekan.

Edit: I'd ingin menambahkan jawaban saya sebelumnya.

Jika saya lakukan hari ini, saya'a menggunakan broadcast, atau mungkin memerintahkan siaran jika saya harapkan panel lain untuk pemutakhiran serempak ke master/konten utama panel.

LocalBroadcastManager dalam Mendukung Perpustakaan dapat membantu dengan ini, dan anda hanya mengirim broadcast di onBackPressed dan berlangganan di fragmen yang peduli. Saya berpikir bahwa Pesan yang lebih dipisahkan pelaksanaan dan skala baik, sehingga akan saya resmi pelaksanaan rekomendasi sekarang. Hanya menggunakan Niat's bertindak sebagai filter untuk pesan anda. mengirimkan anda yang baru dibuat ACTION_BACK_PRESSED, kirim dari aktivitas anda dan mendengarkan untuk itu dalam relevan fragmen.

Komentar (7)

Tidak ada yang mudah untuk menerapkan dan tidak akan berfungsi secara optimal.

Fragmen memiliki metode panggilan onDetach yang akan melakukan pekerjaan.

@Override
    public void onDetach() {
        super.onDetach();
        PUT YOUR CODE HERE
    }

INI AKAN MELAKUKAN PEKERJAAN.

Komentar (5)

Hanya menambahkan addToBackStack saat anda beralih di antara fragmen-fragmen seperti di bawah ini:

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

jika anda menulis addToBackStack(null) , itu akan menangani hal ini dengan sendirinya tetapi jika anda memberi tag , anda harus menanganinya secara manual.

Komentar (3)

karena pertanyaan ini dan beberapa jawaban yang lebih dari lima tahun, biarkan saya berbagi solusi saya. Ini adalah follow-up dan modernisasi untuk jawaban dari @oyenigun

UPDATE: Di bagian bawah artikel ini, saya menambahkan alternatif implementasi menggunakan abstrak Fragmen ekstensi yang tidak't melibatkan Aktivitas sama sekali, yang akan berguna bagi siapa saja dengan yang lebih kompleks fragmen hirarki yang melibatkan bersarang fragmen yang berbeda membutuhkan kembali perilaku.

Aku yang diperlukan untuk melaksanakan ini karena beberapa fragmen yang saya gunakan memiliki pandangan yang lebih kecil yang saya ingin memberhentikan dengan tombol kembali, seperti informasi kecil pemandangan yang pop up, dll, tapi ini bagus untuk siapa saja yang membutuhkan untuk mengganti perilaku tombol kembali di dalam fragmen-fragmen.

Pertama, mendefinisikan sebuah Antarmuka

public interface Backable {
    boolean onBackPressed();
}

Antarmuka ini, yang saya sebut Didukung (I'm ngotot untuk konvensi penamaan), memiliki satu metode onBackPressed() yang harus kembali boolean nilai. Kita perlu menegakkan nilai boolean karena kita akan perlu untuk mengetahui apakah tombol kembali tekan "diserap" kembali acara. Kembali benar berarti bahwa ia memiliki, dan tidak ada tindakan lebih lanjut diperlukan, jika tidak, false mengatakan bahwa default kembali aksi masih berlangsung. Antarmuka ini harus itu's file sendiri (sebaiknya dalam paket terpisah bernama interface). Ingat, memisahkan kelas anda ke dalam paket adalah praktik yang baik.

Kedua, menemukan beberapa fragmen

Saya dibuat sebuah metode yang mengembalikan terakhir Fragmen objek di belakang tumpukan. Saya menggunakan tag... jika anda menggunakan ID's, membuat perubahan yang diperlukan. Saya memiliki metode statis di kelas utilitas yang berhubungan dengan navigasi serikat, dll... tapi tentu saja, menempatkan di tempat yang paling cocok untuk anda. Untuk peneguhan, I've menempatkan saya di kelas yang disebut NavUtils.

public static Fragment getCurrentFragment(Activity activity) {
    FragmentManager fragmentManager = activity.getFragmentManager();
    if (fragmentManager.getBackStackEntryCount() > 0) {
        String lastFragmentName = fragmentManager.getBackStackEntryAt(
                fragmentManager.getBackStackEntryCount() - 1).getName();
        return fragmentManager.findFragmentByTag(lastFragmentName);
    }
    return null;
}

Pastikan kembali tumpukan hitung lebih besar dari 0, jika tidak sebuah ArrayOutOfBoundsException bisa dilemparkan pada saat runtime. Jika isn't lebih besar dari 0, return null. Kami'll memeriksa nilai null nanti...

Ketiga, Menerapkan dalam sebuah Fragmen

Menerapkan Didukung antarmuka di mana fragmen di mana anda perlu untuk mengganti tombol kembali perilaku. Tambahkan metode pelaksanaan.

public class SomeFragment extends Fragment implements 
        FragmentManager.OnBackStackChangedListener, Backable {

...

    @Override
    public boolean onBackPressed() {

        // Logic here...
        if (backButtonShouldNotGoBack) {
            whateverMethodYouNeed();
            return true;
        }
        return false;
    }

}

Di onBackPressed() override, menempatkan apapun logika yang anda butuhkan. Jika anda ingin tombol back to bukan pop back stack (perilaku default), kembali sejati, bahwa anda kembali acara yang telah diserap. Jika tidak, kembali palsu.

Terakhir, dalam Aktivitas anda...

Menimpa onBackPressed() metode dan menambahkan logika ini:

@Override
public void onBackPressed() {

    // Get the current fragment using the method from the second step above...
    Fragment currentFragment = NavUtils.getCurrentFragment(this);

    // Determine whether or not this fragment implements Backable
    // Do a null check just to be safe
    if (currentFragment != null && currentFragment instanceof Backable) {

        if (((Backable) currentFragment).onBackPressed()) {
            // If the onBackPressed override in your fragment 
            // did absorb the back event (returned true), return
            return;
        } else {
            // Otherwise, call the super method for the default behavior
            super.onBackPressed();
        }
    }

    // Any other logic needed...
    // call super method to be sure the back button does its thing...
    super.onBackPressed();
}

Kami mendapatkan fragmen saat ini di back stack, maka kita lakukan null memeriksa dan menentukan apakah itu mengimplementasikan kami Didukung antarmuka. Jika tidak, menentukan apakah acara tersebut diserap. Jika demikian, kita're dilakukan dengan onBackPressed() dan dapat kembali. Jika tidak, memperlakukannya sebagai normal kembali tekan dan call super metode.

Pilihan kedua untuk tidak melibatkan Aktivitas

Pada saat ini, anda don't ingin Kegiatan untuk menangani ini semua, dan anda perlu untuk menangani langsung dalam fragmen. Tapi siapa bilang anda dapat't memiliki Fragmen dengan tekan kembali API? Hanya memperpanjang fragmen ke kelas baru.

Membuat sebuah kelas abstrak yang memanjang Fragmen dan mengimplementasikan Melihat.OnKeyListner antarmuka...

import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public abstract class BackableFragment extends Fragment implements View.OnKeyListener {

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.setFocusableInTouchMode(true);
        view.requestFocus();
        view.setOnKeyListener(this);
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                onBackButtonPressed();
                return true;
            }
        }

        return false;
    }

    public abstract void onBackButtonPressed();
}

Seperti yang anda lihat, setiap fragmen yang meluas BackableFragment secara otomatis akan menangkap kembali klik menggunakan Melihat.OnKeyListener antarmuka. Hanya panggilan abstrak onBackButtonPressed() metode dari dalam menerapkan ng mengambang dan donkey() menggunakan metode standar logika untuk melihat tekan tombol kembali. Jika anda perlu untuk mendaftar klik tombol selain tombol kembali, hanya pastikan untuk memanggil super ketika meng-override metode ng mengambang dan donkey() dalam fragmen anda, jika anda'll override perilaku dalam abstraksi.

Mudah digunakan, hanya memperluas dan menerapkan:

public class FragmentChannels extends BackableFragment {

    ...

    @Override
    public void onBackButtonPressed() {
        if (doTheThingRequiringBackButtonOverride) {
            // do the thing
        } else {
            getActivity().onBackPressed();
        }
    }

    ...
}

Sejak onBackButtonPressed() metode di kelas super adalah abstrak, setelah anda memperpanjang anda harus menerapkan onBackButtonPressed(). Kembali batal karena itu hanya perlu untuk melakukan suatu tindakan dalam fragmen kelas, dan tidak perlu relay penyerapan tekan kembali untuk Aktivitas. Pastikan anda melakukan panggilan Aktivitas onBackPressed() jika metode apapun yang anda're lakukan dengan tombol kembali doesn't membutuhkan penanganan, jika tidak, tombol kembali akan dinonaktifkan... dan anda don't ingin itu!

Peringatan Seperti yang anda lihat, ini set kunci pendengar ke akar lihat dari fragmen, dan kami'll perlu fokus itu. Jika ada yang mengedit naskah-naskah yang terlibat (atau yang lain fokus-mencuri pandangan) dalam fragmen yang membentang di kelas ini, (atau bagian lain fragmen atau pandangan yang sama), anda'll perlu menangani secara terpisah. Ada's sebuah artikel yang baik pada memperpanjang EditText untuk kehilangan fokus pada kembali tekan.

Saya berharap seseorang menemukan ini berguna. Happy coding.

Komentar (6)

Solusinya sederhana:

  1. Jika anda memiliki basis fragmen kelas yang semua fragmen memperpanjang, kemudian tambahkan kode ini ke it's class, jika tidak membuat dasar seperti fragmen kelas
 /* 
 * called when on back pressed to the current fragment that is returned
 */
 public void onBackPressed()
 {
    // add code in super class when override
 }
  1. Dalam Aktivitas kelas, menimpa onBackPressed sebagai berikut:
private BaseFragment _currentFragment;

@Override
public void onBackPressed()
{
      super.onBackPressed();
     _currentFragment.onBackPressed();
}
  1. Dalam Fragmen kelas, tambahkan kode yang anda inginkan:
 @Override
 public void onBackPressed()
 {
    setUpTitle();
 }
Komentar (1)

onBackPressed() menyebabkan Fragmen yang akan melepaskan diri dari Aktivitas.

Menurut @Sterling Diaz menjawab saya pikir dia benar. TETAPI beberapa situasi akan menjadi salah. (ex. Memutar Layar)

Jadi, saya pikir kita bisa mendeteksi apakah isRemoving() untuk mencapai tujuan.

Anda dapat menulis di onDetach() atau onDestroyView(). Itu adalah pekerjaan.

@Override
public void onDetach() {
    super.onDetach();
    if(isRemoving()){
        // onBackPressed()
    }
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    if(isRemoving()){
        // onBackPressed()
    }
}
Komentar (0)

Anda harus menambahkan antarmuka untuk proyek anda seperti di bawah ini;

public interface OnBackPressed {

     void onBackPressed();
}

Dan kemudian, anda harus mengimplementasikan interface ini pada fragmen;

public class SampleFragment extends Fragment implements OnBackPressed {

    @Override
    public void onBackPressed() {
        //on Back Pressed
    }

}

Dan anda dapat memicu ini onBackPressed acara dalam kegiatan anda onBackPressed acara seperti di bawah ini;

public class MainActivity extends AppCompatActivity {
       @Override
        public void onBackPressed() {
                Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
                if (currentFragment instanceof OnBackPressed) {  
                    ((OnBackPressed) currentFragment).onBackPressed();
                }
                super.onBackPressed();
        }
}
Komentar (1)

Yah aku melakukan hal seperti ini, dan itu bekerja untuk saya

Antarmuka yang sederhana

FragmentOnBackClickInterface.java

public interface FragmentOnBackClickInterface {
    void onClick();
}

Contoh implementasi

MyFragment.java

public class MyFragment extends Fragment implements FragmentOnBackClickInterface {

// other stuff

public void onClick() {
       // what you want to call onBackPressed?
}

kemudian hanya menimpa onBackPressed dalam kegiatan

    @Override
public void onBackPressed() {
    int count = getSupportFragmentManager().getBackStackEntryCount();
    List frags = getSupportFragmentManager().getFragments();
    Fragment lastFrag = getLastNotNull(frags);
    //nothing else in back stack || nothing in back stack is instance of our interface
    if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
        super.onBackPressed();
    } else {
        ((FragmentOnBackClickInterface) lastFrag).onClick();
    }
}

private Fragment getLastNotNull(List list){
    for (int i= list.size()-1;i>=0;i--){
        Fragment frag = list.get(i);
        if (frag != null){
            return frag;
        }
    }
    return null;
}
Komentar (8)

Jika anda menggunakan EventBus, itu mungkin jauh lebih sederhana solusi :

Di Fragmen :

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    EventBus.getDefault().register(this);
}

@Override
public void onDetach() {
    super.onDetach();
    EventBus.getDefault().unregister(this);
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    getSupportFragmentManager().popBackStack();
}

dan di kelas Kegiatan anda anda dapat menentukan :

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    super.onBackPressed();
}

@Override
public void onBackPressed() {
    EventBus.getDefault().post(new BackPressedMessage(true));
}

BackPressedMessage.java hanya POJO objek

Ini adalah super bersih dan tidak ada antarmuka/implementasi kerumitan.

Komentar (0)

Ini hanya sedikit kode yang akan melakukan trik:

 getActivity().onBackPressed();

Berharap itu membantu seseorang :)

Komentar (2)

ini adalah solusi saya:

di MyActivity.java:

public interface OnBackClickListener {
        boolean onBackClick();
    }

    private OnBackClickListener onBackClickListener;

public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
        this.onBackClickListener = onBackClickListener;
    }

@Override
    public void onBackPressed() {
        if (onBackClickListener != null && onBackClickListener.onBackClick()) {
            return;
        }
        super.onBackPressed();
    }

dan di Fragmen:

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
    @Override
    public boolean onBackClick() {
        if (condition) {
            return false;
        }

        // some codes

        return true;
    }
});
Komentar (0)

Bagaimana menggunakan onDestroyView()?

@Override
public void onDestroyView() {
    super.onDestroyView();
}
Komentar (2)
public class MyActivity extends Activity {

    protected OnBackPressedListener onBackPressedListener;

    public interface OnBackPressedListener {
        void doBack();
    }

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    } 

    @Override
    protected void onDestroy() {
        onBackPressedListener = null;
        super.onDestroy();
    }
}

dalam fragmen tambahkan berikut, jangan lupa untuk menerapkan mainactivity's antarmuka.

public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
         ((MyActivity) getActivity()).setOnBackPressedListener(this);
    }

@Override
public void doBack() {
    //BackPressed in activity will call this;
}

}
Komentar (0)
@Override
public void onResume() {
    super.onResume();

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
                // handle back button
                replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);

                return true;
            }

            return false;
        }
    });
}
Komentar (1)

Sangat pendek dan manis menjawab:

getActivity().onBackPressed();

Penjelasan dari seluruh skenario dari kasus saya:

Saya telah FragmentA di MainActivity, Aku membuka FragmentB dari FragmentA (FragmentB adalah anak atau bersarang fragmen FragmentA)

 Fragment duedateFrag = new FragmentB();
 FragmentTransaction ft  = getFragmentManager().beginTransaction();
 ft.replace(R.id.container_body, duedateFrag);
 ft.addToBackStack(null);
 ft.commit();

Sekarang jika anda ingin pergi ke FragmentA dari FragmentB anda hanya dapat menempatkan getActivity().onBackPressed(); di FragmentB.

Komentar (4)

Hanya ikuti langkah-langkah berikut:

Selalu sambil menambahkan fragmen,

fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

Kemudian dalam kegiatan utama, menimpa onBackPressed()

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    getSupportFragmentManager().popBackStack();
} else {
    finish();
}

Untuk menangani tombol kembali di aplikasi anda,

Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
    if (f != null) 
        getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()               
}

Yang's itu!

Komentar (0)