Fragmen onResume () & onPause () tidak dipanggil di backstack


195

Saya memiliki beberapa fragmen di dalam suatu aktivitas. Pada sebuah tombol klik saya memulai sebuah fragmen baru, menambahkannya ke backstack. Saya secara alami mengharapkan onPause()metode Fragmen saat ini dan onResume()Fragmen baru untuk dipanggil. Yah itu tidak terjadi.

LoginFragment.java

public class LoginFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
      final FragmentManager mFragmentmanager =  getFragmentManager();

      Button btnHome  = (Button)view.findViewById(R.id.home_btn);
      btnHome.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view){
           HomeFragment fragment    = new HomeFragment();
           FragmentTransaction ft2   =  mFragmentmanager.beginTransaction();
           ft2.setCustomAnimations(R.anim.slide_right, R.anim.slide_out_left
                    , R.anim.slide_left, R.anim.slide_out_right);
           ft2.replace(R.id.middle_fragment, fragment);
           ft2.addToBackStack(""); 
           ft2.commit();    
         }
      });
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of LoginFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
    Log.e("DEBUG", "OnPause of loginFragment");
    super.onPause();
  }
}

HomeFragment.java

public class HomeFragment extends Fragment{
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     final View view  =   inflater.inflate(R.layout.login_fragment, container, false);
  }

  @Override
  public void onResume() {
     Log.e("DEBUG", "onResume of HomeFragment");
     super.onResume();
  }

  @Override
  public void onPause() {
     Log.e("DEBUG", "OnPause of HomeFragment");
     super.onPause();
  }
}

Apa yang saya harapkan, adalah,

  1. Ketika diklik, LoginFragment akan diganti dengan HomeFragment , onPause()dari LoginFragment , dan onResume()dari HomeFragment dipanggil
  2. Ketika kembali ditekan, HomeFragment adalah poped keluar dan LoginFragment terlihat, dan onPause()dari HomeFragment dan onResume()dari LoginFragment dipanggil.

Apa yang saya dapatkan adalah,

  1. Ketika tombol diklik, HomeFragment dengan benar mengganti LoginFragment , onResume () dari HomeFragment dipanggil, tetapi onPause () dari LoginFragment tidak pernah dipanggil.
  2. Saat ditekan kembali, HomeFragment muncul dengan benar untuk menampilkan LoginFragment , onPause () dari HomeFragment dipanggil, tetapi onResume () dari LoginFragment tidak pernah dipanggil.

Apakah ini perilaku normal? Mengapa onResume()dari LoginFragment tidak mendapatkan disebut ketika saya menekan tombol kembali.


Tambahkan kode aktivitas yang menangani fragmen.
blessenm

Saya mengalami masalah sampel, pada jeda tidak dipanggil, bagaimana Anda menyelesaikan ini,
Sam

Saya memiliki masalah yang sama tetapi menyadari bahwa saya menggunakan ft2.add (); bukannya ft2.replace (). Hanya alasan lain yang akan terjadi jika aktivitas Anda menyimpan referensi ke fragmen (menambahkannya ke koleksi, atau menugaskannya ke variabel kelas)
Friggles

3
Saya mengalami masalah yang sama. Saya perhatikan bahwa .replace () akan memanggil metode siklus hidup yang diperlukan, tetapi pada dasarnya menghancurkan fragmen. Juga, onSaveInstanceState tidak dipanggil. Karena itu, saya tidak dapat mempertahankan kondisinya. Jadi, saya perlu menggunakan add, tetapi onResume / Pause tidak disebut :(
ariets

FWIW, pengalaman saya adalah bahwa fragmen pustaka dukungan memang memanggil onPause dan onResume ketika mendorong / muncul backstack, tetapi fragmen bawaan Android tidak. Belum menemukan solusi yang tepat untuk itu.
benkc

Jawaban:


185

Fragmen onResume()atau onPause()akan dipanggil hanya ketika Kegiatan onResume()atau onPause()dipanggil. Mereka sangat erat dengan Activity.

Membaca Menangani Siklus Hidup Bagian dari artikel ini .


1
Dalam artikel tersebut, dikatakan bahwa "setelah aktivitas mencapai keadaan dilanjutkan, Anda dapat dengan bebas menambah dan menghapus fragmen ke aktivitas. Dengan demikian, hanya saat aktivitas dalam keadaan kembali dapat siklus hidup fragmen berubah secara mandiri." Apakah ini berarti bahwa fragmen padaResume dapat dipanggil bahkan jika aktivitas padaResume tidak disebut?
v4r

3
seperti untuk fragmen asli (tidak mendukung) di 4.4 (tidak yakin apakah itu benar untuk versi yang lebih lama) onPause () dan onResume () dipanggil tidak hanya ketika peristiwa ini terjadi dalam aktivitas, tetapi misalnya ketika Anda menelepon ganti () atau tambahkan () / hapus () saat melakukan transaksi, jadi jawaban ini menyesatkan setidaknya untuk versi Android terbaru.
Dmide

19
Menurut dokumen itu, fragmen itu seharusnya benar-benar dipindahkan ke status berhenti ketika ditukar ke backstack. Tetapi tidak hanya onPause dan onResume tidak dipanggil, tidak juga onStop dan onStart - atau dalam hal ini, metode siklus hidup lainnya. Jadi panduan ini jelas menyesatkan.
benkc

1
Meskipun tidak berhubungan tetapi saya menemukan pertanyaan ini ketika mencari masalah saya onPause()dipanggil setelah onSaveInstanceState()daripada sebelumnya. Ini dapat direproduksi jika Anda ke anak yang berbeda di saya FragmentStatePagerAdapter(katakanlah Anda pindah dari anak 0 ke anak 2, perhatikan untuk diri sendiri, ini terjadi karena anak 0 dihancurkan ketika anak 2 dibuka )
Sufian

Tidak yakin apa yang kamu maksud. Memanggil ft.replace harus memicu onPause (dari fragmen yang diganti) dan onResume (dari fragmen yang diganti). Ini dilakukan terlepas dari aktivitas apa pun ...
David Refaeli

20
  • Karena Anda telah menggunakan ft2.replace(), FragmentTransaction.remove() metode dipanggil dan Loginfragmentakan dihapus. Lihat ini . Jadi onStop()dari LoginFragmentakan disebut bukan onPause(). (Karena fragmen baru sepenuhnya menggantikan yang lama).
  • Tapi karena Anda juga telah menggunakan ft2.addtobackstack(), keadaan Loginfragmentakan disimpan sebagai bundel dan ketika Anda mengklik tombol kembali dari HomeFragment, onViewStateRestored()akan disebut diikuti oleh onStart()dari LoginFragment. Jadi akhirnya onResume()tidak akan dipanggil.

1
onViewStateRestoreddipanggil jika Anda memilikisetRetainInstance(true)
Farid

14

Inilah jawaban Gor versi saya yang lebih kuat (menggunakan fragmen.size () tidak dapat diandalkan karena ukuran tidak dikurangi setelah fragmen muncul)

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            if (getFragmentManager() != null) {

                Fragment topFrag = NavigationHelper.getCurrentTopFragment(getFragmentManager());

                if (topFrag != null) {
                    if (topFrag instanceof YourFragment) {
                        //This fragment is being shown. 
                    } else {
                        //Navigating away from this fragment. 
                    }
                }
            }
        }
    });

Dan metode 'getCurrentTopFragment':

public static Fragment getCurrentTopFragment(FragmentManager fm) {
    int stackCount = fm.getBackStackEntryCount();

    if (stackCount > 0) {
        FragmentManager.BackStackEntry backEntry = fm.getBackStackEntryAt(stackCount-1);
        return  fm.findFragmentByTag(backEntry.getName());
    } else {
        List<Fragment> fragments = fm.getFragments();
        if (fragments != null && fragments.size()>0) {
            for (Fragment f: fragments) {
                if (f != null && !f.isHidden()) {
                    return f;
                }
            }
        }
    }
    return null;
}

9

Jika Anda benar-benar ingin mengganti fragmen di dalam fragmen lain, Anda harus menggunakan Nested Fragmen .

Dalam kode Anda, Anda harus mengganti

final FragmentManager mFragmentmanager =  getFragmentManager();

dengan

final FragmentManager mFragmentmanager =  getChildFragmentManager();

5
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> fragments = getFragmentManager().getFragments();
            if (fragments.size() > 0 && fragments.get(fragments.size() - 1) instanceof YoureFragment){
                //todo if fragment visible
            } else {
                //todo if fragment invisible
            }

        }
    });

tapi hati-hati jika lebih dari satu fragmen terlihat


Terima kasih, ini berfungsi, tetapi jika hanya satu fragmen yang terlihat (jadi, ViewPagerdengan fragmen akan merujuk pada fragmennya)
CoolMind

3

Saya memiliki kode yang sangat mirip dengan Anda dan jika berfungsi onPause () dan onResume (). Saat mengubah fragmen, fungsi-fungsi ini diaktifkan masing-masing.

Kode dalam fragmen:

 @Override
public void onResume() {
    super.onResume();
    sensorManager.registerListener(this, proximidad, SensorManager.SENSOR_DELAY_NORMAL);
    sensorManager.registerListener(this, brillo, SensorManager.SENSOR_DELAY_NORMAL);
    Log.e("Frontales","resume");
}

@Override
public void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
    Log.e("Frontales","Pause");

}

Log ketika perubahan fragmen:

05-19 22:28:54.284 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:28:57.002 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:28:58.697 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:00.840 2371-2371/madi.cajaherramientas E/Frontales: Pause
05-19 22:29:02.248 2371-2371/madi.cajaherramientas E/Frontales: resume
05-19 22:29:03.718 2371-2371/madi.cajaherramientas E/Frontales: Pause

Fragmen onCreateView:

View rootView;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.activity_proximidad, container, false);
    ButterKnife.bind(this,rootView);
    inflar();
    setTextos();
    return rootView;
}

Tindakan saat saya membalas pulsa (dalam aktivitas tempat saya memuat fragmen):

@Override
public void onBackPressed() {

    int count = getFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();

    } else {
        getFragmentManager().popBackStack();
    }

 }

2

Apa yang saya lakukan dalam fragmen anak:

@Override
public void onDetach() {
   super.onDetach();
   ParentFragment pf = (ParentFragment) this.getParentFragment();
   pf.onResume();
}

Dan kemudian menimpa onResume di ParentFragment


1
Anda seharusnya tidak pernah memanggil metode siklus hidup secara manual, terutama di dalam satu sama lain
breakline

@ garis teknik ini bekerja. Apakah Anda punya cara lain?
Vikash Parajuli

Ya, Anda harus menambahkan implementasi Anda sendiri untuk memanggil karena metode siklus hidup juga dipanggil oleh sistem dan jika Anda memanggil metode siklus hidup di dalam satu sama lain seperti ini Anda mungkin (dan kemungkinan besar akan) menyebabkan masalah kemudian.
breakline

1

Anda tidak dapat menambahkan fragmen ke fragmen. Ini perlu terjadi di FragmentActivity. Saya berasumsi Anda sedang membuat LoginFragment di FragmentActivity, jadi untuk membuatnya bekerja, Anda perlu menambahkan HomeFragment melalui FragmentActivity ketika login ditutup.

Poin umum adalah bahwa Anda memerlukan kelas FragmentActivity dari mana Anda menambahkan setiap Fragment ke FragmentManager. Tidak mungkin melakukan ini di dalam kelas Fragmen.


Ya mereka berada di dalam aktivitas fragmen.
Krishnabhadra

jika fragmen ditambahkan secara dinamis maka Anda dapat menambahkan fragmen sebanyak yang Anda inginkan ke fragmen tetapi tidak ke fragmen yang didefinisikan dalam tag <ml fragmen> xml
Argumen Ilegal

1

Jika Anda menambahkan fragmen dalam XML, Anda tidak dapat menukarnya secara dinamis. Apa yang terjadi adalah mereka terlalu berlebihan, sehingga peristiwa-peristiwa tidak terjadi seperti yang diharapkan. Masalahnya didokumentasikan dalam pertanyaan ini. Ganti FragmenManager membuat overlay

Ubah middle_fragment menjadi FrameLayout, dan muat seperti di bawah ini dan acara Anda akan diaktifkan.

getFragmentManager().beginTransation().
    add(R.id.middle_fragment, new MiddleFragment()).commit();

1

Anda dapat mencoba ini,

Langkah1: Ganti metode yang Dipilih pada aktivitas Anda

@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    // When the given tab is selected, switch to the corresponding page in
    // the ViewPager.
    try {
    if(MyEventsFragment!=null && tab.getPosition()==3)
    {
        MyEvents.fragmentChanged();
    }
    }
    catch (Exception e)
    {

    }
    mViewPager.setCurrentItem(tab.getPosition());
}

Langkah 2: Menggunakan metode statis lakukan apa yang Anda inginkan dalam fragmen Anda,

public static void fragmentChanged()
{
    Toast.makeText(actvity, "Fragment Changed", Toast.LENGTH_SHORT).show();
}

1

Saya gunakan dalam aktivitas saya - KOTLIN

supportFragmentManager.addOnBackStackChangedListener {
                val f = supportFragmentManager.findFragmentById(R.id.fragment_container)

                if (f?.tag == "MyFragment")
                {
                    //doSomething
                }
            }

0

Sebuah fragmen harus selalu tertanam dalam suatu aktivitas dan siklus hidup fragmen secara langsung dipengaruhi oleh siklus hidup aktivitas host. Misalnya, ketika aktivitas dijeda, begitu juga semua fragmen di dalamnya, dan ketika aktivitas dihancurkan, begitu juga semua fragmen


0

onPause() Metode bekerja di kelas aktivitas yang dapat Anda gunakan:

public void onDestroyView(){
super.onDestroyView    
}

untuk tujuan yang sama ..


0

Ikuti langkah-langkah di bawah ini, dan Anda akan mendapatkan jawaban yang dibutuhkan

1- Untuk kedua fragmen, buat induk abstrak baru.
2- Tambahkan metode abstrak kustom yang harus diimplementasikan oleh keduanya.
3- Sebut saja dari instance saat ini sebelum mengganti dengan yang kedua.


Bagaimana cara membantu dalam situasi ketika pengguna kembali dari fragmen 2 ke fragmen 1?
CoolMind

0

Berdasarkan jawaban @Gor saya menulis serupa di Kotlin. Tempatkan kode ini dalam onCreate()suatu kegiatan. Ini berfungsi untuk satu fragmen yang terlihat. Jika Anda memiliki ViewPagerdengan fragmen, itu akan memanggil ViewPagerfragmen, bukan yang sebelumnya.

supportFragmentManager.addOnBackStackChangedListener {
    supportFragmentManager.fragments.lastOrNull()?.onResume()
}

Setelah membaca https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6 Saya mengerti bahwa akan lebih baik dalam banyak situasi untuk melampirkan fragmen baru dengan replace, bukan add. Jadi kebutuhan onResumedalam beberapa kasus akan hilang.


0

Panggilan ft.replace harus memicu onPause (dari fragmen yang diganti) dan onResume (dari fragmen yang diganti).

Saya perhatikan bahwa kode Anda mengembang login_fragmentpada fragmen rumah, dan juga tidak mengembalikan tampilan di onCreateView. Jika ini salah ketik, dapatkah Anda menunjukkan bagaimana fragmen-fragmen ini dipanggil dari dalam aktivitas Anda?


Ini bukan jawaban, bagaimana jika "menambahkan" adalah keharusan untuk desain seseorang ?!
Farid

0

Meskipun dengan kode yang berbeda, saya mengalami masalah yang sama dengan OP, karena saya awalnya menggunakan

fm.beginTransaction()
            .add(R.id.fragment_container_main, fragment)
            .addToBackStack(null)
            .commit();

dari pada

fm.beginTransaction()
                .replace(R.id.fragment_container_main, fragment)
                .addToBackStack(null)
                .commit();

Dengan "ganti" fragmen pertama akan diciptakan kembali ketika Anda kembali dari fragmen kedua dan karenanya onResume () juga disebut.


Ini bukan jawaban, bagaimana jika "menambahkan" adalah keharusan untuk desain seseorang ?!
Farid

-2

Saat membuat transaksi fragmen, pastikan untuk menambahkan kode berikut.

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

Pastikan juga, untuk melakukan transaksi setelah menambahkannya ke backstack

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.