Parça yöneticisi

FragmentManager, uygulamanızın parçaları üzerinde bunları ekleme, çıkarma veya değiştirme ve arka yığına ekleme gibi işlemler yapmaktan sorumlu sınıftır.

Jetpack Navigation kitaplığını kullanıyorsanız FragmentManager ile doğrudan etkileşimde bulunamazsınız. Bu kitaplık sizin adınıza FragmentManager ile çalışır. Ancak, parça kullanan tüm uygulamalar belirli bir düzeyde FragmentManager kullanır. Bu nedenle, parçanın ne olduğunu ve nasıl çalıştığını anlamak önemlidir.

Bu sayfada ele alınan konular:

  • FragmentManager platformuna nasıl erişilir?
  • Etkinlikleriniz ve parçalarınızla ilişkili olarak FragmentManager rolü.
  • Arka yığını FragmentManager ile yönetme.
  • Parçalarınıza veri ve bağımlılıkları sağlama.

FragmentManager'a erişme

FragmentManager öğesine bir etkinlikten veya parçadan erişebilirsiniz.

FragmentActivity ve AppCompatActivity gibi alt sınıfları, FragmentManager'a getSupportFragmentManager() yöntemiyle erişebilir.

Parçalar, bir veya daha fazla alt parçayı barındırabilir. Bir parçanın içinde, parçanın alt öğelerini getChildFragmentManager() aracılığıyla yöneten FragmentManager referansı alabilirsiniz. FragmentManager ana makinesine erişmeniz gerekiyorsa getParentFragmentManager() kullanabilirsiniz.

Parçalar, bunların ana makineleri ve her biriyle ilişkilendirilmiş FragmentManager örnekleri arasındaki ilişkileri görmek için birkaç örneği burada bulabilirsiniz.

Parçalar ile ana makine etkinlikleri arasındaki ilişkileri gösteren iki kullanıcı arayüzü düzeni örneği
Şekil 1. Parçalar ve ana makine etkinlikleri arasındaki ilişkileri gösteren iki kullanıcı arayüzü düzeni örneği.

Şekil 1'de, her biri tek bir etkinlik ana makinesine sahip iki örnek gösterilmektedir. Bu örneklerin her ikisindeki ana makine etkinliği, kullanıcıya üst düzey gezinmeyi bir BottomNavigationView olarak gösterir. Bu öğe, uygulamadaki ana makine parçasını farklı ekranlarla değiştirmekten sorumludur. Her ekran ayrı bir parça olarak uygulanır.

Örnek 1'deki ana makine parçası, bölünmüş görünüm ekranını oluşturan iki alt parça barındırır. Örnek 2'deki ana makine parçası, kaydırma görünümünün görünen parçasını oluşturan tek bir alt parçayı barındırır.

Bu kuruluma göre, her bir ana makineyi, alt parçalarını yöneten bir FragmentManager öğesine sahip olarak düşünebilirsiniz. Bu, Şekil 2'de supportFragmentManager, parentFragmentManager ve childFragmentManager arasındaki mülk eşlemeleriyle birlikte gösterilmiştir.

her ana makinenin, alt parçalarını yöneten, kendisiyle ilişkilendirilmiş kendi FragmentManager'ı vardır
Şekil 2. Her ana makinenin, alt parçalarını yöneten kendi FragmentManager ile ilişkilendirilmiş olması gerekir.

Referansta bulunulacak uygun FragmentManager özelliği, çağrı sitesinin parça hiyerarşisinde nerede bulunduğuna ve erişmeye çalıştığınız parça yöneticisine bağlıdır.

FragmentManager için referansınız olduğunda, bunu kullanıcıya gösterilen parçaları değiştirmek için kullanabilirsiniz.

Alt parçalar

Genel olarak, uygulamanız uygulama projenizde bir veya az sayıda etkinlikten oluşur ve her etkinlik bir grup ilgili ekranı temsil eder. Etkinlik, üst düzey gezinmenin yerleştirileceği bir nokta ve parçalar arasındaki ViewModel nesnelerinin ve diğer görünüm durumlarının kapsamının belirlenmesi için bir yer sağlayabilir. Parça, uygulamanızdaki ayrı bir hedefi temsil eder.

Bölünmüş görünümde veya kontrol panelinde olduğu gibi, aynı anda birden fazla parça göstermek istiyorsanız hedef parçanız ve alt parça yöneticisi tarafından yönetilen alt parçaları kullanabilirsiniz.

Alt parçalar için diğer kullanım alanları şunlardır:

  • Bir dizi alt parça görünümünü yönetmek için üst parçada ViewPager2 kullanarak bir ekran slaytları.
  • Bir dizi ilgili ekranda alt gezinme.
  • Jetpack Navigasyon, alt parçaları ayrı hedefler olarak kullanır. Bir etkinlik tek bir üst öğe NavHostFragment barındırır ve kullanıcılar uygulamanızda gezinirken bu alanın alanını farklı alt hedef parçalarla doldurur.

FragmentManager'ı kullanma

FragmentManager, parça arka yığınını yönetir. Çalışma zamanında FragmentManager, kullanıcı etkileşimlerine yanıt olarak parçaları ekleme veya kaldırma gibi arka yığın işlemleri gerçekleştirebilir. Her değişiklik grubu, FragmentTransaction adı verilen tek bir birim olarak birlikte işlenir. Parça işlemleri hakkında daha ayrıntılı bir tartışma için parça işlemleri kılavuzunu inceleyin.

Kullanıcı, cihazındaki Geri düğmesine dokunduğunda veya FragmentManager.popBackStack() çağrısını yaptığınızda, en üstteki parça işlemi yığından çıkar. Yığında başka parça işlemi yoksa ve alt parçalar kullanmıyorsanız Geri etkinliği, etkinliği baloncuk olarak gösterir. Alt parçalar kullanıyorsanız alt ve kardeş parçalar için özel noktalara bakın.

Bir işlemde addToBackStack() çağrısı yaptığınızda, işlem birden fazla parça ekleme veya birden fazla container'daki parçaları değiştirme gibi herhangi bir sayıda işlemi içerebilir.

Geri yığın patlatıldığında, tüm bu işlemler tek bir atomik işlem olarak tersine çevrilir. Ancak popBackStack() çağrısından önce ek işlemler yaptıysanız ve işlem için addToBackStack() kullanmadıysanız bu işlemler geri alınmaz. Bu nedenle, arka yığını etkileyen işlemleri tek bir FragmentTransaction içinde etkilemeyen işlemlerle karıştırmaktan kaçının.

İşlem gerçekleştirme

Düzen kapsayıcısındaki bir parçayı görüntülemek için FragmentManager kullanarak FragmentTransaction oluşturun. Ardından işlem sırasında kapsayıcıda bir add() veya replace() işlemi gerçekleştirebilirsiniz.

Örneğin, basit bir FragmentTransaction aşağıdaki gibi görünebilir:

Kotlin

supportFragmentManager.commit {
   replace<ExampleFragment>(R.id.fragment_container)
   setReorderingAllowed(true)
   addToBackStack("name") // Name can be null
}

Java

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null)
    .setReorderingAllowed(true)
    .addToBackStack("name") // Name can be null
    .commit();

Bu örnekte ExampleFragment, şu anda R.id.fragment_container kimliğiyle tanımlanan düzen kapsayıcısında bulunan parçayı (varsa) değiştirir. Parça sınıfının replace() yöntemine sağlanması, FragmentManager ürününün, FragmentFactory yöntemini kullanarak örneklendirmeyi işleyebilmesini sağlar. Daha fazla bilgi için Parçalarınıza bağımlılıkları sağlama bölümüne bakın.

setReorderingAllowed(true), animasyonların ve geçişlerin düzgün çalışması için işlemle ilgili parçaların durum değişikliklerini optimize eder. Animasyonlar ve geçişlerle gezinme hakkında daha fazla bilgi için Parça işlemleri ve Animasyonları kullanarak parçalar arasında gezinme bölümlerine bakın.

addToBackStack() çağrıldığında işlem arka yığına kaydedilir. Kullanıcı, daha sonra Geri düğmesine dokunarak işlemi tersine çevirebilir ve önceki parçayı geri getirebilir. Tek bir işleme birden fazla parça ekler veya kaldırırsanız arka yığın açıldığında tüm bu işlemler geri alınır. addToBackStack() çağrısında sağlanan isteğe bağlı ad, popBackStack() kullanarak belirli bir işleme geri dönme olanağı sağlar.

Bir parçayı kaldıran bir işlem gerçekleştirirken addToBackStack() yöntemini çağırmazsanız işlem gerçekleştiğinde kaldırılan parça kaldırılır ve kullanıcı geri gidemez. Bir parçayı kaldırırken addToBackStack() çağrısı yaparsanız parça yalnızca STOPPED olur ve kullanıcı geri döndüğünde daha sonra RESUMED olur. Bu durumda görünümü kaldırılır. Daha fazla bilgi için Parça yaşam döngüsü bölümüne bakın.

Mevcut bir parçayı bulma

findFragmentById() kullanarak bir düzen kapsayıcısındaki mevcut parçaya referans alabilirsiniz. Bir parçayı XML'den şişirilmişken verilen kimliğe ya da FragmentTransaction içine eklendiğinde kapsayıcı kimliğine göre aramak için findFragmentById() kullanın. Aşağıda bununla ilgili bir örnek verilmiştir:

Kotlin

supportFragmentManager.commit {
   replace<ExampleFragment>(R.id.fragment_container)
   setReorderingAllowed(true)
   addToBackStack(null)
}
...
val fragment: ExampleFragment =
        supportFragmentManager.findFragmentById(R.id.fragment_container) as ExampleFragment

Java

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null)
    .setReorderingAllowed(true)
    .addToBackStack(null)
    .commit();
...
ExampleFragment fragment =
        (ExampleFragment) fragmentManager.findFragmentById(R.id.fragment_container);

Alternatif olarak, bir parçaya benzersiz bir etiket atayabilir ve findFragmentByTag() kullanarak bir referans alabilirsiniz. Düzeniniz içinde veya FragmentTransaction içindeki bir add() ya da replace() işlemi sırasında tanımlanan parçalarda android:tag XML özelliğini kullanarak etiket atayabilirsiniz.

Kotlin

supportFragmentManager.commit {
   replace<ExampleFragment>(R.id.fragment_container, "tag")
   setReorderingAllowed(true)
   addToBackStack(null)
}
...
val fragment: ExampleFragment =
        supportFragmentManager.findFragmentByTag("tag") as ExampleFragment

Java

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
    .replace(R.id.fragment_container, ExampleFragment.class, null, "tag")
    .setReorderingAllowed(true)
    .addToBackStack(null)
    .commit();
...
ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentByTag("tag");

Alt ve kardeş parçalar için özel noktalar

Herhangi bir zamanda parça arka yığınını yalnızca bir FragmentManager kontrol edebilir. Uygulamanız ekranda aynı anda birden fazla eşdüzey parça gösteriyorsa veya uygulamanız alt parçalar kullanıyorsa uygulamanızın birincil gezinmesini işlemek için bir FragmentManager atanır.

Bir parça işleminin birincil gezinme parçasını tanımlamak için işlemde setPrimaryNavigationFragment() yöntemini çağırın ve childFragmentManager birincil kontrole sahip parçanın örneğini iletin.

Gezinme yapısını bir dizi katman olarak düşünebilirsiniz. Bu katmandaki etkinlik, en dıştaki katman olarak kabul edilir ve altındaki alt parçalardan oluşan her katman sarmalanır. Her katmanın tek bir birincil gezinme parçası vardır.

Geri etkinliği gerçekleştiğinde, en içteki katman gezinme davranışını kontrol eder. En içteki katmanda geri oluşturulacak parça işlemi kalmadığında, kontrol bir sonraki katmana geri döner ve bu işlem siz etkinliğe ulaşana kadar tekrarlanır.

İki veya daha fazla parça aynı anda görüntülendiğinde bunlardan yalnızca biri birincil gezinme parçası olur. Bir parçanın birincil gezinme parçası olarak ayarlanması, önceki parçanın tanımlamasını kaldırır. Önceki örneği kullanarak ayrıntı parçasını birincil gezinme parçası olarak ayarlarsanız ana parçanın ataması kaldırılır.

Birden fazla arka sırayı destekleme

Bazı durumlarda, uygulamanızın birden fazla arka yığını desteklemesi gerekebilir. Uygulamanızın alt gezinme çubuğu kullanması, bunun yaygın bir örneğidir. FragmentManager, saveBackStack() ve restoreBackStack() yöntemleriyle birden fazla arka yığını desteklemenize olanak tanır. Bu yöntemler, bir arka yığını kaydedip farklı bir arka yığını geri yükleyerek arka yığınlar arasında geçiş yapmanızı sağlar.

saveBackStack(), isteğe bağlı name parametresiyle popBackStack() çağrısına benzer şekilde çalışır: Belirtilen işlem ve yığında ondan sonraki tüm işlemler başlatılır. Aralarındaki fark, saveBackStack() özelliğinin pop-up işlemlerdeki tüm parçaların durumunu kaydetmesidir.

Örneğin, daha önce aşağıdaki örnekte gösterildiği gibi addToBackStack() kullanarak bir FragmentTransaction işlemi yaparak arka yığına daha önce bir parça eklediğinizi varsayalım:

Kotlin

supportFragmentManager.commit {
  replace<ExampleFragment>(R.id.fragment_container)
  setReorderingAllowed(true)
  addToBackStack("replacement")
}

Java

supportFragmentManager.beginTransaction()
  .replace(R.id.fragment_container, ExampleFragment.class, null)
  // setReorderingAllowed(true) and the optional string argument for
  // addToBackStack() are both required if you want to use saveBackStack()
  .setReorderingAllowed(true)
  .addToBackStack("replacement")
  .commit();

Bu durumda, saveBackStack() yöntemini çağırarak bu parça işlemini ve ExampleFragment durumunu kaydedebilirsiniz:

Kotlin

supportFragmentManager.saveBackStack("replacement")

Java

supportFragmentManager.saveBackStack("replacement");

Başlatılan işlemlerin ve kayıtlı tüm parça durumlarının geri yüklenmesini sağlamak için restoreBackStack() öğesini aynı ad parametresiyle çağırabilirsiniz:

Kotlin

supportFragmentManager.restoreBackStack("replacement")

Java

supportFragmentManager.restoreBackStack("replacement");

Parçalarınıza bağımlılıklar sağlama

Bir parça eklerken, parçayı manuel olarak örnekleyebilir ve FragmentTransaction öğesine ekleyebilirsiniz.

Kotlin

fragmentManager.commit {
    // Instantiate a new instance before adding
    val myFragment = ExampleFragment()
    add(R.id.fragment_view_container, myFragment)
    setReorderingAllowed(true)
}

Java

// Instantiate a new instance before adding
ExampleFragment myFragment = new ExampleFragment();
fragmentManager.beginTransaction()
    .add(R.id.fragment_view_container, myFragment)
    .setReorderingAllowed(true)
    .commit();

Parça işlemini kaydettiğinizde, oluşturduğunuz parçanın örneği, kullanılan örnek olur. Ancak yapılandırma değişikliği sırasında etkinliğiniz ve tüm parçalarınız yok edilir ve ardından en geçerli Android kaynaklarıyla yeniden oluşturulur. FragmentManager tüm bunları sizin için halleder: Parçalarınızın örneklerini yeniden oluşturur, bunları ana makineye ekler ve arka yığın durumunu yeniden oluşturur.

Varsayılan olarak FragmentManager, çerçevenin parçanızın yeni bir örneğini örneklendirmek için sağladığı bir FragmentFactory kullanır. Bu varsayılan fabrika, parçanız için bağımsız değişkensiz oluşturucu bulmak ve çağırmak üzere yansımayı kullanır. Bu, parçanıza bağımlılıklar sağlamak için bu varsayılan fabrikayı kullanamayacağınız anlamına gelir. Aynı zamanda, parçanızı ilk kez oluşturmak için kullandığınız herhangi bir özel oluşturucunun, yeniden oluşturma sırasında varsayılan olarak kullanılmayacağı anlamına gelir.

Parçanıza bağımlılıklar sağlamak veya herhangi bir özel oluşturucu kullanmak için özel bir FragmentFactory alt sınıfı oluşturup FragmentFactory.instantiate değerini geçersiz kılın. Daha sonra, FragmentManager öğesinin varsayılan fabrikasını özel fabrikanızla geçersiz kılabilirsiniz. Bu ayar daha sonra parçalarınızı göstermek için kullanılır.

Bulunduğunuz şehirde popüler tatlıları görüntülemekten sorumlu bir DessertsFragment sahibi olduğunuzu ve DessertsFragment adlı iş ortağının, kullanıcınıza doğru kullanıcı arayüzünü göstermesi için gereken bilgileri sağlayan bir DessertsRepository sınıfına bağımlılığı olduğunu varsayalım.

DessertsFragment öğenizi, oluşturucuda DessertsRepository örneği gerektirecek şekilde tanımlayabilirsiniz.

Kotlin

class DessertsFragment(val dessertsRepository: DessertsRepository) : Fragment() {
    ...
}

Java

public class DessertsFragment extends Fragment {
    private DessertsRepository dessertsRepository;

    public DessertsFragment(DessertsRepository dessertsRepository) {
        super();
        this.dessertsRepository = dessertsRepository;
    }

    // Getter omitted.

    ...
}

Basit bir FragmentFactory uygulaması aşağıdakine benzer görünebilir.

Kotlin

class MyFragmentFactory(val repository: DessertsRepository) : FragmentFactory() {
    override fun instantiate(classLoader: ClassLoader, className: String): Fragment =
            when (loadFragmentClass(classLoader, className)) {
                DessertsFragment::class.java -> DessertsFragment(repository)
                else -> super.instantiate(classLoader, className)
            }
}

Java

public class MyFragmentFactory extends FragmentFactory {
    private DessertsRepository repository;

    public MyFragmentFactory(DessertsRepository repository) {
        super();
        this.repository = repository;
    }

    @NonNull
    @Override
    public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
        Class<? extends Fragment> fragmentClass = loadFragmentClass(classLoader, className);
        if (fragmentClass == DessertsFragment.class) {
            return new DessertsFragment(repository);
        } else {
            return super.instantiate(classLoader, className);
        }
    }
}

Bu örnekte FragmentFactory alt sınıfları seçilidir ve DessertsFragment için özel parça oluşturma mantığı sağlamak amacıyla instantiate() yöntemini geçersiz kılar. Diğer parça sınıfları, FragmentFactory ile super.instantiate() arasındaki varsayılan davranışa göre işlenir.

Daha sonra, FragmentManager üzerinde bir özellik ayarlayarak MyFragmentFactory uygulamasını, uygulamanızın parçalarını oluştururken kullanılacak fabrika olarak tanımlayabilirsiniz. Parçalarınızı yeniden oluştururken MyFragmentFactory kullanıldığından emin olmak için bu özelliği etkinliğinizin super.onCreate() özelliğinden önce ayarlamanız gerekir.

Kotlin

class MealActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        supportFragmentManager.fragmentFactory = MyFragmentFactory(DessertsRepository.getInstance())
        super.onCreate(savedInstanceState)
    }
}

Java

public class MealActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        DessertsRepository repository = DessertsRepository.getInstance();
        getSupportFragmentManager().setFragmentFactory(new MyFragmentFactory(repository));
        super.onCreate(savedInstanceState);
    }
}

Etkinlikte FragmentFactory ayarlanırsa etkinliğin parça hiyerarşisinde parça oluşturmayı geçersiz kılar. Başka bir deyişle, eklediğiniz alt parçaların childFragmentManager değeri, daha düşük bir düzeyde geçersiz kılınmadığı sürece burada ayarlanan özel parça fabrikasını kullanır.

FragmentFactory ile test edin

Tek etkinlik mimarisinde, FragmentScenario sınıfını kullanarak parçalarınızı ayrı ayrı test edin. Etkinliğinizin özel onCreate mantığını kullanamayacağınız için, aşağıdaki örnekte gösterildiği gibi, FragmentFactory öğesini parça testinize bağımsız değişken olarak aktarabilirsiniz:

// Inside your test
val dessertRepository = mock(DessertsRepository::class.java)
launchFragment<DessertsFragment>(factory = MyFragmentFactory(dessertRepository)).onFragment {
    // Test Fragment logic
}

Bu test süreci hakkında ayrıntılı bilgi ve örneklerin tamamı için Parçalarınızı test etme bölümüne bakın.