Fragman onResume () & onPause () backstack üzerinde çağrılmıyor


196

Bir aktivitenin içinde birden fazla parçam var. Bir butona tıkladığımda yeni bir parça başlatıyorum. Doğal olarak onPause()mevcut Fragman ve onResume()yeni Fragment yöntemlerinin çağrılmasını bekliyordum. Peki bu gerçekleşmiyor.

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

Beklediğim,

  1. Düğmesine tıklandığında, LoginFragment ile değiştirilir alır HomeFragment , onPause()bir LoginFragment ve onResume()içinde HomeFragment çağrılan
  2. Geri basıldığında, HomeFragment dışarı poped ve LoginFragment ve görülür onPause()bir HomeFragment ve onResume()bir LoginFragment çağrılır.

Ne alıyorum,

  1. Düğmesine tıklandığında, HomeFragment doğru yerini alan LoginFragment , onResume () ait HomeFragment denir, ama OnPause () ait LoginFragment asla denir.
  2. Geri basıldığında HomeFragment doğru ortaya çıkarmak için haşhaş LoginFragment , OnPause () ait HomeFragment çağrılan, ancak onResume () ait LoginFragment asla çağrılır.

Bu normal bir davranış mı? Neden onResume()ait LoginFragment geri düğmesine bastığınızda denilen almıyorum.


Parçaları işleyen etkinlik kodunu ekleyin.
blessenm

Ben örnek sorunu yaşıyorum, duraklama çağrılmadı, bunu nasıl
Sam

Aynı sorunu vardı ama ft2.add () kullanarak fark etti; ft2.replace () yerine. Yalnızca başka bir neden, etkinliğiniz parçanın referansını tutması (bir koleksiyona eklenmesi veya bir sınıf değişkenine ataması) olabilir
Friggles

3
Aynı sorunu yaşıyorum. .Replace () yönteminin gerekli yaşam döngüsü yöntemlerini çağıracağını fark ettim, ama aslında parçayı yok ediyor. Ayrıca onSaveInstanceState edilir değil denir. Bu yüzden durumunu koruyamam. Yani, add kullanmam gerekiyor, ancak onResume / Pause çağrılmıyor :(
ariets

FWIW, deneyimlerim, destek kütüphanesi parçalarının backstack'i iterken / patlatırken onPause ve onResume'u çağırması, ancak Android yerleşik parçalarının bunu yapmamasıdır. Bunun için henüz uygun bir çözüm bulamadık.
benkc

Yanıtlar:


187

Parçalar onResume()ya onPause()da sadece Etkinlikler onResume()ya onPause()da çağrıldığında çağırılacaktır. Onlar sıkıca bağlı Activity.

Bu makalenin Parça Yaşam Döngüsünün Kullanılması bölümünü okuyun .


1
Makalede, "etkinlik devam ettirilen duruma ulaştığında, etkinliğe parçalar serbestçe ekleyebilir ve çıkarabilirsiniz. Bu nedenle, yalnızca etkinlik devam ettiği sırada bir parçanın yaşam döngüsü bağımsız olarak değişebilir." Bu, onResume üzerindeki aktivite çağrılmasa bile onResume parçasının çağrılabileceği anlamına mı geliyor?
v4r

3
4.4'teki yerel (desteklemeyen) fragmanlarda olduğu gibi (eski sürümler için doğru olup olmadığından emin değilim) onPause () ve onResume () yalnızca etkinlikte bu olaylar gerçekleştiğinde değil, örneğin replace () veya () / remove () işlemini gerçekleştirirken, bu yanıt en azından Android'in son sürümleri için yanıltıcıdır.
Dmide

19
Bu belgeye göre, parça backstack'e geçtiğinde aslında durmuş duruma taşınmalıdır. Ama sadece onPause ve onResume çağrılmıyor, ne onStop hem de onStart da değil - ya da başka bir yaşam döngüsü yöntemi. Bu yüzden rehber kesinlikle yanıltıcı.
benkc

1
Her ne kadar ilgili olmasa da, onPause()daha onSaveInstanceState()önce değil sonra çağrılma sorunumu ararken bu soruyu buldum . Bu farklı bir çocuğa eğer yeniden olabilir benim FragmentStatePagerAdapter(eğer çocuğun 2'ye çocuğa 0 hareket demek çocuk 0 tahrip olduğu için çocuk 2 açtığında Böyle kendime not )
Sufian

Ne demek istediğinden emin değilim. Ft.replace çağrıldığında onPause (değiştirilen parçanın) ve onResume (değiştirilen parçanın) tetiklenmelidir. Bu, herhangi bir faaliyetten bağımsız olarak yapılır ...
David Refaeli

20
  • Eğer kullanmış yana ft2.replace(), FragmentTransaction.remove() yöntemi denir ve Loginfragmentkaldırılacaktır. Bakın bu . Yani onStop()bir LoginFragmentyerine çağrılacak onPause(). (Yeni parça eskisinin yerini alır).
  • Ayrıca kullanmış beri Ama ft2.addtobackstack(), devlet Loginfragmentbir paket olarak kaydedilir ve ne zaman dan geri düğmesine basın HomeFragment, onViewStateRestored()ardından adı verilecek onStart()ait LoginFragment. Yani sonunda onResume()çağrılmayacak.

1
onViewStateRestoredvarsa denirsetRetainInstance(true)
Farid

14

İşte Gor'un cevabının daha sağlam versiyonu

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

Ve 'getCurrentTopFragment' yöntemi:

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

Eğer parçayı gerçekten diğer parçanın içinde değiştirmek istiyorsanız, Yuvalanmış Parçalar'ı kullanmalısınız .

Kodunuzda değiştirmelisiniz

final FragmentManager mFragmentmanager =  getFragmentManager();

ile

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
            }

        }
    });

ancak birden fazla parça görünüyorsa dikkatli olun


Teşekkürler, işe yarıyor, ama sadece bir parça görünürse (yani, ViewPagerparçaları ile parçalarına atıfta bulunacak).
CoolMind

3

Ben seninkine çok benzer bir kod var ve onPause () ve onResume () çalışırsa. Parçayı değiştirirken, bu fonksiyonlar sırasıyla etkinleştirilir.

Parçadaki kod:

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

}

Parça değişiminde günlüğe kaydet:

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

Oluşturma Parçasında Parça:

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

Geri attığımda eylem (parçayı yüklediğim aktivitede):

@Override
public void onBackPressed() {

    int count = getFragmentManager().getBackStackEntryCount();

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

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

 }

2

Çocuk parçasında ne yapıyorum:

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

Ve sonra ParentFragment üzerinde onResume'u geçersiz kıl


1
Yaşam

@breakline bu teknik işe yarıyor. Başka yolun var mı?
Vikash Parajuli

Evet, çağrı yapmak için kendi uygulamanızı eklemelisiniz çünkü yaşam döngüsü yöntemleri sistem tarafından da çağrılır ve yaşam döngüsü yöntemlerini bu şekilde çağırırsanız daha sonra sorunlara neden olabilirsiniz (ve büyük olasılıkla).
breakline

1

You basit olamaz bir fragmanına bir parçasını ekleyin. Bunun FragmentActivity'de olması gerekir. LoginFragment'ı bir FragmentActivity'de oluşturduğunuzu varsayıyorum, bu nedenle bu çalışmayı elde etmek için giriş kapatıldığında FragmentActivity aracılığıyla HomeFragment'ı eklemeniz gerekiyor.

Genel nokta, her bir Fragment'ı FragmentManager'a eklediğiniz yerden bir FragmentActivity sınıfına ihtiyacınız olmasıdır. Bunu bir Fragment sınıfında yapmak mümkün değildir .


Evet, bir parça faaliyetin içindeler.
Krishnabhadra

fragmanlar dinamik olarak eklendiyse, bir fragmana istediğiniz kadar fragman ekleyebilirsiniz, ancak xml <fragment> etiketinde tanımlananlara değil
Geçersiz Yasa Argümanı

1

Parçayı XML olarak eklerseniz, dinamik olarak değiştiremezsiniz. Olan şey, aşırı bir şey oldukları için olaylar beklendiği gibi tetiklenmez. Sorun bu soruda belgelenmiştir. FragmenManager yerine yer paylaşımı yapar

Middle_fragment öğesini bir FrameLayout'a dönüştürün ve aşağıdaki gibi yükleyin; etkinlikleriniz tetiklenir.

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

1

Bunu deneyebilirsin,

Adım 1: Etkinliğinizdeki Tabselected yöntemini geçersiz kılın

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

Adım 2: Statik yöntemi kullanarak parçanızda istediğinizi yapın,

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

1

@Gor'un cevabına dayanarak Kotlin'de benzer yazdım. Bu kodu onCreate()bir etkinliğe yerleştirin. Görünür bir parça için çalışır. Eğer parçalarınız varsa, bir önceki parçayı değil ViewPager, onun parçasını çağırır ViewPager.

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

Okuduktan sonra https://medium.com/@elye.project/puzzle-fragment-stack-pop-cause-issue-on-toolbar-8b947c5c07c6 Ben yeni parçalarını tutturmak için birçok durumda daha iyi olacağını anladım replace, değil add. Yani onResumebazı durumlarda bir ihtiyaç ortadan kalkacaktır.


1

Etkinliğimde kullanıyorum - KOTLIN

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

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

0

Bir parça her zaman bir etkinliğe gömülmelidir ve parçanın yaşam döngüsü, ana bilgisayar etkinliğinin yaşam döngüsünden doğrudan etkilenir. Örneğin, etkinlik duraklatıldığında, içindeki tüm parçalar da ve etkinlik yok edildiğinde, tüm parçalar da


0

onPause() yöntem, kullanabileceğiniz etkinlik sınıfında çalışır:

public void onDestroyView(){
super.onDestroyView    
}

aynı amaç için ..


0

Aşağıdaki adımları izleyin ve gerekli cevabı alacaksınız

1- Her iki parça için de yeni bir soyut ebeveyn oluşturun.
2- Her ikisi tarafından uygulanması gereken özel bir soyut yöntem ekleyin.
3- İkincisiyle değiştirmeden önce mevcut örnekten çağırın.


Bir kullanıcı parça 2'den parça 1'e döndüğünde bu nasıl yardımcı olur?
CoolMind

0

çağrı ft.replace onPause (değiştirilen parçanın) ve onResume (değiştirilen parçanın) tetiklemelidir.

Kodunuzun login_fragmentev parçası üzerinde şiştiğini ve ayrıca onCreateView görünümlerini döndürmüyor dikkat edin. Bunlar yazım hatalarıysa, bu parçaların etkinliğiniz içinden nasıl çağrıldığını gösterebilir misiniz?


Bu bir cevap değil, ya birisinin tasarımı için "add" şart ise ?!
Farid

0

Farklı kodlara rağmen, OP ile aynı sorunu yaşadım, çünkü başlangıçta kullandım

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

onun yerine

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

"Değiştir" ile, ikinci parçadan döndüğünüzde ilk parça yeniden oluşturulur ve bu nedenle onResume () de çağrılır.


Bu bir cevap değil, ya birisinin tasarımı için "add" şart ise ?!
Farid

-2

Bir parça işlemi oluştururken aşağıdaki kodu eklediğinizden emin olun.

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

Ayrıca, işlemi backstack'e ekledikten sonra gerçekleştirdiğinizden emin olun

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.