Umieszczanie aktywności optymalizuje aplikacje na urządzeniach z dużym ekranem, dzieląc między 2 działaniami lub 2 instancjami tego samego działania.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/settings_app.png?authuser=0000&hl=pl)
Jeśli aplikacja składa się z wielu aktywności, umieszczanie aktywności umożliwia zwiększenie wygody użytkowników na tabletach, urządzeniach składanych i urządzeniach z ChromeOS.
Umieszczanie aktywności nie wymaga refaktoryzacji kodu. Sposób wyświetlania działań w aplikacji – obok siebie lub w stosunku do siebie – możesz określić, tworząc plik konfiguracji XML lub wywołując interfejs API Jetpack WindowManager.
Obsługa małych ekranów jest obsługiwana automatycznie. Gdy aplikacja jest na i urządzenia z małym ekranem, aktywności są nakładane jeden na drugi. Wł. na dużych ekranach, aktywności są wyświetlane obok siebie. System określa prezentacji na podstawie utworzonej przez Ciebie konfiguracji – bez rozgałęziania niezbędna jest logika.
Umieszczanie aktywności pozwala uwzględnić zmianę orientacji urządzenia i płynnie działa na urządzeniach składanych, układaj je i rozkładaj podczas składania i rozkładania.
Umieszczanie aktywności jest obsługiwane na większości urządzeń z dużymi ekranami z Androidem 12L (poziom interfejsu API 32) lub nowszym.
Okno podziału zadania
Osadzanie aktywności dzieli okno zadań aplikacji na 2 kontenery: główny drugorzędne. Kontenery zawierają działania uruchomione z głównej aktywności lub z innych aktywności znajdujących się już w kontenerach.
Działania są grupowane w kontenerze dodatkowym w miarę ich uruchamiania. kontener dodatkowy jest umieszczony nad głównym kontenerem Dzięki temu dodawanie aktywności i nawigacja wstecz uporządkowanie aktywności już wbudowanych w aplikację.
Umieszczanie aktywności umożliwia prezentowanie aktywności na różne sposoby. Aplikacja może podzielić okno zadania, uruchamiając 2 aktywności obok siebie jednocześnie:
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/a_b.png?authuser=0000&hl=pl)
Działanie, które zajmuje całe okno zadania, może też spowodować podział według rozpoczyna nowe działanie obok:
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/a_to_a_b.png?authuser=0000&hl=pl)
Działania, które są już podzielone i udostępniają okno zadania, mogą zostać uruchomione inne rodzaje aktywności:
Obok innej aktywności:
Rysunek 4. Aktywność A rozpoczyna aktywność C na boku względem aktywności B. Przesuń podział na bok, ukrywając poprzednią aktywność główną:
Rysunek 5. Ćwiczenie B rozpoczyna aktywność C na bok i przesuwa dzielą się na bok. Uruchamianie aktywności u góry. czyli w ramach tego samego stosu aktywności:
Rysunek 6. Aktywność B rozpoczyna działanie C bez dodatkowych flag intencji. Uruchom pełne okno aktywności w ramach tego samego zadania:
Rysunek 7. Aktywność A lub B rozpoczyna aktywność C, która wypełnia w oknie zadania.
Nawigacja wstecz
Różne rodzaje aplikacji mogą mieć różne reguły przechodzenia wstecz podziału okna zadań w zależności od zależności między działaniami lub jak użytkownicy wywołują zdarzenie wstecz, na przykład:
- Łączenie: jeśli działania są ze sobą powiązane i jeden z nich nie powinien być wyświetlany bez drugiego, można skonfigurować nawigację wstecz, aby dokończyć oba.
- Jeśli czynności są w pełni niezależne: jeśli czynności są w pełni niezależne, przejdź wstecz po działanie nie ma wpływu na stan innej aktywności w oknie zadania.
Gdy używasz przycisku, zdarzenie cofania jest wysyłane do ostatnio zaznaczonego działania nawigacji. Przy nawigowaniu przy użyciu gestów zdarzenie wstecz jest wysyłane do aktywność, podczas której został wykonany gest.
Układ z kilkoma panelami
Jetpack WindowManager umożliwia budowanie układu aktywności w kilku panelach na urządzeniach z dużym ekranem z Androidem 12L (poziom interfejsu API 32) lub nowszym oraz na niektórych urządzeniach z wcześniejszymi wersjami platformy. Istniejące aplikacje, które opierają się na wielu działaniach, a nie na fragmentach, lub w układach opartych na widokach (np. SlidingPaneLayout
), mogą zapewnić użytkownikom lepsze wrażenia na dużym ekranie bez refaktoryzacji kodu źródłowego.
Typowym przykładem jest podział według listy. Aby zapewnić wysoką jakość prezentacji, system rozpoczyna działanie związane z listą, a następnie aplikacja natychmiast rozpoczyna aktywność związaną z szczegółami. System przejścia oczekuje na narysowanie obu działań, a następnie wyświetla je razem. Z punktu widzenia użytkownika te 2 działania są uruchamiane jako jedna.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/launcher_to_list-detail.png?authuser=0000&hl=pl)
Atrybuty podziału
Możesz określić proporcje okna zadania między podzielonymi kontenerami i rozmieszczenie kontenerów.
W przypadku reguł zdefiniowanych w pliku konfiguracji XML ustaw te atrybuty:
splitRatio
: ustawia proporcje kontenera. Wartość jest liczbą zmiennoprzecinkową w otwartym przedziale czasu (0,0, 1,0).splitLayoutDirection
: określa układ podzielonych kontenerów względem siebie. Dostępne wartości:ltr
: od lewej do prawejrtl
: od prawej do lewejlocale
: wartośćltr
lubrtl
jest określana na podstawie ustawienia lokalnego.
Przykłady znajdziesz w sekcji Konfiguracja XML poniżej.
W przypadku reguł utworzonych przy użyciu interfejsów WindowManager API utwórz obiekt SplitAttributes
za pomocą SplitAttributes.Builder
i wywołaj te metody kreatora:
setSplitType()
: ustawia proporcje podzielonych kontenerów. Prawidłowe argumenty (w tym metodaSplitAttributes.SplitType.ratio()
) znajdziesz w sekcjiSplitAttributes.SplitType
.setLayoutDirection()
: ustawia układ kontenerów. Możliwe wartości znajdziesz na stronieSplitAttributes.LayoutDirection
.
Przykłady znajdziesz poniżej w sekcji WindowManager API.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/a_b_vs_a_b.png?authuser=0000&hl=pl)
Obiekty zastępcze
Aktywności zastępcze to puste aktywności dodatkowe, które zajmują obszar podział aktywności. Z czasem mają zostać zastąpione innym aktywność, która zawiera treści. Może to być na przykład aktywność zastępcza zajmują drugą stronę podziału aktywności w układzie z szczegółami listy do czasu element z listy zostanie wybrany, co spowoduje, że działanie zawierające szczegółowe informacje o wybranym elemencie listy zastępują obiekt zastępczy.
Domyślnie system wyświetla obiekty zastępcze tylko wtedy, gdy jest wystarczająco dużo miejsca na podział aktywności. Symbole zastępcze są automatycznie uzupełniane, gdy rozmiar wyświetlacza zmieni się na szerokość lub wysokość zbyt małą, aby można było wyświetlić podział. Jeśli jest wystarczająco dużo miejsca, system ponownie uruchamia obiekt zastępczy w stanie inicjowania.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/placeholder_finished_recreated.png?authuser=0000&hl=pl)
Atrybut stickyPlaceholder
metody SplitPlaceholderRule
lub setSticky()
SplitPlaceholder.Builder
może jednak zastąpić działanie domyślne. Gdy atrybut lub metoda określa wartość true
, system wyświetla obiekt zastępczy jako najwyższą aktywność w oknie zadania, gdy rozmiar wyświetlacza zostaje zmieniony z wyświetlacza z 2 panelami do rozmiaru ekranu z jednym panelem (przykład znajdziesz w sekcji Konfiguracja podziału).
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/placeholder_sticky.png?authuser=0000&hl=pl)
Zmiana rozmiaru okna
Zmiana konfiguracji urządzenia powoduje zmniejszenie szerokości okna zadań, aby nie jest dostatecznie duży, aby zmieścić się w układzie z kilkoma panelami (np. gdy duży ekran jest duży Urządzenie składa się, gdy składa się zmienionych w trybie wielu okien), aktywności niezastępczych w obszarze dodatkowym. okno zadania znajduje się nad działaniami w panel.
Aktywności zastępcze są wyświetlane tylko wtedy, gdy mają wystarczającą szerokość obrazu podzielić dane. Na mniejszych ekranach symbol zastępczy jest automatycznie zamykany. Kiedy obszar wyświetlania ponownie stanie się dostatecznie duży, i zostanie utworzony obiekt zastępczy. (Patrz sekcja Obiekty zastępcze powyżej).
Grupowanie aktywności jest możliwe, ponieważ WindowManager ustawia kolejność elementów na osi Z w panelu dodatkowym nad działaniami w panelu głównym.
Wiele działań w panelu dodatkowym
Działanie B rozpoczyna działanie C bez dodatkowych flag intencji:
w kolejności wykonywania działań w tej kolejności:
W mniejszym oknie zadania aplikacja zmniejsza się do pojedynczego działania, z C na górze stosu:
Przejście z powrotem w mniejszym oknie powoduje przejście między nałożonymi aktywnościami jedna nad drugą.
Jeśli konfiguracja okna zadań zostanie przywrócona do większego rozmiaru, i mieści się w wielu panelach, aktywności są ponownie wyświetlane obok siebie.
Skumulowane podziały
Ćwiczenie B rozpoczyna aktywność C na bok i przesuwa podział w bok:
Efektem jest wykonywanie działań w tej kolejności w tej kolejności:
W mniejszym oknie zadania aplikacja zmniejsza się do pojedynczego działania z C na górze:
Stała orientacja pionowa
Ustawienie w pliku manifestu android:screenOrientation pozwala aplikacjom ograniczać czynności do orientacji pionowej lub poziomej. Aby zwiększyć wygodę użytkowników korzystających z urządzeń z dużym ekranem, takich jak tablety i urządzenia składane, producenci urządzeń (OEM) mogą ignorować żądania orientacji ekranu i letterbox, gdy aplikacja ma orientację pionową lub poziomą na wyświetlaczach pionowych.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/a_letterboxed_portrait_and_landscape.png?authuser=0000&hl=pl)
Podobnie po włączeniu umieszczania aktywności na dużych ekranach (szerokość ≥ 600 dp) dostawcy mogą dostosowywać urządzenia do zdjęć poziomych i pionowych. Gdy stały portret powoduje uruchomienie drugiej aktywności, urządzenie może wyświetlić te aktywności obok siebie na wyświetlaczu z 2 panelami.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/a_letterboxed_portrait_to_a_b.png?authuser=0000&hl=pl)
Zawsze dodawaj właściwość android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
do pliku manifestu aplikacji, aby poinformować urządzenia, że aplikacja obsługuje umieszczanie aktywności (zobacz Konfiguracja podziału poniżej). Urządzenia dostosowane do potrzeb OEM mogą wtedy określić, czy mają być używane stałe pasy pionowe.
Podziel konfigurację
Reguły podziału służą do konfigurowania podziałów aktywności. Reguły podziału definiuje się w pliku konfiguracji XML lub przez wywołania interfejsu API Jetpack WindowManager.
W obu przypadkach aplikacja musi mieć dostęp do biblioteki WindowManager i musi informować system, że aplikacja ma zaimplementowane umieszczanie aktywności.
Wykonaj te czynności:
Dodaj najnowszą zależność biblioteki WindowManager do pliku
build.gradle
na poziomie modułu aplikacji, na przykład:implementation 'androidx.window:window:1.1.0-beta02'
Biblioteka WindowManager zawiera wszystkie komponenty wymagane do umieszczania aktywności.
Poinformuj system, że w Twojej aplikacji jest zaimplementowane umieszczanie aktywności.
Dodaj właściwość
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
do <application> pliku manifestu aplikacji i ustaw wartość true, np.:<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>
W usłudze WindowManager w wersji 1.1.0-alpha06 i nowszych podziały osadzonych aktywności są wyłączone, chyba że właściwość została dodana do pliku manifestu i ma wartość true (prawda).
Oprócz tego producenci urządzeń używają tego ustawienia do włączania niestandardowych funkcji w aplikacjach, które obsługują umieszczanie aktywności. Na przykład urządzenia mogą wyświetlać aktywność w trybie poziomym tylko w orientacji pionowej na wyświetlaczu poziomym, aby ukierunkować aktywność na potrzeby przejścia na układ z 2 panelami po rozpoczęciu drugiej aktywności (patrz Stała orientacja pionowa).
Konfiguracja XML
Aby utworzyć opartą na XML implementację wektora dystrybucyjnego aktywności, wykonaj te czynności:
Utwórz plik zasobów XML, który:
- Definiuje działania o wspólnym podziale
- Konfiguruje opcje podziału
- Tworzy obiekt placeholder dla dodatkowego kontenera podziału, gdy treść jest niedostępna
- Określa działania, które nigdy nie powinny być częścią podziału
Na przykład:
<!-- 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>
Utwórz inicjator.
Komponent WindowManager
RuleController
analizuje plik konfiguracji XML i udostępnia reguły w systemie. Biblioteka startowaInitializer
Jetpacka udostępnia plik XMLRuleController
podczas uruchamiania aplikacji, dzięki czemu reguły są stosowane po rozpoczęciu dowolnych działań.Aby utworzyć inicjator, wykonaj te czynności:
Dodaj najnowszą zależność biblioteki Jetpack Startup do pliku
build.gradle
na poziomie modułu, na przykład:implementation 'androidx.startup:startup-runtime:1.1.1'
Utwórz klasę, która implementuje interfejs
Initializer
.Inicjator udostępnia reguły podziału w usłudze
RuleController
, przekazując identyfikator pliku konfiguracji XML (main_split_config.xml
) do metodyRuleController.parseRules()
.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(); } }
Utwórz dostawcę treści dla definicji reguł.
Dodaj
androidx.startup.InitializationProvider
do pliku manifestu aplikacji jako<provider>
. Dodaj odwołanie do implementacji inicjatoraRuleController
(SplitInitializer
):<!-- 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
wykrywa i inicjujeSplitInitializer
przed wywołaniem metodyonCreate()
aplikacji. Z tego powodu reguły podziału obowiązują po rozpoczęciu głównej aktywności w aplikacji.
Interfejs API WindowManager
Umieszczanie aktywności możesz zaimplementować automatycznie za pomocą kilku wywołań interfejsu API. Wywołuj metodę onCreate()
w podklasie Application
, aby mieć pewność, że reguły zaczną obowiązywać przed uruchomieniem działań.
Aby automatycznie utworzyć podział aktywności:
Utwórz regułę podziału:
Utwórz
SplitPairFilter
wskazujący działania, które należą do tego samego podziału: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 );
Dodaj filtr do zestawu filtrów:
Kotlin
val filterSet = setOf(splitPairFilter)
Java
Set<SplitPairFilter> filterSet = new HashSet<>(); filterSet.add(splitPairFilter);
Utwórz atrybuty układu na potrzeby podziału:
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
tworzy obiekt zawierający atrybuty układu:setSplitType
: określa sposób przydzielania dostępnego obszaru do każdego kontenera aktywności. Typ podziału współczynnika określa część dostępnego obszaru wyświetlania przydzielonego do kontenera głównego. kontener dodatkowy zajmuje pozostałą część dostępnego obszaru wyświetlania.setLayoutDirection
: określa układ kontenerów aktywności względem siebie nawzajem – kontenera głównego.
Tworzenie
SplitPairRule
: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
tworzy i konfiguruje regułę:filterSet
: zawiera filtry par podzielonych, które określają, kiedy zastosować regułę, identyfikując aktywności o takim samym podziale.setDefaultSplitAttributes
: stosuje atrybuty układu do reguły.setMinWidthDp
: ustawia minimalną szerokość wyświetlacza (w pikselach niezależnych od gęstości, dp), która umożliwia podział danych.setMinSmallestWidthDp
: określa minimalną wartość (w dp), jaką musi mieć mniejsza z tych 2 wymiarów wyświetlania, aby umożliwić podział bez względu na orientację urządzenia.setMaxAspectRatioInPortrait
: ustawia maksymalny format obrazu (wysokość:szerokość) w orientacji pionowej, przy którym są wyświetlane podziały aktywności. Jeśli format obrazu pionowego przekracza maksymalny współczynnik proporcji, podziały są wyłączone niezależnie od szerokości ekranu. Uwaga: wartość domyślna to 1,4, co na większości tabletów zajmuje całe okno zadania w orientacji pionowej. Zobacz teżSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
isetMaxAspectRatioInLandscape
. Wartość domyślna w przypadku orientacji poziomej toALWAYS_ALLOW
.setFinishPrimaryWithSecondary
: określa, jak ukończenie wszystkich działań w kontenerze dodatkowym wpływa na działania w kontenerze głównym.NEVER
wskazuje, że system nie powinien kończyć działań głównych po zakończeniu wszystkich działań w kontenerze dodatkowym (patrz Kończenie działań).setFinishSecondaryWithPrimary
: określa, jak ukończenie wszystkich działań w kontenerze głównym wpływa na działania w kontenerze dodatkowym.ALWAYS
oznacza, że system powinien zawsze kończyć działania w kontenerze dodatkowym po zakończeniu wszystkich działań w kontenerze głównym (patrz Kończenie działań).setClearTop
: określa, czy wszystkie działania w kontenerze dodatkowym zostaną zakończone po uruchomieniu w kontenerze nowej aktywności. Wartość Fałsz oznacza, że nowe działania są nakładane na działania znajdujące się już w kontenerze dodatkowym.
Pobierz instancję usługi WindowManager
RuleController
i dodaj do niej regułę:Kotlin
val ruleController = RuleController.getInstance(this) ruleController.addRule(splitPairRule)
Java
RuleController ruleController = RuleController.getInstance(this); ruleController.addRule(splitPairRule);
Utwórz obiekt zastępczy kontenera dodatkowego, gdy treść jest niedostępna:
Utwórz obiekt
ActivityFilter
identyfikujący aktywność, z którą obiekt zastępczy ma wspólny podział okien zadań:Kotlin
val placeholderActivityFilter = ActivityFilter( ComponentName(this, ListActivity::class.java), null )
Java
ActivityFilter placeholderActivityFilter = new ActivityFilter( new ComponentName(this, ListActivity.class), null );
Dodaj filtr do zestawu filtrów:
Kotlin
val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
Java
Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>(); placeholderActivityFilterSet.add(placeholderActivityFilter);
Tworzenie
SplitPlaceholderRule
: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
tworzy i konfiguruje regułę:placeholderActivityFilterSet
: zawiera filtry aktywności, które określają, kiedy zastosować regułę, identyfikując aktywności, z którymi powiązana jest aktywność zastępcza.Intent
: określa uruchomienie działania związanego z obiektem zastępczym.setDefaultSplitAttributes
: stosuje atrybuty układu do reguły.setMinWidthDp
: ustawia minimalną szerokość wyświetlacza (w pikselach niezależnych od gęstości, dp), która umożliwia podział danych.setMinSmallestWidthDp
: określa minimalną wartość (w dp), jaką musi być mniejszy z 2 wymiarów wyświetlacza, by umożliwić podział bez względu na orientację urządzenia.setMaxAspectRatioInPortrait
: ustawia maksymalny format obrazu (wysokość:szerokość) w orientacji pionowej, przy którym są wyświetlane podziały aktywności. Uwaga: wartość domyślna to 1,4, co na większości tabletów powoduje, że zadania wypełniają okno zadania w orientacji pionowej. Zobacz teżSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
isetMaxAspectRatioInLandscape
. Wartość domyślna w przypadku orientacji poziomej toALWAYS_ALLOW
.setFinishPrimaryWithPlaceholder
: określa, jak zakończenie działania obiektu zastępczego wpływa na działania w kontenerze głównym. ZAWSZE wskazuje, że system powinien zawsze kończyć działania w kontenerze głównym po zakończeniu działania symbolu zastępczego (patrz Kończenie działań).setSticky
: określa, czy aktywność zastępcza pojawia się na stosu aktywności na małych ekranach, gdy obiekt zastępczy pojawi się po raz pierwszy w części podziału z wystarczającą minimalną szerokością.
Dodaj regułę do interfejsu WindowManager
RuleController
:Kotlin
ruleController.addRule(splitPlaceholderRule)
Java
ruleController.addRule(splitPlaceholderRule);
Określ działania, które nigdy nie powinny być częścią podziału:
Utwórz obiekt
ActivityFilter
wskazujący aktywność, która zawsze powinna zajmować cały obszar wyświetlania zadań:Kotlin
val expandedActivityFilter = ActivityFilter( ComponentName(this, ExpandedActivity::class.java), null )
Java
ActivityFilter expandedActivityFilter = new ActivityFilter( new ComponentName(this, ExpandedActivity.class), null );
Dodaj filtr do zestawu filtrów:
Kotlin
val expandedActivityFilterSet = setOf(expandedActivityFilter)
Java
Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>(); expandedActivityFilterSet.add(expandedActivityFilter);
Tworzenie
ActivityRule
:Kotlin
val activityRule = ActivityRule.Builder(expandedActivityFilterSet) .setAlwaysExpand(true) .build()
Java
ActivityRule activityRule = new ActivityRule.Builder( expandedActivityFilterSet ).setAlwaysExpand(true) .build();
ActivityRule.Builder
tworzy i konfiguruje regułę:expandedActivityFilterSet
: zawiera filtry aktywności, które określają, kiedy zastosować regułę, identyfikując aktywności, które chcesz wykluczyć z podziałów.setAlwaysExpand
: określa, czy aktywność powinna wypełniać całe okno zadania.
Dodaj regułę do interfejsu WindowManager
RuleController
:Kotlin
ruleController.addRule(activityRule)
Java
ruleController.addRule(activityRule);
Umieszczanie treści z wielu aplikacji
Na Androidzie 13 (poziom interfejsu API 33) i nowszym aplikacje można umieszczać aktywności z innych aplikacji. Umieszczanie aktywności w różnych aplikacjach lub przez UID umożliwia wizualną integrację działań z wielu aplikacji na Androida. System wyświetla na ekranie obok siebie lub u góry i u dołu aktywność aplikacji hostującej i umieszczoną na niej aktywność z innej aplikacji, tak jak w przypadku umieszczania aktywności w pojedynczej aplikacji.
Na przykład aplikacja Ustawienia może umieścić aktywność selektora tapet z aplikacji TapPicker:
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/wallpaper_activity_embedded_in_settings_app.png?authuser=0000&hl=pl)
Model zaufania
Procesy hosta, w których umieszczone są działania z innych aplikacji, mogą na nowo zdefiniować sposób, w jaki te działania są prezentowane, w tym zmieniać rozmiar, położenie, przycinanie i przezroczystość. Złośliwe hosty mogą korzystać z tej funkcji, aby wprowadzać użytkowników w błąd i tworzyć clickjacking lub inne ataki mające na celu korygowanie działania interfejsu użytkownika.
Aby zapobiec niewłaściwemu używaniu umieszczania danych o aktywności w różnych aplikacjach, Android wymaga, aby aplikacje zezwalały na umieszczanie ich aktywności. Aplikacje mogą oznaczać hosty jako zaufane lub niezaufane.
Zaufane hosty
Aby umożliwić innym aplikacjom umieszczanie aktywności z Twojej aplikacji i pełną kontrolę nad ich prezentacją, podaj certyfikat SHA-256 aplikacji hosta w atrybucie android:knownActivityEmbeddingCerts
elementów <activity>
lub <application>
w pliku manifestu aplikacji.
Ustaw wartość android:knownActivityEmbeddingCerts
jako ciąg znaków:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
... />
lub, aby określić wiele certyfikatów, tablica ciągów znaków:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
... />
odwołujący się do zasobu takiego jak ten:
<resources>
<string-array name="known_host_certificate_digests">
<item>cert1</item>
<item>cert2</item>
...
</string-array>
</resources>
Właściciele aplikacji mogą uzyskać podsumowanie certyfikatu SHA, uruchamiając zadanie signingReport
Gradle. Skrót certyfikatu to odcisk cyfrowy SHA-256 bez dwukropków rozdzielających. Więcej informacji znajdziesz w artykułach na temat wygenerowania raportu podpisywania i uwierzytelniania klienta.
Niezaufane hosty
Aby umożliwić dowolnej aplikacji umieszczanie aktywności z aplikacji i kontrolowanie ich prezentacji, określ atrybut android:allowUntrustedActivityEmbedding
w elementach <activity>
lub <application>
w pliku manifestu aplikacji, na przykład:
<activity
android:name=".MyEmbeddableActivity"
android:allowUntrustedActivityEmbedding="true"
... />
Domyślna wartość tego atrybutu to „false”, co uniemożliwia umieszczanie aktywności w różnych aplikacjach.
Uwierzytelnianie niestandardowe
Aby ograniczyć ryzyko związane z umieszczaniem niezaufanych aktywności, utwórz niestandardowy mechanizm uwierzytelniania, który zweryfikuje tożsamość hosta. Jeśli znasz certyfikaty hosta, użyj biblioteki androidx.security.app.authenticator
do uwierzytelnienia. Jeśli host uwierzytelni się po umieszczeniu Twojej aktywności, możesz wyświetlić rzeczywiste treści. W przeciwnym razie możesz poinformować użytkownika, że działanie jest niedozwolone, i zablokować treści.
Użyj metody ActivityEmbeddingController#isActivityEmbedded()
z biblioteki Jetpack WindowManager, aby sprawdzić, czy host umieszcza Twoją aktywność, na przykład:
Kotlin
fun isActivityEmbedded(activity: Activity): Boolean { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity) }
Java
boolean isActivityEmbedded(Activity activity) { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity); }
Ograniczenie dotyczące minimalnego rozmiaru
Do umieszczonych aktywności system Android stosuje minimalną wysokość i szerokość określoną w elemencie <layout>
manifestu aplikacji. Jeśli aplikacja nie określa minimalnej wysokości i szerokości, obowiązują systemowe wartości domyślne (sw220dp
).
Jeśli host spróbuje zmienić rozmiar umieszczonego kontenera do rozmiaru mniejszego niż minimalny, ten kontener zostanie rozwinięty i zajmie całe granice zadania.
<alias-aktywności>
Aby umieszczanie zaufanych lub niezaufanych aktywności działało z elementem <activity-alias>
, do aktywności docelowej, a nie aliasu, należy zastosować android:knownActivityEmbeddingCerts
lub android:allowUntrustedActivityEmbedding
. Zasada sprawdzająca bezpieczeństwo serwera systemowego jest oparta na flagach ustawionych w środowisku docelowym, a nie na aliasie.
Aplikacja hosta
Aplikacje hostujące implementują osadzanie aktywności w różnych aplikacjach w taki sam sposób, w jaki implementują osadzanie aktywności w pojedynczej aplikacji. Obiekty SplitPairRule
i SplitPairFilter
lub ActivityRule
i ActivityFilter
określają umieszczone działania i podziały okien zadań. Reguły podziału definiuje się statycznie w formacie XML lub w czasie działania za pomocą wywołań interfejsu API Jetpack WindowManager.
Jeśli aplikacja hosta próbuje umieścić działanie, które nie ma włączonej opcji umieszczania w różnych aplikacjach, aktywność ta zajmuje cały obszar zadania. W związku z tym aplikacje hosta muszą wiedzieć, czy działania docelowe umożliwiają umieszczanie w różnych aplikacjach.
Jeśli osadzona aktywność rozpoczyna nowe działanie w ramach tego samego zadania, a nowe działanie nie ma włączonej opcji umieszczania w różnych aplikacjach, aktywność zajmuje cały zakres zadania, zamiast nakładać się na działanie w umieszczonym kontenerze.
Aplikacja hosta może osadzać własne działania bez ograniczeń, o ile działania są uruchamiane w tym samym zadaniu.
Przykłady podziału
Podziel od całego okna
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/a_to_a_b.png?authuser=0000&hl=pl)
Refaktoryzacja nie jest wymagana. Możesz zdefiniować konfigurację dla podziału
statycznie lub w czasie działania, a potem wywołaj
Context#startActivity()
bez dodatkowych parametrów.
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Podziel domyślnie
Gdy strona docelowa aplikacji jest zaprojektowana tak, aby dzieliła się na dwie części na dużych ekranach, zapewnia wygodę użytkownikom, gdy są tworzone i prezentowane jednocześnie. Treści te mogą jednak dostępne dla kontenera dodatkowego podziału, dopóki użytkownik nie wejdzie w interakcję z działaniem w kontenerze głównym (np. użytkownik wybiera w menu nawigacyjnym). Działanie tymczasowe może wypełnić lukę do momentu, może być wyświetlana w dodatkowym kontenerze podziału (patrz Obiekty zastępcze powyżej).
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/launcher_main_placeholder.png?authuser=0000&hl=pl)
Aby to zrobić, utwórz zmienną i powiąż ją z obiektem zastępczym z główną aktywnością:
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
Podział precyzyjnych linków
Gdy aplikacja otrzymuje intencję, działanie docelowe może być wyświetlane jako dodatkowa część podziału aktywności; np. żądanie wyświetlenia szczegółów, ekran z informacjami o elemencie z listy. Na małych ekranach szczegóły są wyświetlane w pełnym oknie zadania; na większych urządzeniach.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/deep_link_split.png?authuser=0000&hl=pl)
Prośba o uruchomienie powinna być kierowana do głównego działania, a docelowe działanie szczegółowe powinno zostać uruchomione w części. System automatycznie wybierze właściwą prezentację – ułożone w stos lub obok siebie – na podstawie dostępnej szerokości wyświetlania.
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)); }
Miejsce docelowe precyzyjnego linku może być jedyną dostępną aktywnością użytkownikowi w tylnym stosie nawigacyjnym i lepiej unikać odrzuceniem działania szczegółów i pozostawienie tylko aktywności głównej:
Możesz natomiast zakończyć obie aktywności w tym samym czasie, korzystając z
Atrybut finishPrimaryWithSecondary
:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
Patrz sekcja Atrybuty konfiguracji poniżej.
Wiele aktywności w podzielonych kontenerach
Gromadzenie wielu aktywności w podzielonym kontenerze umożliwia użytkownikom dostęp treści. Na przykład w przypadku podziału na szczegóły listy użytkownik może chcieć przejść do sekcji i zachować sekcję ze szczegółami, ale nie zmieniać głównej funkcji:
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/list-detail_to_list-sub-detail.png?authuser=0000&hl=pl)
Kotlin
class DetailActivity { . . . fun onOpenSubDetail() { startActivity(Intent(this, SubDetailActivity::class.java)) } }
Java
public class DetailActivity { . . . void onOpenSubDetail() { startActivity(new Intent(this, SubDetailActivity.class)); } }
Działanie podrzędne jest umieszczone nad działaniem szczegółów i jest ukrywane:
Użytkownik może wtedy wrócić do poprzedniego poziomu szczegółów, wracając do poprzedniego poziomu w ramach stosu:
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/list-sub-detail_to_list-detail.png?authuser=0000&hl=pl)
Nakładanie się działań na siebie jest domyślne. aktywności są uruchamiane z aktywności w tym samym kontenerze dodatkowym. Działania uruchomione z kontenera głównego w ramach aktywnego podziału również się kończą w kontenerze dodatkowym u góry stosu aktywności.
Działania w nowym zadaniu
Gdy działania w podzielonym oknie zadania rozpoczynają działania w nowym zadaniu, zadanie jest oddzielne od zadania, które obejmuje podział, i jest wyświetlane w całości okno. Ekran Ostatnie przedstawia dwa zadania: zadanie w podziale i nowe zadanie.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/task_1_to_task_2.png?authuser=0000&hl=pl)
Zastępowanie aktywności
Działania można zastępować w dodatkowym stosie kontenerów. na przykład gdy aktywność podstawowa służy do nawigacji najwyższego poziomu, a aktywność pomocnicza aktywność to wybrane miejsce docelowe. Każda opcja z listy najwyższego poziomu nawigacja powinna rozpocząć nową aktywność w kontenerze dodatkowym i usunąć wcześniejsze czynności.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/menu_screen_a_to_menu_screen_b.png?authuser=0000&hl=pl)
Jeśli aplikacja nie zakończy działania w kontenerze dodatkowym, gdy wybór nawigacji, przechodzenie wstecz może być mylące, gdy część podzielona jest zwinięta (po złożeniu urządzenia). Na przykład, jeśli masz w panelu głównym oraz na ekranach A i B nałożonych na stos w panelu dodatkowym. gdy użytkownik składa telefon, symbol B znajduje się na szczycie A, a A na górze menu. Gdy użytkownik wróci z poziomu B, zamiast menu pojawi się A.
W takich przypadkach ekran A musi zostać usunięty z tylnego stosu.
Domyślne zachowanie przy uruchamianiu z boku w nowym kontenerze przez
istniejący podział to umieszczenie nowych kontenerów dodatkowych na górze i zachowanie
te z tyłu. Możesz skonfigurować podziały, aby usunąć poprzedni
kontenery dodatkowe z clearTop
i uruchamiać nowe działania w normalny sposób.
<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))); } }
Możesz też użyć tej samej aktywności dodatkowej i z poziomu głównego (menu) aktywność wysyła nowe intencje, które docierają do tej samej instancji, ale wywołują lub aktualizację interfejsu użytkownika w kontenerze.
Wiele podziałów
Aplikacje mogą zapewniać głęboką nawigację na wielu poziomach, uruchamiając dodatkowe z bliska.
Gdy działanie w kontenerze dodatkowym uruchamia nową aktywność z boku, nowy podział danych zostanie utworzony w stosunku do istniejącego.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/a_b_to_b_c.png?authuser=0000&hl=pl)
Stos tylny zawiera wszystkie wcześniej otwierane działania, więc użytkownicy może przejść do podziału A/B po skończeniu C.
Aby utworzyć nowy podział, uruchom nową aktywność z boku istniejącego kontener dodatkowy. Zadeklaruj konfiguracje dla kategorii A/B i B/C dzieli się i uruchamia działanie C normalnie od B:
<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)); } }
Reagowanie na zmiany stanu podziału
Różne działania w aplikacji mogą mieć elementy interfejsu o identycznym działaniu funkcji; na przykład element sterujący, który otwiera okno z kontem ustawieniach.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/main_detail_with_ui_element.png?authuser=0000&hl=pl)
Jeśli 2 działania, które mają wspólny element interfejsu, są częścią przydziału, Zbędne i wprowadzające w błąd wyświetlanie elementu w obu działaniach.
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/main_detail_with_ui_element_duplicated.png?authuser=0000&hl=pl)
Aby dowiedzieć się, kiedy działania są podzielone, sprawdź proces SplitController.splitInfoList
lub zarejestruj detektor w SplitControllerCallbackAdapter
, aby sprawdzić zmiany stanu podziału. Następnie odpowiednio dostosuj interfejs:
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); }); }
Korutyny można uruchamiać w dowolnym stanie cyklu życia, ale zwykle są uruchamiane w stanie STARTED
, aby oszczędzać zasoby (więcej informacji znajdziesz w artykule o używaniu współrzędnych Kotlina z komponentami dostosowanymi do cyklu życia).
Wywołania zwrotne mogą być wykonywane w dowolnym stanie cyklu życia, w tym wtedy, gdy działanie jest
zatrzymano. Słuchacze powinni zwykle być zarejestrowani w tych krajach: onStart()
i
wyrejestrowano w: onStop()
.
Widok modalny z pełnym oknem
Niektóre działania uniemożliwiają użytkownikom interakcję z aplikacją do czasu wykonywane jest określone działanie; np. aktywność na ekranie logowania, zasady ekranu z potwierdzeniem lub komunikatem o błędzie. Aktywności modalne powinny być zablokowane przed podziałem.
Działanie może wymusić zawsze wypełnienie okna zadania za pomocą polecenia rozwijania Konfiguracja:
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
Kończenie działań
Użytkownicy mogą dokończyć aktywność po obu stronach podziału, przesuwając palcem od krawędzi wyświetlacza:
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/swipe_gesture_finish_b.png?authuser=0000&hl=pl)
![](https://developer.android.com/static/images/guide/topics/large-screens/activity-embedding/swipe_gesture_finish_a.png?authuser=0000&hl=pl)
Jeśli urządzenie zostało skonfigurowane do używania przycisku Wstecz zamiast nawigacji przy użyciu gestów, dane wejściowe są wysyłane do zaznaczonego działania – czynności, którego dotknięto, uruchomiono jako ostatnią.
Wpływ zakończenia wszystkich działań w kontenerze na kontener przeciwny zależy od konfiguracji podziału.
Atrybuty konfiguracji
Możesz określić atrybuty reguły podziału pary, aby określić, jak zakończenie wszystkich działań po jednej stronie podziału wpływa na aktywności po drugiej stronie podziału. Te atrybuty:
window:finishPrimaryWithSecondary
– jak zakończenie wszystkich działań w kontenerze dodatkowym wpływa na działania w kontenerze głównym.window:finishSecondaryWithPrimary
– jak zakończenie wszystkich działań w kontenerze głównym wpływa na działania w kontenerze dodatkowym.
Możliwe wartości atrybutów:
always
– zawsze kończ działania w powiązanym kontenerze.never
– nigdy nie dokończ działań w powiązanym kontenerze.adjacent
– dokończ działania w powiązanym kontenerze, gdy 2 kontenery są wyświetlane obok siebie, ale nie wtedy, gdy dwa kontenery są ustawione w stosie
Na przykład:
<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>
Konfiguracja domyślna
Gdy wszystkie działania w jednym kontenerze w ramach podzielonego zakończenia zajmują cały kontener, pozostały kontener zajmuje całe okno:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Wspólne kończenie działań
Automatycznie dokończ działania w kontenerze głównym, gdy wszystkie działania w kontenerze dodatkowym zostaną zakończone:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Automatycznie dokończ działania w kontenerze dodatkowym, gdy wszystkie działania w kontenerze głównym zostaną zakończone:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Zakończ działania razem, gdy zakończą się wszystkie działania w kontenerze głównym lub dodatkowym:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Kończenie wielu działań w kontenerach
Jeśli wiele aktywności znajduje się w dzielonym kontenerze, zakończenie danej aktywności znajdujące się na dole stosu nie kończy automatycznie działań na górze.
Jeśli na przykład w kontenerze dodatkowym znajdują się 2 działania, nadrzędne są działania C nad nimi:
a konfiguracja podziału jest zdefiniowana przez konfigurację zadania A i B:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
do zakończenia głównej aktywności zachowuje podział.
Zakończenie działania dolnego (głównego) kontenera dodatkowego nie powoduje usunąć wyświetlane na niej aktywności; więc zachowuje ten podział.
Wszelkie dodatkowe reguły dotyczące kończenia ćwiczeń razem, np. zakończenie. jest też wykonywane działanie dodatkowe z aktywnością główną:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Gdy podział zostanie skonfigurowany tak, aby zakończyć razem: główną i dodatkową:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Zmiana właściwości podziału w czasie działania
Nie można zmienić właściwości obecnie aktywnego i widocznego podziału. Zmiana reguł podziału ma wpływ na dodatkowe uruchomienia aktywności i nowe kontenery, a nie istniejące i aktywne podziały.
Aby zmienić właściwości aktywnych podziałów, zakończ aktywność dodatkową lub i uruchomić ponownie z nową konfiguracją.
Wyodrębnij aktywność z podzielonego do pełnego okna
Utwórz nową konfigurację, która wyświetli pełne okno aktywności bocznej. a następnie ponownie uruchom aktywność z intencją prowadzącą do tej samej instancji.
Sprawdzanie obsługi podziału w czasie działania
Umieszczanie aktywności jest obsługiwane na Androidzie 12L (poziom interfejsu API 32) i nowszych, ale jest też dostępne na niektórych urządzeniach z wcześniejszymi wersjami platformy. Aby sprawdzić dostępność funkcji w czasie działania, użyj właściwości SplitController.splitSupportStatus
lub metody SplitController.getSplitSupportStatus()
:
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. }
Jeśli podziały nie są obsługiwane, aktywności są uruchamiane na początku stosu aktywności (zgodnie z modelem umieszczania aktywności bez aktywności).
Zapobiegaj zastąpieniu systemu
producenci urządzeń z Androidem (producentom oryginalnego sprzętu; OEM) mogą wdrożyć umieszczanie aktywności jako funkcję systemu urządzeń. system określa reguły podziału dla aplikacji o wielu aktywnościach, zastępując ustawianie okien działanie aplikacji. Zastąpienie przez system wymusza na aplikacjach z wieloma aktywnościami zdefiniowany przez system tryb umieszczania aktywności.
Umieszczanie aktywności w systemie może uatrakcyjnić prezentację aplikacji przez wiele paneli układy, takie jak list-detail, bez żadnych zmian w aplikacji. Umieszczanie aktywności w systemie może jednak powodują również nieprawidłowe układy aplikacji, błędy lub konflikty z umieszczaniem aktywności implementowana przez aplikację.
Aplikacja może zablokować umieszczanie aktywności systemu lub zezwolić na to, ustawiając parametr property w pliku manifestu aplikacji np.:
<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>
Nazwa właściwości jest zdefiniowana w programie Jetpack WindowManager.
WindowWłaściwości.
Ustaw wartość false
, jeśli w Twojej aplikacji jest zaimplementowane umieszczanie aktywności lub
chcesz w inny sposób uniemożliwić systemowi stosowanie reguł umieszczania aktywności
do Twojej aplikacji. Ustaw wartość na true
, aby system mógł go zastosować.
zdefiniowane przez system aktywność w aplikacji.
Ograniczenia, ograniczenia i zastrzeżenia
- Tylko hostująca aplikacja zadania, która jest identyfikowana jako właściciel katalogu głównego może porządkować i umieszczać w zadaniu inne działania. Jeśli działania obsługujące umieszczanie i podziały są uruchamiane w zadaniu należącym do do innej aplikacji, osadzanie i podziały nie będą działać w przypadku tych działań.
- Czynności można uporządkować tylko w ramach jednego zadania. Uruchamianie działania w nowym zadaniu zawsze umieszcza je w nowym, rozszerzonym oknie poza żadnym istniejące podziały.
- Tylko działania w ramach tego samego procesu mogą być porządkowane i podzielone na segmenty.
SplitInfo
wywołanie zwrotne raportuje tylko działania należące do tego samego procesu, ponieważ nie ma możliwości sprawdzenia działań w różnych procesach. - Każda para lub pojedyncza reguła związana z aktywnością ma zastosowanie tylko do uruchomień aktywności, które następuje po zarejestrowaniu reguły. Obecnie nie ma możliwości aktualizować istniejących podziałów lub ich właściwości wizualnych.
- Konfiguracja filtra pary podzielonej musi pasować do intencji używanych, gdy całkowicie rozpocząć działania. Dopasowanie następuje w momencie, gdy nowy jest rozpoczynana w trakcie procesu zgłaszania, więc może nie wiedzieć o nazwy komponentów, które są rozpoznawane w dalszej części procesu systemowego przy użyciu funkcji niejawne intencje. Jeśli w momencie uruchomienia nazwa komponentu nie jest znana, zamiast niego można użyć symbolu wieloznacznego („*/*”), a filtrowanie na działanie intencji.
- Obecnie nie można przenosić działań między kontenerami ani do nich i z powrotem podziałów po ich utworzeniu. Podziały są tworzone tylko przez po uruchomieniu nowych działań z pasującymi regułami w bibliotece WindowManager, i podziały zostają zniszczone, gdy ostatnia aktywność w podzielonym kontenerze .
- Działania można uruchamiać ponownie po zmianie konfiguracji, np. w przypadku zostanie utworzony lub usunięty, a granice aktywności zmienią się, aktywność może przez całkowite zniszczenie poprzedniej instancji i utworzenie nowy. Dlatego deweloperzy aplikacji powinni uważać na: podczas uruchamiania nowych działań z wywołań zwrotnych cyklu życia.
- Urządzenia muszą mieć interfejs rozszerzeń okien, aby obsługiwać umieszczanie aktywności. Prawie wszystkie urządzenia z dużym ekranem z Androidem 12L (poziom interfejsu API 32) lub nowszym mają interfejs. Jednak niektóre urządzenia z dużym ekranem, które nie obsługują wielu aktywności, nie mają interfejsu rozszerzeń okien. Jeśli urządzenie z dużym ekranem nie obsługuje trybu wielu okien, może nie obsługiwać umieszczania aktywności.
Dodatkowe materiały
- Ćwiczenia z programowania – Tworzenie układu z opisem listy z wykorzystaniem umieszczania aktywności i interfejsu Material Design
- Ścieżka szkoleniowa – Umieszczanie modułów
Polecane dla Ciebie
- Uwaga: tekst linku wyświetla się, gdy JavaScript jest wyłączony
- Tworzenie układu z podziałem na listy z użyciem umieszczania aktywności i interfejsu Material Design
- Tryb zgodności urządzenia
- Obsługa trybu wielu okien