Arka yığına eklendiğinde parça durumunu nasıl koruyabilirim?


160

İki parça arasında geçiş yapan sahte bir etkinlik yazdım. FragmentA'dan FragmentB'ye gittiğinizde, FragmentA arka yığına eklenir. Ancak, (geri basarak) FragmentA döndüğümde, tamamen yeni bir FragmentA oluşturulur ve içinde bulunduğu durum kaybolur. Bu soru ile aynı şey peşinde olduğumu hissediyorum olsun , ama sorunu kökten yardımcı olmak için tam bir kod örneği dahil ettik:

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

Bazı günlük mesajları eklendiğinde:

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

Asla FragmentA.onSaveInstanceState öğesini çağırmaz ve geri döndüğünüzde yeni bir FragmentA oluşturur. Ancak, eğer FragmentA üzerindeysem ve ekranı kilitlersem, FragmentA.onSaveInstanceState çağrılır. Çok garip ... Arka yığını eklenen bir parçanın yeniden yaratılmasını beklemiyor muyum? İşte ne dokümanlar ki:

Oysa, bir parçayı kaldırırken addToBackStack () öğesini çağırırsanız, parça durdurulur ve kullanıcı geri giderse devam ettirilir.


3
@ Jan-Henk Getirilmesi gerekenler ne olacak? Örneğin, a ListView. Bir kaydırma dinleyicisi eklemek ve bir örnek değişkenini güncellemek için çok fazla çember atlama gibi görünüyor.
Jake Wharton

2
@JakeWharton Daha kolay olması gerektiğine katılıyorum, ancak bildiğim kadarıyla bunun etrafında bir yol yok çünkü geri parçadan bir parça geri yüklendiğinde onCreateView çağrılıyor. Ama yanılmış olabilirim :)
Jan-Henk

1
onCreate çağrılmaz. Görünüşe göre aynı örneği yeniden kullanıyor ama onCreateView'ı tekrar mı çağırıyor? Topal. Sanırım sadece onCreateView sonucunu önbelleğe alabilir ve onCreateView tekrar çağrılırsa mevcut görünümü döndürebilirim.
Eric

1
Tam olarak saatlerce aradığım şey. Bunu nasıl başardığınızı örnek değişkeni kullanarak gönderebilir misiniz?
Uma

1
Son zamanlarda github.com/frostymarvelous/Folio'da kendi uygulamama başladım ve bir sorunla karşılaştım. OOM çökmelerine başlamadan önce yaklaşık 5 karmaşık Sayfa / Parça oluşturabiliyorum. Beni buraya getiren de buydu. Gizlemek ve Göstermek yeterli değildir. Görüntülemeler çok ağır.
16:50

Yanıtlar:


120

Arka yığından bir parçaya geri dönerseniz, parçayı yeniden oluşturmaz ancak aynı örneği yeniden kullanır ve onCreateView()parça yaşam döngüsüyle başlar , bkz. Parça yaşam döngüsü .

Eğer mağaza durumuna istiyorsanız Yani örnek değişkenler kullanmak ve gerektiği değil güvenmek onSaveInstanceState().


32
Belgelerin mevcut sürümü bu iddia ile çelişmektedir. Akış şeması ne belirttiğinizi söylüyor, ancak sayfanın ana alanındaki metinde onCreateView () ifadesi yalnızca Parça ilk görüntülendiğinde çağrılıyor diyor : developer.android.com/guide/components/fragments.html Bununla savaşıyorum Şimdi sorun ve ben backtack bir parça döndürürken denilen herhangi bir yöntem görmüyorum. (Android 4.2)
Colin M.

10
Davranışını kaydetmeye çalıştı. Parça görüntülenirken her zaman onCreateView () yöntemi çağrılır.
princepiero

4
@ColinM. Soruna çözüm var mı?
blizzard

9
Bu benim için işe yaramıyor. Örnek değişkenlerim, parçaya dönüşte boş! Devleti nasıl kurtarabilirim?
Don Rhummy

5
öyleyse, kaydetme örneğine geçmemeliysek, parça durumunu ve verilerini nasıl kaydetmeliyiz?
Mehdi

80

Apple UINavigationControllerve UIViewControllerGoogle ile karşılaştırıldığında , Android yazılım mimarisinde iyi performans göstermez. Ve Android'in dokümanı Fragmentpek yardımcı olmuyor.

FragmentB'den FragmentB'ye girdiğinizde, varolan FragmentA örneği yok olmaz. FragmentB'de Back tuşuna basıp FragmentA öğesine döndüğünüzde, yeni bir FragmentA örneği oluşturmayız. Mevcut FragmentA örneği onCreateView()çağrılacaktır.

Önemli olan, görünümü FragmentA'larda tekrar şişirmememiz gerektiğidir onCreateView(), çünkü mevcut FragmentA örneğini kullanıyoruz. RootView'i kaydetmeli ve tekrar kullanmalıyız.

Aşağıdaki kod iyi çalışıyor. Sadece parça durumunu korumakla kalmaz, aynı zamanda RAM ve CPU yükünü de azaltır (çünkü düzeni yalnızca gerekirse şişiririz). Google'ın örnek kodunun ve dokümanının bundan hiç bahsetmediğini ancak düzeni her zaman şişirdiğini düşünemiyorum .

Sürüm 1 (Sürüm 1'i kullanma) Sürüm 2'yi kullanın)

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // (it will be added back).
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        return _rootView;
    }
}

------ 3 Mayıs 2005 Güncellemesi: -------

Bahsedildiği gibi, bazen _rootView.getParent()null onCreateView, bu da çökmeye neden olur. Sürüm 2, dell116'nın önerdiği gibi onDestroyView () öğesinde _rootView öğesini kaldırır. Android 4.0.3, 4.4.4, 5.1.0'da test edildi.

Versiyon 2

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // in onDestroyView() (it will be added back).
        }
        return _rootView;
    }

    @Override
    public void onDestroyView() {
        if (_rootView.getParent() != null) {
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        super.onDestroyView();
    }
}

UYARI!!!

Bu bir HACK! Uygulamamda kullanmama rağmen, yorumları test etmeniz ve dikkatlice okumalısınız.


38
Tüm parçanın kök görünümüne referans vermek kötü bir fikir IMO'sudur. Bir backstack'e sürekli olarak birkaç parça ekliyorsanız ve bunların hepsi kök görünümünü (oldukça büyük bir bellek ayak izine sahip) tutuyorsa, tüm parçaların rootview referansı ve GC cant tuttuğu için OutOfMemoryError ile sonuçlanma olasılığınız yüksektir. topla. Bence daha iyi bir yaklaşım her zaman görünümü şişirmek (ve izin Android sistemi görünümü oluşturma / imha işlemek) ve onActivityCreated / onViewCreated verilerinizin boş olup olmadığını kontrol etmektir. Evetse, yükleyin, aksi takdirde verileri görünümlere ayarlayın.
traninho

15
Bunu yapma! Parçanın görünüm hiyerarşisi oluşturulduğunda, parçayı o sırada tutan Etkinliğe dahili bir referans içerir. Bir yapılandırma değişikliği meydana geldiğinde, Etkinlik genellikle yeniden oluşturulur. Eski düzeni yeniden kullanmak, o zombi etkinliğini referans aldığı nesnelerle birlikte bellekte tutar. Bunun gibi bellek israfı performansı engeller ve uygulamanızı ön planda olmadığında anında fesih için en iyi aday yapar.
Krylez

4
@AllDayAmazing Bu iyi bir nokta. Dürüst olmak gerekirse, şu anda çok kafam karıştı. Herhangi bir parçanın rootview referansını tutmak neden iyi değil ama sadece rootview herhangi bir çocuk için (yine de rootview referansı vardır) bir referans tutmak tamam açıklamaya çalışabilir miyim?
traninho

2
Kodunuzu neyin hata olduğunu bulmak için 5 saat boşa harcamak istemiyorsanız sürece bu yerden uzak dur ..... sonra sadece bunun sebebi olduğunu bulmak için. Şimdi bir sürü şeyi yeniden gözden geçirmem gerekiyor çünkü bu hack'i kullandım. Parçanın kullanıcı arayüzünü (üstte bile olsa) görünür hale getirirken parçanın UI'sını temas halinde tutmak istiyorsanız fragmentTransaction.add'yi kullanmak çok daha iyidir. fragmentTransaction.replace (), parçanın görüşlerini yok etmek içindir ... sistemle savaşmayın.
dell116

2
@VinceYuan - Android 5.1'deki en son v7-appcompat kütüphanesi ile test ettim ve bu, etkinliğimin FragmentManager'ında kaldırılması gereken bir parçanın 6 örneğini bıraktı. GC doğru bir şekilde işleyecek olsa bile (ki inanmayacağım) bu hem uygulamanız hem de genel olarak cihaz için gereksiz yere zorlanmaya neden oluyor. Basitçe .add () kullanmak, tüm bu hileli kod gereksinimini tamamen ortadan kaldırır. Bunu yapmak, FragmentTransaction.replace () yöntemini kullanmanın ilk etapta yapılması gerekenlere tamamen aykırıdır.
dell116

53

Aradığınızı başarmanın alternatif bir yolu var sanırım. Ben tam bir çözüm demiyorum ama benim durumumda amaca hizmet etti.

Yaptığım parçayı değiştirmek yerine hedef parçayı yeni ekledim. Temel olarak add()bunun yerine yöntemi kullanacaksınız replace().

Başka ne yaptım. Mevcut parçamı saklıyorum ve backstack'e ekliyorum.

Bu nedenle, mevcut parça üzerinde görüşünü bozmadan yeni parçayla örtüşüyor. ( onDestroyView()Yönteminin çağrılmadığından emin olun. Ayrıca backstate, parçanın devam ettirilmesi avantajını bana eklemek .

İşte kod:

Fragment fragment=new DestinationFragment();
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment);
ft.hide(SourceFragment.this);
ft.addToBackStack(SourceFragment.class.getName());
ft.commit();

AFAIK Sistemi yalnızca onCreateView()görünüm yok edilirse veya oluşturulmazsa çağrı yapar . Ancak burada görünümü bellekten kaldırarak kurtardık. Bu yüzden yeni bir görünüm oluşturmayacak.

Ve Hedef Parçasından geri döndüğünüzde FragmentTransaction, en üstteki (SourceFragment) görünümünün ekran üzerinde görünmesini sağlayan son kaldırma üst parçasını açacaktır.

YORUM: Dediğim gibi, Kaynak parçasının görünümünü kaldırmaz ve bu nedenle normalden daha fazla bellek işgal eder, çünkü tam bir çözüm değildir. Ama yine de, amaca hizmet edin. Ayrıca, geleneksel olmayan görüntüyü değiştirmek yerine, görünümü gizlemek için tamamen farklı bir mekanizma kullanıyoruz.

Yani bu gerçekten devleti nasıl koruduğunuz için değil, görüşü nasıl koruduğunuz için.


Benim durumumda, yerine bir parça ekleyerek yoklama kullanırken soruna neden olur veya parçada başka bir web isteği kullanılır. Parça B eklendiğinde bu yoklamayı Parça A'da duraklatmak istiyorum. Bu konuda bir fikrin var mı?
Uma

FirstFragment'ta yoklamayı nasıl kullanıyorsunuz? Her iki parça da bellekte kaldığı için bunu manuel olarak yapmanız gerekir. Böylece gerekli eylemi gerçekleştirmek için örneklerini kullanabilirsiniz. Umarım bu yardımcı olur.
kaushal trivedi

1
İpucu için teşekkürler =). Bunu ben yaptım. Ama bunu yapmanın tek yolu bu mu? Ve uygun bir yol? Ayrıca ana sayfa düğmesine bastığımda ve uygulamayı yeniden başlattığımda tüm parçalar tekrar aktif hale geliyor. Diyelim ki burada bu şekilde F Parçası B'deyim. Activity A{Fragment A --> Fragment B}home düğmesine bastıktan sonra uygulamayı tekrar başlattığımda her iki parça onResume()da çağrılır ve böylece yoklamalarına başlarlar. Bunu nasıl kontrol edebilirim?
Uma

1
Maalesef yapamazsınız, Sistem bu şekilde normal davranışta çalışmaz, her iki parçayı da doğrudan faaliyetin alt öğesi olarak kabul eder. Tüm bu sorunları keşfettim, şimdi önerim bu yoldan gitmemek. üzgünüm.
kaushal trivedi

1
Tabii ki, son olarak başka bir çözüm bulana kadar bu yaklaşıma gitmemeyi söyleyeceğim, çünkü yönetmek zor.
kaushal trivedi

7

Çok basit bir çözüm öneririm.

View başvuru değişkenini alın ve OnCreateView'da görünümü ayarlayın. Bu değişkente görünümün zaten mevcut olup olmadığını kontrol edin, ardından aynı görünümü döndürün.

   private View fragmentView;

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

        if (fragmentView != null) {
            return fragmentView;
        }
        View view = inflater.inflate(R.layout.yourfragment, container, false);
        fragmentView = view;
        return view;
    }

1
OnDestroy ()
Arun PM

@ArunPM böylece onDestroy () fragmentView nasıl kaldırılır? if (_rootView.getParent() != null) { ((ViewGroup)_rootView.getParent()).removeView(_rootView); }belleği temizlemek için uygun mu?
Mehmet Gür

1
@ MehmetGür Bu çözümü birçok kez kullanıyorum. Şimdiye kadar herhangi bir bellek sızıntı hatası alamadım. Ama isterseniz ArunPM çözümünü kullanabilirsiniz. OnDestroy () yönteminde null için fragmentView ayarlamak için söylüyor düşünüyorum.
Mandeep Singh

1
Bu yöntemi izlediğimde bellek sızıntılarını ve atma sızıntılarını tespit etmek için LeakCanary kullanıyorum . @Mandeep açıklamada belirtildiği iç çekişle Ama biz atayarak bu sorunu aşabiliriz nulliçin fragmentView değişken onDestroy()yöntemiyle.
Arun PM

1
Bildiğim kadarıyla, bir parça parçalandığında, parça ile ilişkili görüş temizlenir onDestroyView(). Bu temizleme, yedekleme görünümü değişkenimiz (burada fragmentView ) için gerçekleşmez ve parça geri istiflendiğinde / yok edildiğinde bellek sızıntısına neden olur. Aynı referansı LeakCanery girişindeki [Bellek sızıntılarının yaygın nedenleri] ( square.github.io/leakcanary/fundamentals/… ) bölümünde bulabilirsiniz.
Arun PM

6

Bu sorunu, kaydetmek / yeniden yüklemek için çok fazla kurulum ayrıntısına sahip bir harita içeren bir Fragment ile karşılaştım. Benim çözümüm bu Parçayı tüm zaman boyunca aktif tutmaktı (@kaushal'ın bahsettiğine benzer).

Mevcut A Parçanız olduğunu ve F Parçasını B görüntülemek istediğinizi varsayalım. Sonuçları özetlemek gerekirse:

  • replace () - A Parçasını kaldırın ve B Parçasıyla değiştirin. A parçası tekrar öne getirildiğinde yeniden oluşturulur
  • add () - (oluştur ve) F Parçası B ekler ve arka planda hala aktif olan A Parçası ile çakışır.
  • remove () - Parça B'yi kaldırmak ve A'ya dönmek için kullanılabilir. Parça B, daha sonra çağrıldığında yeniden oluşturulacaktır

Bu nedenle, her iki Parçayı da "kaydedilmiş" tutmak istiyorsanız, hide () / show () işlevini kullanarak bunları değiştirin.

Artıları : birden fazla Fragman çalışan tutmak için kolay ve basit bir yöntem
Eksileri : hepsini çalıştırmak için çok daha fazla bellek kullanın. Sorunlara neden olabilir, örneğin birçok büyük bitmap görüntüleme


b parçasını kaldırdığımızda ve A'ya döndüğümüzde lütfen bana A parçasında hangi yöntemin çağrıldığını söyler misiniz? B parçasını kaldırdığımızda biraz işlem yapmak istiyorum.
Google

5

onSaveInstanceState() yalnızca yapılandırma değişikliği varsa çağrılır.

Bir parçadan diğerine geçiş yapıldığından, hiçbir yapılandırma değişikliği olmadığından hiçbir çağrı yoktur onSaveInstanceState(). Hangi devlet kurtarılmıyor? Belirleyebilir misiniz?

EditText'e bir metin girerseniz, metin otomatik olarak kaydedilir. Kimliği olmayan herhangi bir UI öğesi, görüntüleme durumu kaydedilmeyecek olan öğedir.


onSaveInstanceState() sistem Aktivite'yi yok ettiğinde de çağrılır, çünkü kaynakları yoktur.
Marcel Bro

0

Burada, onSaveInstanceStateparçaya geri parçaya parça eklediğinizde çağırmaz. Backstack fragman yaşam döngüsü restore başlangıç zaman onCreateViewve bitiş onDestroyViewsüre onSaveInstanceStatearasına denir onDestroyViewve onDestroy. Benim çözüm örnek değişken oluşturmak ve init in onCreate. Basit kod:

private boolean isDataLoading = true;
private ArrayList<String> listData;
public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     isDataLoading = false;
     // init list at once when create fragment
     listData = new ArrayList();
}

Ve kontrol et onActivityCreated:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if(isDataLoading){
         fetchData();
    }else{
         //get saved instance variable listData()
    }
}

private void fetchData(){
     // do fetch data into listData
}

0
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
    {
        @Override
        public void onBackStackChanged()
        {
            if (getSupportFragmentManager().getBackStackEntryCount() == 0)
            {
                //setToolbarTitle("Main Activity");
            }
            else
            {
                Log.e("fragment_replace11111", "replace");
            }
        }
    });


YourActivity.java
@Override
public void onBackPressed()
{
 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.Fragment_content);
  if (fragment instanceof YourFragmentName)
    {
        fragmentReplace(new HomeFragment(),"Home Fragment");
        txt_toolbar_title.setText("Your Fragment");
    }
  else{
     super.onBackPressed();
   }
 }


public void fragmentReplace(Fragment fragment, String fragment_name)
{
    try
    {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.Fragment_content, fragment, fragment_name);
        fragmentTransaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
        fragmentTransaction.addToBackStack(fragment_name);
        fragmentTransaction.commitAllowingStateLoss();
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

0

Sorunum benzerdi ama parçayı canlı tutmadan üstesinden geldim. Diyelim ki 2 parçalı bir etkinliğiniz var - F1 ve F2. F1 başlangıçta başlatılır ve bazı kullanıcı bilgileri içerdiğini söyleyelim ve daha sonra bazı durumlarda F2, kullanıcıdan ek özellikleri (telefon numaralarını) doldurmasını ister . Sonra, bu telefon numarasının F1'e geri dönmesini ve kayıt işlemini tamamlamasını istiyorsunuz, ancak önceki tüm kullanıcı bilgilerinin kaybolduğunu ve önceki verilerinin olmadığını fark ediyorsunuz. Parça sıfırdan yeniden oluşturulur ve bu bilgileri onSaveInstanceStatepakete kaydetmiş olsanız bile null geri gelir onActivityCreated.

Çözüm: Gerekli bilgileri arama etkinliğinde örnek değişken olarak kaydedin. Sonra bu örnek değişkeni parçanıza iletin.

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Bundle args = getArguments();

    // this will be null the first time F1 is created. 
    // it will be populated once you replace fragment and provide bundle data
    if (args != null) {
        if (args.get("your_info") != null) {
            // do what you want with restored information
        }
    }
}

Bu yüzden benim örneğimi takip: F2 görüntülemeden önce kullanıcı verisini bir geri arama kullanarak örnek değişkenine kaydediyorum. Sonra F2'yi başlatırım, kullanıcı telefon numarasını doldurur ve kaydet tuşuna basar. Ben, aktivitede başka geri arama kullanmak bu bilgileri toplamak ve bu sefer benim parçası F1 yerine sahiptir ı kullanabileceği paket veri.

@Override
public void onPhoneAdded(String phone) {
        //replace fragment
        F1 f1 = new F1 ();
        Bundle args = new Bundle();
        yourInfo.setPhone(phone);
        args.putSerializable("you_info", yourInfo);
        f1.setArguments(args);

        getFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, f1).addToBackStack(null).commit();

    }
}

Geri aramalar hakkında daha fazla bilgiyi şu adreste bulabilirsiniz: https://developer.android.com/training/basics/fragments/communicating.html


0

ilk : FragmentTransaction sınıfının yerine yöntemi yerine add yöntemini kullanın, sonra addToBackStack yöntemi ile yığına secondFragment eklemeniz gerekir

ikinci : geri tıkladığınızda popBackStackImmediate ()

Fragment sourceFragment = new SourceFragment ();
final Fragment secondFragment = new SecondFragment();
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.add(R.id.child_fragment_container, secondFragment );
ft.hide(sourceFragment );
ft.addToBackStack(NewsShow.class.getName());
ft.commit();
                                
((SecondFragment)secondFragment).backFragmentInstanceClick = new SecondFragment.backFragmentNewsResult()
{
        @Override
        public void backFragmentNewsResult()
        {                                    
            getChildFragmentManager().popBackStackImmediate();                                
        }
};

0

Bir Parçayı aşağıdaki kodu kullanarak değiştirin:

Fragment fragment = new AddPaymentFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment, "Tag_AddPayment")
                .addToBackStack("Tag_AddPayment")
                .commit();

Aktivitenin onBackPressed () yöntemi:

  @Override
public void onBackPressed() {
    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 1) {

        fm.popBackStack();
    } else {


        finish();

    }
    Log.e("popping BACKSTRACK===> ",""+fm.getBackStackEntryCount());

}

0
Public void replaceFragment(Fragment mFragment, int id, String tag, boolean addToStack) {
        FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
        mTransaction.replace(id, mFragment);
        hideKeyboard();
        if (addToStack) {
            mTransaction.addToBackStack(tag);
        }
        mTransaction.commitAllowingStateLoss();
    }
replaceFragment(new Splash_Fragment(), R.id.container, null, false);

1
Sınırlı ve anında yardım sağlayabilecek bu kod snippet'i için teşekkür ederiz. Bir Doğru bir açıklama ölçüde uzun vadeli değer artıracak göstererek neden bu soruna iyi bir çözüm olduğunu ve diğer benzer sorularla gelecek okuyucularına daha kullanışlı bir hale getirecektir. Yaptığınız varsayımlar dahil bazı açıklamalar eklemek için lütfen yanıtınızı düzenleyin .
Machavity

0

Yığın içinde eski parçayı bulan ve yığın halinde varsa yükleyen mükemmel çözüm.

/**
     * replace or add fragment to the container
     *
     * @param fragment pass android.support.v4.app.Fragment
     * @param bundle pass your extra bundle if any
     * @param popBackStack if true it will clear back stack
     * @param findInStack if true it will load old fragment if found
     */
    public void replaceFragment(Fragment fragment, @Nullable Bundle bundle, boolean popBackStack, boolean findInStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        String tag = fragment.getClass().getName();
        Fragment parentFragment;
        if (findInStack && fm.findFragmentByTag(tag) != null) {
            parentFragment = fm.findFragmentByTag(tag);
        } else {
            parentFragment = fragment;
        }
        // if user passes the @bundle in not null, then can be added to the fragment
        if (bundle != null)
            parentFragment.setArguments(bundle);
        else parentFragment.setArguments(null);
        // this is for the very first fragment not to be added into the back stack.
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            ft.addToBackStack(parentFragment.getClass().getName() + "");
        }
        ft.replace(R.id.contenedor_principal, parentFragment, tag);
        ft.commit();
        fm.executePendingTransactions();
    }

gibi kullan

Fragment f = new YourFragment();
replaceFragment(f, null, boolean true, true); 
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.