Etkinlik yerleştirme

Etkinlik yerleştirme, bir uygulamanın görev penceresini iki etkinlik veya aynı etkinliğin iki örneğine bölerek büyük ekranlı cihazlarda uygulamaları optimize eder.

Şekil 1. Etkinliklerin yan yana gösterildiği Ayarlar uygulaması.

Uygulamanızda birden fazla etkinlik varsa etkinlik yerleştirme özelliği; tabletlerde, katlanabilir cihazlarda ve ChromeOS cihazlarda gelişmiş bir kullanıcı deneyimi sunmanızı sağlar.

Etkinlik yerleştirme, kodun yeniden düzenlenmesini gerektirmez. Bir XML yapılandırma dosyası oluşturarak veya Jetpack WindowManager API çağrıları yaparak uygulamanızın etkinliklerini yan yana veya yığın halinde nasıl göstereceğini siz belirlersiniz.

Küçük ekran desteği otomatik olarak devam eder. Uygulamanız küçük ekranlı bir cihazda olduğunda, etkinlikler üst üste yığılır. Büyük ekranlarda, etkinlikler yan yana gösterilir. Sistem, sunumu oluşturduğunuz yapılandırmaya göre belirler. Dallara ayırma mantığına gerek yoktur.

Etkinlik yerleştirme özelliği, cihaz yönü değişikliklerini kabul eder ve katlanabilir cihazlarda sorunsuz şekilde çalışır. Cihaz katlanıp açılırken etkinlikleri yığma ve açma işlemleri

Etkinlik yerleştirme, Android 12L (API düzeyi 32) ve sonraki sürümleri çalıştıran büyük ekranlı cihazların çoğunda desteklenir.

Görev penceresini böl

Etkinlik yerleştirme, uygulama görevi penceresini birincil ve ikincil olmak üzere iki kapsayıcıya böler. Kapsayıcılar, ana etkinlikten veya zaten kapsayıcıda bulunan diğer etkinliklerden başlatılan etkinlikleri barındırır.

Etkinlikler, kullanıma sunuldukça ikincil kapsayıcıda yığılır ve ikincil kapsayıcı, küçük ekranlarda birincil kapsayıcının üzerine yerleştirilir. Böylece, etkinlik yığınlama ve geri gezinme, uygulamanızda hâlihazırda yerleşik olarak bulunan etkinliklerin sıralamasıyla tutarlı olur.

Etkinlik yerleştirme, etkinlikleri çeşitli şekillerde görüntülemenizi sağlar. Uygulamanız aynı anda yan yana iki etkinliği başlatarak görev penceresini bölebilir:

Şekil 2. Yan yana iki etkinlik.

Veya tüm görev penceresini kaplayan bir etkinlik, aşağıdakilerin yanında yeni bir etkinlik başlatarak bölme oluşturabilir:

Şekil 3. A etkinliği, B etkinliğini yan tarafta başlatır.

Zaten bölünmüş olan ve bir görev penceresini paylaşan etkinlikler, aşağıdaki yollarla başka etkinlikler başlatabilir:

  • Başka bir aktivitenin yanında:

    Şekil 4. A Etkinliği, B aktivitesinin üzerinde yan tarafta C aktivitesini başlatır.
  • Önceki birincil aktiviteyi gizleyerek yana ve bölmeyi yana doğru kaydırın:

    Şekil 5. B Etkinliği, C etkinliğini kenara çeker ve bölmeyi yana doğru kaydırır.
  • En üstte, yani aynı etkinlik yığınında bir etkinlik başlatın:

    Şekil 6. B Etkinliği, C etkinliğini ekstra intent işareti olmadan başlatır.
  • Aynı görevde bir etkinlik tam penceresini başlatma:

    Şekil 7. A Etkinliği veya B etkinliği, görev penceresini dolduran C etkinliğini başlatır.

Geri gitme

Farklı uygulama türleri, etkinlikler arasındaki bağımlılıklara veya kullanıcıların geri etkinliğini nasıl tetiklediğine bağlı olarak bölünmüş görev penceresi durumunda farklı geri gezinme kurallarına sahip olabilir. Örneğin:

  • Birlikte gitme: Etkinlikler birbiriyle ilişkiliyse ve biri diğeri olmadan gösterilmeyecekse geri gitme, her ikisini de tamamlayacak şekilde yapılandırılabilir.
  • Tek başına devam etmek: Aktiviteler tamamen bağımsızysa bir etkinlikte geri gezinme, görev penceresindeki başka bir etkinliğin durumunu etkilemez.

Geri etkinliği, düğmeyle gezinme kullanılırken son odaklanılan etkinliğe gönderilir. Harekete dayalı gezinme ile geri etkinliği, hareketin gerçekleştiği etkinliğe gönderilir.

Çok bölmeli düzen

Jetpack WindowManager, Android 12L (API düzeyi 32) veya sonraki sürümleri çalıştıran büyük ekranlı cihazlarda ve daha eski platform sürümlerine sahip bazı cihazlarda çok bölmeli düzen yerleştirebilmenizi sağlar. SlidingPaneLayout gibi parçalar veya görünüme dayalı düzenler yerine birden çok etkinliğe dayalı mevcut uygulamalar, kaynak kodunu yeniden düzenlemeden daha iyi bir büyük ekran kullanıcı deneyimi sağlayabilir.

Liste ayrıntılarına bölünme, yaygın bir örnektir. Yüksek kaliteli bir sunum sağlamak için sistem, liste etkinliğini başlatır ve ardından uygulama hemen ayrıntı etkinliğini başlatır. Geçiş sistemi, her iki etkinlik de çekilinceye kadar bekler, ardından bunları birlikte görüntüler. Kullanıcı için iki etkinlik tek bir etkinlik olarak başlatılır.

Şekil 8. Çok bölmeli bir düzende iki etkinlik aynı anda başlatıldı.

Bölme özellikleri

Görev penceresinin bölünmüş kapsayıcılar arasında nasıl oranlanacağını ve kapsayıcıların birbirlerine göre nasıl düzenleneceğini belirtebilirsiniz.

Bir XML yapılandırma dosyasında tanımlanan kurallar için aşağıdaki özellikleri ayarlayın:

  • splitRatio: Kapsayıcı oranlarını ayarlar. Değer, açık aralıktaki (0,0, 1,0) bir kayan nokta sayıdır.
  • splitLayoutDirection: Bölünen kapsayıcıların birbirine göre nasıl düzenleneceğini belirtir. Olası değerlere örnekler:
    • ltr: Soldan sağa
    • rtl: Sağdan sola
    • locale: Yerel ayardan ltr veya rtl belirlenir

Örnekler için aşağıdaki XML yapılandırması bölümüne bakın.

WindowManager API'leri kullanılarak oluşturulan kurallar için SplitAttributes.Builder ile bir SplitAttributes nesnesi oluşturun ve aşağıdaki oluşturucu yöntemlerini çağırın:

Örnekler için aşağıdaki WindowManager API'sini inceleyin.

Şekil 9. Soldan sağa düzenlenmiş ancak farklı oranlara sahip iki etkinlik bölümü.

Yer tutucular

Yer tutucu etkinlikleri, etkinlik bölümünün bir alanını kaplayan boş ikincil etkinliklerdir. Bunların, içerik barındıran başka bir etkinlikle değiştirilmesi amaçlanır. Örneğin, bir yer tutucu etkinliği, listeden bir öğe seçilene kadar liste ayrıntısı düzeninde bölünmüş bir etkinliğin ikincil tarafını işgal edebilir. Bu noktada, seçilen liste öğesinin ayrıntı bilgilerini içeren bir etkinlik yer tutucunun yerini alır.

Varsayılan olarak sistem, yer tutucuları yalnızca etkinlik bölmesi için yeterli alan olduğunda görüntüler. Görüntü boyutu, bölme gösterilemeyecek kadar küçük bir genişlik veya yükseklik olarak değiştiğinde yer tutucular otomatik olarak işlemi bitirir. Alan izin verdiğinde sistem, yer tutucuyu sıfırlanmış durumda yeniden başlatır.

Şekil 10. Katlanabilir cihaz katlanabilir ve açılır. Yer tutucu etkinliği tamamlandı ve görüntü boyutu değiştikçe yeniden oluşturuldu.

Bununla birlikte, SplitPlaceholder.Builder SplitPlaceholderRule veya setSticky() yönteminin stickyPlaceholder özelliği varsayılan davranışı geçersiz kılabilir. Özellik veya yöntem true değerini belirttiğinde, ekran iki bölmeli bir ekrandan tek bölmeli bir ekrana yeniden boyutlandırıldığında sistem yer tutucuyu görev penceresinde en üst etkinlik olarak görüntüler (bir örnek için Bölünmüş yapılandırma bölümüne bakın).

Şekil 11. Katlanabilir cihaz katlanabilir ve açılır. Yer tutucu etkinliği sabittir.

Pencere boyutu değişiklikleri

Cihaz yapılandırmasında yapılan değişiklikler görev penceresi genişliğini çok bölmeli düzen için yeterince büyük olmayacak şekilde azalttığında (örneğin, büyük ekranlı katlanabilir bir cihaz tablet boyutundan telefon boyutuna katlandığında veya uygulama penceresi çoklu pencere modunda yeniden boyutlandırıldığında), görev penceresinin ikincil bölmesindeki yer tutucu olmayan etkinlikler birincil paneldeki etkinliklerin üzerine yerleştirilir.

Yer tutucu etkinlikleri, yalnızca bir bölüm için yeterli görüntü genişliği olduğunda gösterilir. Daha küçük ekranlarda yer tutucu otomatik olarak kapatılır. Görüntüleme alanı tekrar yeterince geniş hale geldiğinde yer tutucu yeniden oluşturulur. (Yukarıdaki Yer tutucular konusuna bakın.)

WindowManager ikincil bölmedeki etkinlikleri birincil bölmedeki etkinliklerin üzerinde z sıraya koyduğundan etkinlik yığınlama mümkündür.

İkincil bölmede birden fazla etkinlik

B Etkinliği, C etkinliğini ekstra amaç işaretleri olmadan, yerinde başlatır:

C, B'nin üzerine yığılmış A, B ve C etkinliklerini içeren etkinlik bölmesi.

Bu durum, aynı görevde etkinliklerin z sırasına aşağıdaki gibi olmasına yol açar:

B'nin üstünde yığılmış C etkinliğini içeren ikincil etkinlik yığını.
          İkincil yığın, A etkinliğini içeren temel etkinlik yığınının üzerine yerleştirilir.

Dolayısıyla, daha küçük bir görev penceresinde uygulama, yığının en üstünde C ile tek bir etkinliğe küçülür:

Yalnızca C etkinliğini gösteren küçük pencere.

Küçük pencerede geri dönerseniz üst üste yığılmış etkinlikler arasında gezinebilirsiniz.

Görev penceresi yapılandırması, birden çok bölmeyi barındırabilecek daha büyük bir boyuta geri yüklenirse etkinlikler tekrar yan yana görüntülenir.

Yığınlı bölmeler

B etkinliği C etkinliğini kenara çeker ve bölme yanlara doğru kaydırılır:

A ve B etkinliklerini, ardından B ve C etkinliklerini gösteren görev penceresi.

Sonuç, aynı görevdeki etkinliklerin z-sıralamasıdır:

A, B ve C etkinlikleri tek bir yığında. Etkinlikler yukarıdan aşağıya doğru şu şekilde sıralanır: C, B, A.

Daha küçük bir görev penceresinde, uygulama en üstte C olacak şekilde tek bir etkinliğe daraltılır:

Yalnızca C etkinliğini gösteren küçük pencere.

Sabit dikey yön

android:screenOrientation manifest ayarı, uygulamaların etkinlikleri dikey veya yatay yönde kısıtlamasına olanak tanır. Cihaz üreticileri (OEM'ler), tablet ve katlanabilir cihazlar gibi büyük ekranlı cihazlarda kullanıcı deneyimini iyileştirmek için, ekran yönü isteklerini ve yatay ekranlarda dikey yöndeki uygulamayı, dikey ekranlarda yatay yönde izleyen uygulamaları yoksayabilir.

Şekil 12. Sinemaskoplu etkinlikler: yatay cihazda sabit dikey (solda), dikey cihazda sabit yatay (sağ)

Benzer şekilde, etkinlik yerleştirme etkinleştirildiğinde OEM'ler cihazları büyük ekranlarda yatay yönde (genişlik ≥ 600 dp) sinemaskop sabit dikey etkinlikler için özelleştirebilir. Sabit dikey etkinlik ikinci bir etkinliği başlattığında cihaz, bu iki etkinliği iki bölmeli bir ekranda yan yana görüntüleyebilir.

Şekil 13. Sabit dikey etkinlik A, B etkinliğini yan tarafta başlatır.

Cihaza, uygulamanızın etkinlik yerleştirmeyi desteklediğini bildirmek için her zaman android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED özelliğini uygulama manifest dosyanıza ekleyin (aşağıdaki Bölünmüş yapılandırma bölümüne bakın). Ardından, OEM tarafından özelleştirilmiş cihazlar, sinemaskop sabit dikey aktivitelerin yapılıp yapılmayacağını belirleyebilir.

Bölünmüş yapılandırma

Bölme kuralları etkinlik bölümlerini yapılandırır. Bölme kurallarını XML yapılandırma dosyasında veya Jetpack WindowManager API çağrıları yaparak tanımlarsınız.

Her iki durumda da, uygulamanızın WindowManager kitaplığına erişmesi ve sisteme, uygulamanın etkinlik yerleştirme işlemini uyguladığını bildirmesi gerekir.

Aşağıdakileri yapın:

  1. Uygulamanızın modül düzeyindeki build.gradle dosyasına en yeni WindowManager kitaplığı bağımlılığını ekleyin. Örneğin:

    implementation 'androidx.window:window:1.1.0-beta02'

    WindowManager kitaplığı etkinlik yerleştirme için gereken tüm bileşenleri sağlar.

  2. Sisteme, uygulamanızın etkinlik yerleştirmeyi uyguladığını bildirin.

    android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED özelliğini, uygulama manifesti dosyasının <application> öğesine ekleyin ve değeri true olarak ayarlayın. Örneğin:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <application>
            <property
                android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
                android:value="true" />
        </application>
    </manifest>
    

    WindowManager 1.1.0-alpha06 ve sonraki sürümlerinde, özellik manifeste eklenip doğru değerine ayarlanmadığı sürece etkinlik yerleştirme bölmeleri devre dışı bırakılır.

    Ayrıca cihaz üreticileri, etkinlik yerleştirmeyi destekleyen uygulamalar için özel özellikleri etkinleştirmek üzere bu ayarı kullanır. Örneğin, cihazlar ikinci bir etkinlik başladığında iki bölmeli düzene geçiş etkinliğini yönlendirmek için yatay ekranlarda yalnızca dikey olarak gösterilen bir etkinliği sinemaskop olarak ayarlayabilir (bkz. Dikey yön).

XML yapılandırması

Etkinlik yerleştirme özelliğinin XML tabanlı bir uygulamasını oluşturmak için aşağıdaki adımları tamamlayın:

  1. Aşağıdakileri gerçekleştiren bir XML kaynak dosyası oluşturun:

    • Bir bölümü paylaşan etkinlikleri tanımlar
    • Bölme seçeneklerini yapılandırır
    • İçerik kullanılamadığında bölmenin ikincil kapsayıcısı için bir yer tutucu oluşturur
    • Hiçbir zaman bölmenin parçası olmaması gereken etkinlikleri belirtir

    Örnek:

    <!-- main_split_config.xml -->
    
    <resources
        xmlns:window="http://schemas.android.com/apk/res-auto">
    
        <!-- Define a split for the named activities. -->
        <SplitPairRule
            window:splitRatio="0.33"
            window:splitLayoutDirection="locale"
            window:splitMinWidthDp="840"
            window:splitMaxAspectRatioInPortrait="alwaysAllow"
            window:finishPrimaryWithSecondary="never"
            window:finishSecondaryWithPrimary="always"
            window:clearTop="false">
            <SplitPairFilter
                window:primaryActivityName=".ListActivity"
                window:secondaryActivityName=".DetailActivity"/>
        </SplitPairRule>
    
        <!-- Specify a placeholder for the secondary container when content is
             not available. -->
        <SplitPlaceholderRule
            window:placeholderActivityName=".PlaceholderActivity"
            window:splitRatio="0.33"
            window:splitLayoutDirection="locale"
            window:splitMinWidthDp="840"
            window:splitMaxAspectRatioInPortrait="alwaysAllow"
            window:stickyPlaceholder="false">
            <ActivityFilter
                window:activityName=".ListActivity"/>
        </SplitPlaceholderRule>
    
        <!-- Define activities that should never be part of a split. Note: Takes
             precedence over other split rules for the activity named in the
             rule. -->
        <ActivityRule
            window:alwaysExpand="true">
            <ActivityFilter
                window:activityName=".ExpandedActivity"/>
        </ActivityRule>
    
    </resources>
    
  2. Başlatıcı oluşturun.

    WindowManager RuleController bileşeni, XML yapılandırma dosyasını ayrıştırır ve kuralların sisteme uygunluğunu sağlar. Jetpack Startup kitaplığı Initializer, XML dosyasını uygulama başlatılırken RuleController tarafından kullanılabilir hale getirir. Böylece, herhangi bir etkinlik başlatıldığında kurallar geçerli olur.

    Başlatıcı oluşturmak için aşağıdakileri yapın:

    1. Modül düzeyindeki build.gradle dosyanıza en yeni Jetpack Startup kitaplığı bağımlılığını ekleyin. Örneğin:

      implementation 'androidx.startup:startup-runtime:1.1.1'

    2. Initializer arayüzünü uygulayan bir sınıf oluşturun.

      Başlatıcı, XML yapılandırma dosyasının kimliğini (main_split_config.xml) RuleController.parseRules() yöntemine ileterek bölme kurallarını RuleController tarafından kullanılabilir hale getirir.

      Kotlin

      class SplitInitializer : Initializer<RuleController> {
      
       override fun create(context: Context): RuleController {
           return RuleController.getInstance(context).apply {
               setRules(RuleController.parseRules(context, R.xml.main_split_config))
           }
       }
      
       override fun dependencies(): List<Class<out Initializer<*>>> {
           return emptyList()
       }
      }
      

      Java

      public class SplitInitializer implements Initializer<RuleController> {
      
        @NonNull
        @Override
        public RuleController create(@NonNull Context context) {
            RuleController ruleController = RuleController.getInstance(context);
            ruleController.setRules(
                RuleController.parseRules(context, R.xml.main_split_config)
            );
            return ruleController;
        }
      
        @NonNull
        @Override
        public List<Class<? extends Initializer<?>>> dependencies() {
            return Collections.emptyList();
        }
      }
      
  3. Kural tanımları için bir içerik sağlayıcı oluşturun.

    androidx.startup.InitializationProvider öğesini, uygulama manifest dosyanıza <provider> olarak ekleyin. RuleController başlatıcınızın (SplitInitializer) uygulanmasıyla ilgili bir referans ekleyin:

    <!-- AndroidManifest.xml -->
    
    <provider android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <!-- Make SplitInitializer discoverable by InitializationProvider. -->
        <meta-data android:name="${applicationId}.SplitInitializer"
            android:value="androidx.startup" />
    </provider>
    

    InitializationProvider, uygulamanın onCreate() yöntemi çağrılmadan önce SplitInitializer uygulamasını bulup başlatır. Sonuç olarak, bölme kuralları uygulamanın ana etkinliği başladığında geçerli olur.

WindowManager API'sı

Birkaç API çağrısıyla etkinlik yerleştirmeyi programatik olarak uygulayabilirsiniz. Herhangi bir etkinlik başlamadan önce kuralların geçerli olduğundan emin olmak için Application alt sınıfının onCreate() yönteminde çağrılar yapın.

Programlı bir şekilde etkinlik bölmesi oluşturmak için aşağıdakileri yapın:

  1. Bölme kuralı oluşturun:

    1. Bu bölünmeyi paylaşan etkinlikleri tanımlayan bir SplitPairFilter oluşturun:

      Kotlin

      val splitPairFilter = SplitPairFilter(
         ComponentName(this, ListActivity::class.java),
         ComponentName(this, DetailActivity::class.java),
         null
      )
      

      Java

      SplitPairFilter splitPairFilter = new SplitPairFilter(
         new ComponentName(this, ListActivity.class),
         new ComponentName(this, DetailActivity.class),
         null
      );
      
    2. Filtreyi bir filtre grubuna ekleyin:

      Kotlin

      val filterSet = setOf(splitPairFilter)
      

      Java

      Set<SplitPairFilter> filterSet = new HashSet<>();
      filterSet.add(splitPairFilter);
      
    3. Bölme için düzen özellikleri oluşturun:

      Kotlin

      val splitAttributes: SplitAttributes = SplitAttributes.Builder()
          .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
          .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
          .build()
      

      Java

      final SplitAttributes splitAttributes = new SplitAttributes.Builder()
            .setSplitType(SplitAttributes.SplitType.ratio(0.33f))
            .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)
            .build();
      

      SplitAttributes.Builder, düzen özelliklerini içeren bir nesne oluşturur:

      • setSplitType: Kullanılabilir görüntüleme alanının her bir etkinlik kapsayıcısına nasıl ayrılacağını tanımlar. Oranlı bölme türü, birincil kapsayıcıya ayrılan kullanılabilir görüntüleme alanının oranını belirtir. İkincil kapsayıcı ise kullanılabilir görüntüleme alanının geri kalanını kaplar.
      • setLayoutDirection: Etkinlik kapsayıcılarının, önce birincil kapsayıcı olmak üzere birbirine göre nasıl düzenleneceğini belirtir.
    4. Bir SplitPairRule oluşturun:

      Kotlin

      val splitPairRule = SplitPairRule.Builder(filterSet)
          .setDefaultSplitAttributes(splitAttributes)
          .setMinWidthDp(840)
          .setMinSmallestWidthDp(600)
          .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
          .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER)
          .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS)
          .setClearTop(false)
          .build()
      

      Java

      SplitPairRule splitPairRule = new SplitPairRule.Builder(filterSet)
          .setDefaultSplitAttributes(splitAttributes)
          .setMinWidthDp(840)
          .setMinSmallestWidthDp(600)
          .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
          .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER)
          .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS)
          .setClearTop(false)
          .build();
      

      SplitPairRule.Builder, kuralı oluşturur ve yapılandırır:

      • filterSet: Aynı bölünmeyi paylaşan etkinlikleri tanımlayarak kuralın ne zaman uygulanacağını belirleyen bölünmüş çift filtreleri içerir.
      • setDefaultSplitAttributes: Düzen özelliklerini kurala uygular.
      • setMinWidthDp: Bölme işleminin gerçekleştirilmesini sağlayan minimum görüntü genişliğini (yoğunluktan bağımsız piksel cinsinden, dp) ayarlar.
      • setMinSmallestWidthDp: Cihazın yönünden bağımsız olarak bölme işlemi yapabilmesi için iki ekran boyutundan daha küçük olana kadar olması gereken minimum değeri (dp cinsinden) ayarlar.
      • setMaxAspectRatioInPortrait: Etkinlik bölmelerinin görüntüleneceği dikey yönde maksimum görüntü en boy oranını (yükseklik:genişlik) ayarlar. Bir dikey ekranın en boy oranı maksimum en boy oranını aşarsa ekranın genişliği ne olursa olsun bölmeler devre dışı bırakılır. Not: Varsayılan değer 1,4'tür.Bu değer, çoğu tablette etkinliklerin dikey yönde tüm görev penceresinin tamamını kaplamasına neden olur. Ayrıca bkz. SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT ve setMaxAspectRatioInLandscape. Yatay için varsayılan değer ALWAYS_ALLOW şeklindedir.
      • setFinishPrimaryWithSecondary: İkincil kapsayıcıdaki tüm etkinliklerin tamamlanmasının birincil kapsayıcıdaki etkinlikleri nasıl etkileyeceğini belirler. NEVER, ikincil kapsayıcıdaki tüm etkinlikler tamamlandığında sistemin birincil etkinlikleri tamamlamaması gerektiğini belirtir (İşlemleri tamamlama bölümüne bakın).
      • setFinishSecondaryWithPrimary: Birincil kapsayıcıdaki tüm etkinliklerin tamamlanmasının ikincil kapsayıcıdaki etkinlikleri nasıl etkileyeceğini belirler. ALWAYS, birincil kapsayıcıdaki tüm etkinlikler tamamlandığında sistemin her zaman ikincil kapsayıcıdaki etkinlikleri tamamlaması gerektiğini belirtir (İşlemleri tamamlama bölümüne bakın).
      • setClearTop: Kapsayıcıda yeni bir etkinlik başlatıldığında ikincil kapsayıcıdaki tüm etkinliklerin tamamlanıp tamamlanmayacağını belirtir. Yanlış değeri, yeni etkinliklerin zaten ikincil kapsayıcıda bulunan etkinliklerin üzerine yığıldığını belirtir.
    5. WindowManager RuleController tekli örneğini alın ve kuralı ekleyin:

      Kotlin

      val ruleController = RuleController.getInstance(this)
      ruleController.addRule(splitPairRule)
      

      Java

      RuleController ruleController = RuleController.getInstance(this);
      ruleController.addRule(splitPairRule);
      
  2. İçerik kullanılamadığında ikincil kapsayıcı için bir yer tutucu oluşturun:

    1. Yer tutucunun bir görev penceresi bölmesini paylaştığı etkinliği tanımlayan bir ActivityFilter oluşturun:

      Kotlin

      val placeholderActivityFilter = ActivityFilter(
          ComponentName(this, ListActivity::class.java),
          null
      )
      

      Java

      ActivityFilter placeholderActivityFilter = new ActivityFilter(
          new ComponentName(this, ListActivity.class),
          null
      );
      
    2. Filtreyi bir filtre grubuna ekleyin:

      Kotlin

      val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
      

      Java

      Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>();
      placeholderActivityFilterSet.add(placeholderActivityFilter);
      
    3. Bir SplitPlaceholderRule oluşturun:

      Kotlin

      val splitPlaceholderRule = SplitPlaceholderRule.Builder(
            placeholderActivityFilterSet,
            Intent(context, PlaceholderActivity::class.java)
          ).setDefaultSplitAttributes(splitAttributes)
           .setMinWidthDp(840)
           .setMinSmallestWidthDp(600)
           .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
           .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS)
           .setSticky(false)
           .build()
      

      Java

      SplitPlaceholderRule splitPlaceholderRule = new SplitPlaceholderRule.Builder(
            placeholderActivityFilterSet,
            new Intent(context, PlaceholderActivity.class)
          ).setDefaultSplitAttributes(splitAttributes)
           .setMinWidthDp(840)
           .setMinSmallestWidthDp(600)
           .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f))
           .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS)
           .setSticky(false)
           .build();
      

      SplitPlaceholderRule.Builder, kuralı oluşturur ve yapılandırır:

      • placeholderActivityFilterSet: Yer tutucu etkinliğin ilişkili olduğu etkinlikleri tanımlayarak kuralın ne zaman uygulanacağını belirleyen etkinlik filtrelerini içerir.
      • Intent: Yer tutucu etkinliğin başlatıldığını belirtir.
      • setDefaultSplitAttributes: Düzen özelliklerini kurala uygular.
      • setMinWidthDp: Bölme işlemine izin veren minimum görüntü genişliğini (yoğunluktan bağımsız piksel cinsinden, dp cinsinden) ayarlar.
      • setMinSmallestWidthDp: Cihazın yönü ne olursa olsun iki ekran boyutundan daha küçük olanın bölmeye izin vermesi gereken minimum değeri (dp cinsinden) ayarlar.
      • setMaxAspectRatioInPortrait: Etkinlik bölmelerinin görüntüleneceği dikey yönde maksimum görüntü en boy oranını (yükseklik:genişlik) ayarlar. Not: Varsayılan değer 1,4'tür.Bu değer, çoğu tablette etkinliklerin görev penceresini dikey yönde doldurur. Ayrıca bkz. SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT ve setMaxAspectRatioInLandscape. Yatay için varsayılan değer ALWAYS_ALLOW şeklindedir.
      • setFinishPrimaryWithPlaceholder: Yer tutucu etkinliğini tamamlamanın birincil kapsayıcıdaki etkinlikleri nasıl etkileyeceğini belirler. HER ZAMAN yer tutucu tamamlandığında sistemin birincil kapsayıcıdaki etkinlikleri her zaman tamamlaması gerektiğini belirtir (İşlemleri tamamlama bölümüne bakın).
      • setSticky: Yer tutucu etkinliğin, yeterli minimum genişliğe sahip bir bölmede ilk kez göründükten sonra küçük ekranlarda etkinlik yığınının üstünde görünüp görünmeyeceğini belirler.
    4. Kuralı WindowManager RuleController içine ekleyin:

      Kotlin

      ruleController.addRule(splitPlaceholderRule)
      

      Java

      ruleController.addRule(splitPlaceholderRule);
      
  3. Hiçbir zaman bölmenin parçası olmaması gereken etkinlikleri belirtin:

    1. Tüm görev görüntüleme alanını her zaman kaplaması gereken bir etkinliği tanımlayan bir ActivityFilter oluşturun:

      Kotlin

      val expandedActivityFilter = ActivityFilter(
        ComponentName(this, ExpandedActivity::class.java),
        null
      )
      

      Java

      ActivityFilter expandedActivityFilter = new ActivityFilter(
        new ComponentName(this, ExpandedActivity.class),
        null
      );
      
    2. Filtreyi bir filtre grubuna ekleyin:

      Kotlin

      val expandedActivityFilterSet = setOf(expandedActivityFilter)
      

      Java

      Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>();
      expandedActivityFilterSet.add(expandedActivityFilter);
      
    3. ActivityRule oluşturun:

      Kotlin

      val activityRule = ActivityRule.Builder(expandedActivityFilterSet)
          .setAlwaysExpand(true)
          .build()
      

      Java

      ActivityRule activityRule = new ActivityRule.Builder(
          expandedActivityFilterSet
      ).setAlwaysExpand(true)
       .build();
      

      ActivityRule.Builder, kuralı oluşturur ve yapılandırır:

      • expandedActivityFilterSet: Bölümlerden hariç tutmak istediğiniz etkinlikleri tanımlayarak kuralın ne zaman uygulanacağını belirleyen etkinlik filtrelerini içerir.
      • setAlwaysExpand: Etkinliğin görev penceresinin tamamını doldurup doldurmayacağını belirtir.
    4. Kuralı WindowManager RuleController içine ekleyin:

      Kotlin

      ruleController.addRule(activityRule)
      

      Java

      ruleController.addRule(activityRule);
      

Uygulamalar arası yerleştirme

Android 13 (API düzeyi 33) ve sonraki sürümlerde uygulamalar, diğer uygulamalardaki etkinlikleri yerleştirebilir. Uygulamalar arası veya UID'si için etkinlik yerleştirme, birden çok Android uygulamasındaki etkinliklerin görsel entegrasyonunu sağlar. Sistem, ana makine uygulamanın bir etkinliğini ve başka bir uygulamadaki yerleşik etkinliği, tek uygulama etkinlik yerleştirmede olduğu gibi ekranda yan yana veya üstte ve altta gösterir.

Örneğin, Ayarlar uygulaması, Wallpaper Picker uygulamasından duvar kağıdı seçici etkinliği yerleştirebilir:

Şekil 14. Yerleşik etkinlik olarak duvar kağıdı seçicinin (sağda) yer aldığı Ayarlar uygulaması (soldaki menü).

Güven modeli

Diğer uygulamalardaki etkinliklerin yerleştirildiği ana makine işlemleri, yerleştirilmiş etkinliklerin sunumunu (boyut, konum, kırpma ve şeffaflık gibi) yeniden tanımlayabilir. Kötü amaçlı barındırıcılar, bu özelliği kullanıcıları yanıltmak, tıklama korsanlığı veya kullanıcı arayüzünü iyileştirmeye yönelik başka saldırılar oluşturmak için kullanabilir.

Android, uygulamalar arası etkinlik yerleştirme özelliğinin kötüye kullanılmasını önlemek için uygulamaların, etkinliklerinin yerleştirilmesine izin verme özelliğini etkinleştirmesini zorunlu kılar. Uygulamalar, ana makineleri güvenilir veya güvenilmeyen olarak atayabilir.

Güvenilir ana makineler

Diğer uygulamaların, uygulamanızdaki etkinliklerin sunumunu yerleştirmesine ve tamamen kontrol etmesine izin vermek için uygulamanızın manifest dosyasındaki <activity> veya <application> öğelerinin android:knownActivityEmbeddingCerts özelliğinde ana makine uygulamasının SHA-256 sertifikasını belirtin.

android:knownActivityEmbeddingCerts değerini bir dize olarak ayarlayın:

<activity
    android:name=".MyEmbeddableActivity"
    android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
    ... />

veya birden fazla sertifika belirtmek için bir dize dizisi:

<activity
    android:name=".MyEmbeddableActivity"
    android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
    ... />

aşağıdaki gibi bir kaynağa referans verir:

<resources>
    <string-array name="known_host_certificate_digests">
      <item>cert1</item>
      <item>cert2</item>
      ...
    </string-array>
</resources>

Uygulama sahipleri, Gradle signingReport görevini çalıştırarak SHA sertifikası özeti alabilir. Sertifika özeti, ayırıcı iki nokta olmadan SHA-256 parmak izidir. Daha fazla bilgi için İmzalama raporu çalıştırma ve İstemcinizin Kimliğini Doğrulama başlıklı makaleleri inceleyin.

Güvenilmeyen ana makineler

Herhangi bir uygulamanın, uygulamanızın etkinliklerini yerleştirmesine ve bunların sunularını kontrol etmesine izin vermek için uygulama manifestindeki <activity> veya <application> öğelerinde android:allowUntrustedActivityEmbedding özelliğini belirtin. Örneğin:

<activity
    android:name=".MyEmbeddableActivity"
    android:allowUntrustedActivityEmbedding="true"
    ... />

Özelliğin varsayılan değeri false'tur. Bu, uygulamalar arası etkinlik yerleştirmeyi engeller.

Özel kimlik doğrulama

Güvenilir olmayan etkinlik yerleştirme riskini azaltmak için ana makine kimliğini doğrulayan özel bir kimlik doğrulama mekanizması oluşturun. Ana makine sertifikalarını biliyorsanız kimlik doğrulaması için androidx.security.app.authenticator kitaplığını kullanın. Ana makine, etkinliğinizi yerleştirdikten sonra kimlik doğrulaması yaparsa gerçek içeriği görüntüleyebilirsiniz. Değilse kullanıcıyı işleme izin verilmediğini bildirebilir ve içeriği engelleyebilirsiniz.

Bir ana makinenin etkinliğinizi yerleştirip yerleştirmediğini kontrol etmek için Jetpack WindowManager kitaplığındaki ActivityEmbeddingController#isActivityEmbedded() yöntemini kullanın. Örneğin:

Kotlin

fun isActivityEmbedded(activity: Activity): Boolean {
    return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity)
}

Java

boolean isActivityEmbedded(Activity activity) {
    return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity);
}

Minimum boyut kısıtlaması

Android sistemi, yerleştirilmiş etkinliklere uygulama manifesti <layout> öğesinde belirtilen minimum yükseklik ve genişliği uygular. Bir uygulama minimum yükseklik ve genişliği belirtmezse sistem varsayılan değerleri (sw220dp) geçerli olur.

Ana makine, yerleştirilmiş kapsayıcıyı minimum değerden daha küçük bir boyuta yeniden boyutlandırmaya çalışırsa, yerleştirilmiş kapsayıcı genişleyerek tüm görev sınırlarını kaplar.

<activity-alias>

Güvenilen veya güvenilir olmayan etkinlik yerleştirmenin <activity-alias> öğesiyle çalışması için hedef etkinliğe takma ad yerine android:knownActivityEmbeddingCerts veya android:allowUntrustedActivityEmbedding uygulanmalıdır. Sistem sunucusundaki güvenliği doğrulayan politika, takma ada değil, hedef üzerinde ayarlanan flag'lere dayanır.

Ana makine uygulaması

Ana makine uygulamaları, uygulamalar arası etkinlik yerleştirme işlemini, tek uygulama etkinliği yerleştirmeyi uyguladığı şekilde uygular. SplitPairRule ve SplitPairFilter veya ActivityRule ve ActivityFilter nesneleri, yerleştirilmiş etkinlikleri ve görev penceresi bölmelerini belirtir. Bölme kuralları, XML'de statik olarak veya çalışma zamanında Jetpack WindowManager API çağrıları kullanılarak tanımlanır.

Bir ana makine uygulaması, uygulamalar arası yerleştirmenin etkinleştirilmediği bir etkinliği yerleştirmeye çalışırsa bu etkinlik tüm görev sınırlarını kaplar. Sonuç olarak, barındıran uygulamaların hedef etkinliklerin uygulamalar arası yerleştirmeye izin verip vermediğini bilmesi gerekir.

Yerleştirilmiş bir etkinlik, aynı görevde yeni bir etkinlik başlatırsa ve yeni etkinlik, uygulamalar arası yerleştirmenin etkinleştirilmesini seçmemişse bu etkinlik, yerleştirilmiş kapsayıcının içine yerleştirmek yerine görev sınırlarının tamamını kaplar.

Bir barındırma uygulaması, etkinlikler aynı görevde başlatıldığı sürece kendi etkinliklerini herhangi bir kısıtlama olmadan yerleştirebilir.

Bölme örnekleri

Tam pencereden ayır

Şekil 15. A etkinliği, B etkinliğini yan tarafta başlatır.

Yeniden düzenleme gerekmez. Bölme yapılandırmasını statik olarak veya çalışma zamanında tanımlayabilir ve ardından ek parametre olmadan Context#startActivity() çağrısı yapabilirsiniz.

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Varsayılan olarak böl

Bir uygulamanın açılış sayfası, büyük ekranlarda iki kapsayıcıya bölünecek şekilde tasarlandığında, her iki etkinlik de aynı anda oluşturulup sunulduğunda kullanıcı deneyimi en iyi düzeye ulaşır. Bununla birlikte, kullanıcı birincil kapsayıcıdaki etkinlikle etkileşimde bulunana kadar (örneğin, kullanıcı gezinme menüsünden bir öğe seçene) kadar, bölmenin ikincil kapsayıcısı için içerik kullanılamayabilir. İçerik, bölmenin ikincil kapsayıcısında gösterilene kadar boşluğu bir yer tutucu etkinliği doldurabilir (yukarıdaki Yer tutucular bölümüne bakın).

Şekil 16. Bölme, iki etkinliğin aynı anda açılmasıyla oluşturuldu. Etkinliklerden biri yer tutucudur.

Yer tutucuyla bölme oluşturmak için bir yer tutucu oluşturun ve bunu birincil etkinlikle ilişkilendirin:

<SplitPlaceholderRule
    window:placeholderActivityName=".PlaceholderActivity">
    <ActivityFilter
        window:activityName=".MainActivity"/>
</SplitPlaceholderRule>

Bir uygulama bir amaç aldığında, hedef etkinlik, etkinlik bölümünün ikincil bölümü olarak gösterilebilir (örneğin, listedeki bir öğeyle ilgili bilgiler içeren bir ayrıntı ekranı gösterme isteği). Küçük ekranlarda ayrıntı, tam görev penceresinde, daha büyük cihazlarda listenin yanında gösterilir.

Şekil 17. Derin bağlantı ayrıntısı etkinliği küçük bir ekranda tek başına, ancak büyük bir ekranda liste etkinliğiyle birlikte gösterilir.

Başlatma isteği ana etkinliğe yönlendirilmeli ve hedef ayrıntısı etkinliği bölünmüş bir şekilde başlatılmalıdır. Sistem, mevcut ekran genişliğine göre doğru sunuyu (yığılmış veya yan yana) otomatik olarak seçer.

Kotlin

override fun onCreate(savedInstanceState Bundle?) {
    . . .
    RuleController.getInstance(this)
        .addRule(SplitPairRule.Builder(filterSet).build())
    startActivity(Intent(this, DetailActivity::class.java))
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    . . .
    RuleController.getInstance(this)
        .addRule(new SplitPairRule.Builder(filterSet).build());
    startActivity(new Intent(this, DetailActivity.class));
}

Derin bağlantı hedefi, geri gezinme yığınında kullanıcının kullanabileceği tek etkinlik olabilir ve ayrıntı etkinliğini kapatmaktan ve yalnızca ana etkinliği bırakmaktan kaçınmak isteyebilirsiniz:

Liste etkinliği ile ayrıntı etkinliğini yan yana gösteren büyük ekran.
          Geri gezinme, ayrıntı etkinliklerini kapatamadı ve liste etkinliğini ekranda bırakamadı.

Yalnızca ayrıntılı etkinlik içeren küçük ekran. Geri gezinme, ayrıntı etkinliklerini kapatamadı ve liste etkinliğini gösteremedi.

Bunun yerine, finishPrimaryWithSecondary özelliğini kullanarak her iki etkinliği aynı anda tamamlayabilirsiniz:

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".ListActivity"
        window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>

Aşağıdaki Yapılandırma özellikleri bölümüne bakın.

Bölünmüş kapsayıcılarda birden fazla etkinlik

Birden fazla etkinliği bölünmüş bir container'da yığmak, kullanıcıların derin içeriğe erişebilmesini sağlar. Örneğin, liste-ayrıntı bölmesi kullanıldığında kullanıcının bir alt ayrıntı bölümüne girmesi, ancak birincil etkinliği yerinde tutması gerekebilir:

Şekil 18. Etkinlik, görev penceresinin ikincil bölmesinde açıldı.

Kotlin

class DetailActivity {
    . . .
    fun onOpenSubDetail() {
      startActivity(Intent(this, SubDetailActivity::class.java))
    }
}

Java

public class DetailActivity {
    . . .
    void onOpenSubDetail() {
        startActivity(new Intent(this, SubDetailActivity.class));
    }
}

Alt ayrıntı etkinliği ayrıntı etkinliğinin üzerine yerleştirilir ve gizlenir:

Kullanıcı daha sonra yığında geri giderek önceki ayrıntı düzeyine geri dönebilir:

Şekil 19. Etkinlik, grubun en üstünden kaldırıldı.

Etkinlikler aynı ikincil kapsayıcıdaki bir etkinlikten başlatıldığında varsayılan davranış, etkinliklerin üst üste yığılmasıdır. Etkin bir bölümdeki birincil kapsayıcıdan başlatılan etkinlikler de etkinlik yığınının en üstündeki ikincil kapsayıcıda yer alır.

Yeni bir görevdeki etkinlikler

Bölünmüş görev penceresindeki etkinlikler yeni bir görevde etkinlik başlattığında, yeni görev bölümü içeren görevden ayrıdır ve tam pencerede gösterilir. Son kullanılanlar ekranında iki görev gösterilir: Bölünmüş görev ve yeni görev.

Şekil 20. Yeni bir görevde C etkinliğini B etkinliğinden başlatın.

Etkinlik değişimi

Etkinlikler, ikincil kapsayıcı yığınında değiştirilebilir. Örneğin, birincil etkinlik üst düzey gezinme için kullanıldığında ve ikincil etkinlik seçilen hedef olduğunda. Üst düzey gezinmedeki her seçim, ikincil kapsayıcıda yeni bir etkinlik başlatmalı ve daha önce orada bulunan etkinlikleri veya etkinlikleri kaldırmalıdır.

Şekil 21. Birincil bölmedeki üst düzey gezinme etkinliği, ikincil bölmedeki hedef etkinliklerinin yerini alır.

Gezinme seçimi değiştiğinde uygulama ikincil kapsayıcıdaki etkinliği bitiremezse bölme daraltıldığında (cihaz katlanmışken) geri gezinme kafa karıştırıcı olabilir. Örneğin, birincil bölmede bir menünüz ve ikincil bölmede de A ile B ekranları yığın halindeyse, kullanıcı telefonu kattığında B, A'nın üzerinde, A da menünün üzerindedir. Kullanıcı B'den geri döndüğünde, menü yerine A görünür.

Bu gibi durumlarda A ekranı arka yığından kaldırılmalıdır.

Yeni bir kapsayıcıda mevcut bir bölme yerine yeni bir kapsayıcı kullanıma sunulurken varsayılan davranış, yeni ikincil kapsayıcıları üste koyup arka yığındaki eskileri tutmaktır. Bölmeleri, clearTop ile önceki ikincil kapsayıcıları temizleyip yeni etkinlikleri normal şekilde başlatacak şekilde yapılandırabilirsiniz.

<SplitPairRule
    window:clearTop="true">
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenA"/>
    <SplitPairFilter
        window:primaryActivityName=".Menu"
        window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>

Kotlin

class MenuActivity {
    . . .
    fun onMenuItemSelected(selectedMenuItem: Int) {
        startActivity(Intent(this, classForItem(selectedMenuItem)))
    }
}

Java

public class MenuActivity {
    . . .
    void onMenuItemSelected(int selectedMenuItem) {
        startActivity(new Intent(this, classForItem(selectedMenuItem)));
    }
}

Alternatif olarak, aynı ikincil etkinliği kullanın ve birincil (menü) etkinlikten, aynı örneğe çözümlenen ancak ikincil kapsayıcıda durum veya kullanıcı arayüzü güncellemesini tetikleyen yeni amaçlar gönderin.

Çoklu bölme

Uygulamalar yan tarafta ek etkinlikler başlatarak çok düzeyli derin gezinme sağlayabilir.

İkincil bir kapsayıcıdaki etkinlik, tarafta yeni bir etkinlik başlattığında mevcut bölmenin üzerinde yeni bir bölme oluşturulur.

Şekil 22. B etkinliği C etkinliğini yan tarafta başlatır.

Arka yığın, daha önce açılmış tüm etkinlikleri içerir. Böylece kullanıcılar, C işlemini bitirdikten sonra A/B bölümüne gidebilir.

Bir yığındaki A, B ve C etkinlikleri. Etkinlikler yukarıdan aşağıya doğru şu şekilde sıralanır: C, B, A.

Yeni bir bölme oluşturmak için yeni etkinliği mevcut ikincil kapsayıcıdan yan tarafta başlatın. Hem A/B hem de B/C bölümleri için yapılandırmaları bildirin ve C etkinliğini B'den normal bir şekilde başlatın:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
    <SplitPairFilter
        window:primaryActivityName=".B"
        window:secondaryActivityName=".C"/>
</SplitPairRule>

Kotlin

class B {
    . . .
    fun onOpenC() {
        startActivity(Intent(this, C::class.java))
    }
}

Java

public class B {
    . . .
    void onOpenC() {
        startActivity(new Intent(this, C.class));
    }
}

Bölünme durumu değişikliklerine tepki verme

Bir uygulamadaki farklı etkinlikler, aynı işlevi gerçekleştiren kullanıcı arayüzü öğelerine (örneğin, hesap ayarlarını içeren bir pencereyi açan kontrol) sahip olabilir.

Şekil 23. İşlevsel olarak aynı kullanıcı arayüzü öğelerine sahip farklı etkinlikler.

Ortak bir kullanıcı arayüzü öğesine sahip iki etkinlik bir bölmedeyse öğenin her iki etkinlikte de gösterilmesi gereksizdir ve kafa karıştırıcı olabilir.

Şekil 24. Etkinlik bölümünde yinelenen kullanıcı arayüzü öğeleri.

Etkinliklerin ne zaman bölündüğünü öğrenmek için SplitController.splitInfoList akışını kontrol edin veya bölme durumundaki değişiklikleri SplitControllerCallbackAdapter ile görmek üzere bir işleyici kaydedin. Ardından, kullanıcı arayüzünü uygun şekilde ayarlayın:

Kotlin

val layout = layoutInflater.inflate(R.layout.activity_main, null)
val view = layout.findViewById<View>(R.id.infoButton)
lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        splitController.splitInfoList(this@SplitDeviceActivity) // The activity instance.
            .collect { list ->
                view.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE
            }
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    . . .
    new SplitControllerCallbackAdapter(SplitController.getInstance(this))
        .addSplitListener(
            this,
            Runnable::run,
            splitInfoList -> {
                View layout = getLayoutInflater().inflate(R.layout.activity_main, null);
                layout.findViewById(R.id.infoButton).setVisibility(
                    splitInfoList.isEmpty() ? View.VISIBLE : View.GONE);
            });
}

Eş yordamlar herhangi bir yaşam döngüsü durumunda başlatılabilir, ancak kaynakları korumak için genellikle STARTED durumunda başlatılır (daha fazla bilgi için Yaşam döngüsüne duyarlı bileşenlerle Kotlin eş yordamlarını kullanma bölümüne bakın).

Geri çağırmalar, bir etkinliğin durdurulduğu zamanlar da dahil olmak üzere herhangi bir yaşam döngüsü durumunda yapılabilir. Dinleyiciler genellikle onStart() dahilinde kayıtlı olmalı ve onStop() konumunda kayıtlı olmamalıdır.

Tam pencere kalıcı pencere

Bazı etkinlikler, giriş ekranı etkinliği, politika onay ekranı veya hata mesajı gibi belirli bir işlem yapılana kadar kullanıcıların uygulamayla etkileşimde bulunmasını engeller. Kalıcı etkinliklerin bölmede görünmesi önlenmelidir.

Bir etkinlik, genişletme yapılandırmasını kullanarak görev penceresini her zaman doldurmaya zorlanabilir:

<ActivityRule
    window:alwaysExpand="true">
    <ActivityFilter
        window:activityName=".FullWidthActivity"/>
</ActivityRule>

Etkinlikleri tamamlayın

Kullanıcılar, ekranın kenarından hızlıca kaydırarak bölmenin her iki tarafındaki etkinlikleri tamamlayabilir:

Şekil 25. Kaydırma hareketi, B etkinliğini bitirir.
Şekil 26. Kaydırma hareketi A etkinliğini bitirir.

Cihaz, hareketle gezinme yerine geri düğmesini kullanacak şekilde ayarlanmışsa giriş, odaklanılan etkinliğe (en son dokunulan veya başlatılan etkinlik) gönderilir.

Bir kapsayıcıdaki tüm etkinliklerin sonlandırılmasının karşı kapsayıcı üzerindeki etkisi, bölme yapılandırmasına bağlıdır.

Yapılandırma özellikleri

Bölmenin bir tarafındaki tüm etkinlikleri bitirmenin, bölünmenin diğer tarafındaki etkinlikleri nasıl etkileyeceğini yapılandırmak için bölme çifti kuralı özelliklerini belirtebilirsiniz. Özellikler şunlardır:

  • window:finishPrimaryWithSecondary: İkincil kapsayıcıda tüm etkinliklerin tamamlanması birincil kapsayıcıdaki etkinlikleri nasıl etkiler?
  • window:finishSecondaryWithPrimary: Birincil kapsayıcıdaki tüm etkinliklerin tamamlanması ikincil kapsayıcıdaki etkinlikleri nasıl etkiler?

Özelliklerin olası değerleri şunlardır:

  • always: Etkinlikleri her zaman ilişkili kapsayıcıda tamamlayın
  • never: İlişkili kapsayıcıdaki etkinlikleri hiçbir zaman tamamlama
  • adjacent: İki kapsayıcı yan yana görüntülendiğinde (iki kapsayıcı yığıldığında değil) ilişkili kapsayıcıdaki etkinlikleri bitirin

Örnek:

<SplitPairRule
    <!-- Do not finish primary container activities when all secondary container activities finish. -->
    window:finishPrimaryWithSecondary="never"
    <!-- Finish secondary container activities when all primary container activities finish. -->
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Varsayılan yapılandırma

Bölmenin bir kapsayıcısındaki tüm etkinlikler sona erdiğinde, kalan kapsayıcı tüm pencereyi kaplar:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

A ve B etkinliklerini içeren bölüm. A işlemi tamamlanmıştır. B, tüm pencereyi kaplayacak şekilde kalır.

A ve B etkinliklerini içeren bölüm. B işlemi tamamlanmıştır. A, tüm pencereyi kaplayacak şekilde
          kalır.

Etkinlikleri birlikte tamamlayın

İkincil kapsayıcıdaki tüm etkinlikler tamamlandığında birincil kapsayıcıdaki etkinlikleri otomatik olarak tamamlayın:

<SplitPairRule
    window:finishPrimaryWithSecondary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

A ve B etkinliklerini içeren bölüm. B de tamamlanmış olur. Bu da A işlemini tamamlayarak görev penceresini boş bırakır.

A ve B etkinliklerini içeren bölüm. A tamamlanır. B, görev penceresinde yalnız kalır.

Birincil kapsayıcıdaki tüm etkinlikler tamamlandığında ikincil kapsayıcıdaki etkinlikleri otomatik olarak tamamlayın:

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

A ve B etkinliklerini içeren bölüm. A da tamamlanmış olur. Bu da B işlemini tamamlayarak görev penceresini boş bırakır.

A ve B etkinliklerini içeren bölüm. B tamamlanır. A işlemini görev penceresinde yalnız bırakırsınız.

Birincil veya ikincil kapsayıcıdaki tüm etkinlikler tamamlandığında etkinlikleri birlikte tamamlayın:

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

A ve B etkinliklerini içeren bölüm. A da tamamlanmış olur. Bu da B işlemini tamamlayarak görev penceresini boş bırakır.

A ve B etkinliklerini içeren bölüm. B de tamamlanmış olur. Bu da A işlemini tamamlayarak görev penceresini boş bırakır.

Kapsayıcılarda birden fazla etkinliği tamamlama

Birden fazla etkinlik bölünmüş bir kapsayıcıda yığılmışsa bir etkinliğin yığının altında tamamlanması, etkinlikleri otomatik olarak en üstte tamamlamaz.

Örneğin, ikincil kapsayıcıda iki etkinlik varsa, B'nin üstündeki C:

B etkinliğini içeren C etkinliğini içeren ikincil etkinlik yığını, A etkinliğini içeren ana etkinlik yığınının üzerine yerleştirilir.

Bölüm yapılandırması, A ve B etkinliklerinin yapılandırmasıyla tanımlanır:

<SplitPairRule>
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

en büyük etkinliğin tamamlanması bölünmeyi sürdürüyor.

Birincil kapsayıcıda A etkinliği, ikincil kapsayıcıda B ve C etkinlikleri, B&#39;nin üzerine ise C etkinliğiyle ayırın. A ve B, etkinlik bölmesinde kalır.

İkincil kapsayıcının alt (kök) etkinliğini tamamlamak, üstteki etkinlikleri kaldırmaz ve böylece bölme işlemini de korur.

Birincil kapsayıcıda A etkinliği, ikincil kapsayıcıda B ve C etkinlikleri, B&#39;nin üzerine ise C etkinliğiyle ayırın. A ve C etkinlik bölmesinde kalır.

İkincil etkinlikleri birincil etkinlikle tamamlamak gibi, etkinliklerin birlikte tamamlanması için ek kurallar da yürütülür:

<SplitPairRule
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Birincil kapsayıcıda A etkinliğiyle, ikincil kapsayıcıda B ve C etkinlikleriyle, C ise B&#39;nin üzerine yığılır. A bitirir, de B ve C&#39;yi bitirir.

Bölme, birincil ve ikincil bölümleri birlikte bitirecek şekilde yapılandırıldığında:

<SplitPairRule
    window:finishPrimaryWithSecondary="always"
    window:finishSecondaryWithPrimary="always">
    <SplitPairFilter
        window:primaryActivityName=".A"
        window:secondaryActivityName=".B"/>
</SplitPairRule>

Birincil kapsayıcıda A etkinliği, ikincil kapsayıcıda B ve C etkinlikleri, B&#39;nin üzerine ise C etkinliğiyle ayırın. A ve B, etkinlik bölmesinde kalır.

Birincil kapsayıcıda A etkinliği, ikincil kapsayıcıda B ve C etkinlikleri, B&#39;nin üzerine ise C etkinliğiyle ayırın. A ve C etkinlik bölmesinde kalır.

Birincil kapsayıcıda A etkinliği, ikincil kapsayıcıda B ve C etkinlikleri, B&#39;nin üzerine ise C etkinliğiyle ayırın. A, B ve C&#39;yi de bitirir.

Çalışma zamanında bölünmüş özellikleri değiştirme

O anda etkin olan ve görünür bir bölünmenin özellikleri değiştirilemez. Bölme kurallarının değiştirilmesi, ek etkinlik başlatmaları ve yeni kapsayıcıları etkiler, ancak mevcut ve etkin bölümleri etkilemez.

Aktif bölümlerin özelliklerini değiştirmek için bölümdeki yan etkinliği veya aktiviteleri tamamlayın ve yeni bir yapılandırmayla yan tarafa başlayın.

Bir etkinliği bölünmüş pencereden tam pencereye çıkarma

Yan etkinlik tam penceresini gösteren yeni bir yapılandırma oluşturun ve ardından aynı örneğe çözümlenen bir niyetle etkinliği yeniden başlatın.

Çalışma zamanında bölünmüş desteği kontrol etme

Etkinlik yerleştirme özelliği, Android 12L (API düzeyi 32) ve sonraki sürümlerde desteklenir ancak önceki platform sürümlerini çalıştıran bazı cihazlarda da kullanılabilir. Çalışma zamanında özelliğin kullanılabilir olup olmadığını kontrol etmek için SplitController.splitSupportStatus özelliğini veya SplitController.getSplitSupportStatus() yöntemini kullanın:

Kotlin

if (SplitController.getInstance(this).splitSupportStatus ==
     SplitController.SplitSupportStatus.SPLIT_AVAILABLE) {
     // Device supports split activity features.
}

Java

if (SplitController.getInstance(this).getSplitSupportStatus() ==
     SplitController.SplitSupportStatus.SPLIT_AVAILABLE) {
     // Device supports split activity features.
}

Bölmeler desteklenmiyorsa etkinlikler, etkinlik yığınının üzerinde başlatılır (etkinlik olmayan yerleştirme modelinden sonra).

Sistemde geçersiz kılmayı önle

Android cihaz üreticileri (özgün donanım üreticileri veya OEM'ler), cihaz sisteminin bir işlevi olarak etkinlik yerleştirme özelliğini uygulayabilir. Sistem, çoklu etkinlik uygulamaları için bölme kurallarını belirleyerek uygulamaların pencere davranışını geçersiz kılar. Sistem geçersiz kılması, çok etkinlikli uygulamaları sistem tanımlı etkinlik yerleştirme moduna zorlar.

Sistem etkinliği yerleştirme, uygulamada herhangi bir değişiklik yapılmadan list-detail gibi çok bölmeli düzenler aracılığıyla uygulama sunumunu iyileştirebilir. Ancak, sistemin etkinlik yerleştirme işlemi de yanlış uygulama düzenlerine, hatalara veya uygulama tarafından uygulanan etkinlik yerleştirmeyle çakışmalara neden olabilir.

Uygulamanız, uygulama manifest dosyasında bir özellik ayarlayarak sistem etkinliği yerleştirmeyi engelleyebilir veya bunlara izin verebilir. Örneğin:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <property
            android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
            android:value="true|false" />
    </application>
</manifest>

Özellik adı, Jetpack WindowManager WindowProperties nesnesinde tanımlanır. Uygulamanız etkinlik yerleştirmeyi uyguluyorsa veya sistemin etkinlik yerleştirme kurallarını uygulamanıza uygulamasını engellemek istiyorsanız değeri false olarak ayarlayın. Sistemin, sistem tanımlı etkinlik yerleştirme işlemini uygulamanıza uygulayabilmesi için değeri true olarak ayarlayın.

Sınırlamalar, kısıtlamalar ve uyarılar

  • Yalnızca görevdeki kök etkinliğin sahibi olarak tanımlanan görevin ana makine uygulaması, göreve diğer etkinlikleri düzenleyebilir ve yerleştirebilir. Yerleştirme ve bölmeleri destekleyen etkinlikler farklı bir uygulamaya ait görevde çalışırsa yerleştirme ve bölmeler bu etkinlikler için çalışmaz.
  • Aktiviteler yalnızca tek bir görev içinde düzenlenebilir. Yeni bir görevde bir etkinlik başlatmak, onu her zaman mevcut bölümlerin dışında yeni bir genişletilmiş pencereye yerleştirir.
  • Yalnızca aynı süreçte yer alan etkinlikler düzenlenebilir ve bölümlere ayrılabilir. Farklı süreçlerdeki etkinlikleri bilmek mümkün olmadığından, SplitInfo geri çağırması yalnızca aynı sürece ait etkinlikleri raporlar.
  • Her çift veya tekil etkinlik kuralı, yalnızca kural kaydedildikten sonra gerçekleşen etkinlik başlatmaları için geçerlidir. Şu anda mevcut bölmeleri veya görsel özelliklerini güncellemenin bir yolu yoktur.
  • Bölünmüş çift filtre yapılandırması, etkinlikler tamamen başlatılırken kullanılan amaçlarla eşleşmelidir. Eşleştirme, uygulama işleminden yeni bir etkinlik başlatıldığında ortaya çıkar. Bu nedenle, örtülü amaçlar kullanılırken sistem işleminin ilerleyen aşamalarında çözümlenen bileşen adlarını bilmeyebilir. Başlatma sırasında bir bileşen adı bilinmiyorsa bunun yerine joker karakter ("*/*") kullanılabilir ve amaç işlemine göre filtreleme yapılabilir.
  • Şu anda etkinlikleri, container'lar arasında veya oluşturulduktan sonra bölümlerin içine ve dışına taşımak mümkün değildir. Bölmeler yalnızca eşleşen kurallara sahip yeni etkinlikler başlatıldığında windowManager kitaplığı tarafından oluşturulur ve bölmeler, bölünmüş bir container'daki son etkinlik tamamlandığında yok edilir.
  • Yapılandırma değiştiğinde etkinlikler yeniden başlatılabilir. Böylece, bir bölüm oluşturulduğunda veya kaldırıldığında ve etkinlik sınırları değiştiğinde, etkinlik önceki örneğin tamamen yok edilerek yeni bir örneğin oluşturulması gerçekleştirilebilir. Sonuç olarak uygulama geliştiriciler, yaşam döngüsü geri çağırma yoluyla yeni etkinlikler başlatmak gibi konularda dikkatli olmalıdır.
  • Cihazların, etkinlik yerleştirmeyi desteklemek için pencere uzantıları arayüzünü içermesi gerekir. Android 12L (API düzeyi 32) veya sonraki sürümleri çalıştıran büyük ekranlı cihazların neredeyse hepsi bu arayüze sahiptir. Ancak, birden fazla etkinlik çalıştıramayan bazı büyük ekranlı cihazlarda pencere uzantıları arayüzü bulunmaz. Büyük ekranlı bir cihaz çoklu pencere modunu desteklemiyorsa cihaz etkinlik yerleştirmeyi desteklemiyor olabilir.

Ek kaynaklar