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?
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();
}
}
Aku hal terbaik solusi
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;
}
}
}
interface IOnBackPressed {
fun onBackPressed(): Boolean
}
class MyActivity : AppCompatActivity() {
override fun onBackPressed() {
val fragment =
this.supportFragmentManager.findFragmentById(R.id.main_container)
(fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
super.onBackPressed()
}
}
}
class MyFragment : Fragment(), IOnBackPressed {
override fun onBackPressed(): Boolean {
return if (myCondition) {
//action not popBackStack
true
} else {
false
}
}
}
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
OnBackPressedListener
antarmuka publik OnBackPressedListener { public void doBack(); }
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); } }
BaseActivity
dan fragmenBaseActivity
dilindungi OnBackPressedListener onBackPressedListener;
BaseActivity
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) { ini.onBackPressedListener = onBackPressedListener; }
onBackPressed
melaksanakan sesuatu seperti itu@Override public void onBackPressed() { jika (onBackPressedListener != null) onBackPressedListener.doBack(); lain super.onBackPressed();
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.
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;
}
});
}
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.
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.
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.
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.
Solusinya sederhana:
/*
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
// add code in super class when override
}
private BaseFragment _currentFragment;
@Override
public void onBackPressed()
{
super.onBackPressed();
_currentFragment.onBackPressed();
}
@Override
public void onBackPressed()
{
setUpTitle();
}
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()
}
}
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();
}
}
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<Fragment> 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<Fragment> list){
for (int i= list.size()-1;i>=0;i--){
Fragment frag = list.get(i);
if (frag != null){
return frag;
}
}
return null;
}
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.
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;
}
});
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;
}
}
@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;
}
});
}
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.
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!