Penyematan aktivitas mengoptimalkan aplikasi di perangkat layar besar dengan membagi jendela tugas aplikasi antara dua aktivitas atau dua instance aktivitas yang sama.
Jika aplikasi Anda terdiri dari beberapa aktivitas, penyematan aktivitas memungkinkan Anda memberikan pengalaman pengguna yang ditingkatkan di tablet, perangkat foldable, dan perangkat ChromeOS.
Penyematan aktivitas tidak memerlukan pemfaktoran ulang kode. Anda menentukan bagaimana aplikasi menampilkan aktivitasnya—berdampingan atau ditumpuk—dengan membuat XML file konfigurasi atau dengan melakukan panggilan API Jetpack WindowManager.
Dukungan untuk layar kecil dikelola secara otomatis. Saat aplikasi Anda berada di perangkat yang memiliki layar berukuran kecil, aktivitas akan ditumpuk di atas aktivitas yang lain. Pada layar besar, aktivitas akan ditampilkan secara berdampingan. Sistem menentukan presentasi berdasarkan konfigurasi yang telah Anda buat—tidak ada logika percabangan tidak diperlukan.
Penyematan aktivitas mengakomodasi perubahan orientasi perangkat dan berfungsi dengan lancar pada perangkat foldable, menumpuk dan membongkar aktivitas saat perangkat melipat dan akan terungkap.
Penyematan aktivitas didukung di sebagian besar perangkat layar besar yang menjalankan Android 12L (level API 32) dan yang lebih tinggi.
Jendela pemisahan tugas
Penyematan aktivitas memisahkan jendela tugas aplikasi menjadi dua penampung: primer dan sekunder. Penampung menyimpan aktivitas yang diluncurkan dari aktivitas utama atau dari aktivitas lain yang sudah ada di penampung.
Aktivitas ditumpuk di penampung sekunder saat diluncurkan, dan penampung sekunder ditumpuk di atas penampung utama pada layar kecil sehingga penumpukan aktivitas dan navigasi kembali konsisten dengan pengurutan aktivitas yang sudah ada di dalam aplikasi.
Dengan penyematan aktivitas tersebut, Anda menampilkan aktivitas dalam berbagai cara. Nama aplikasi dapat memisahkan jendela tugas dengan meluncurkan dua aktivitas secara berdampingan secara bersamaan:
Atau, aktivitas yang menempati seluruh jendela tugas dapat membuat pemisahan dengan meluncurkan aktivitas baru bersama:
Aktivitas yang sudah dipisah dan berbagi jendela tugas dapat meluncurkan aktivitas lain dengan cara berikut:
Ke samping di atas aktivitas lain:
Ke samping, dan menggeser pemisahan ke samping untuk menyembunyikan elemen aktivitas:
Meluncurkan aktivitas yang telah diterapkan di atas; yaitu, dalam tumpukan aktivitas yang sama:
Meluncurkan jendela penuh aktivitas dalam tugas yang sama:
Navigasi kembali
Jenis aplikasi yang berbeda dapat memiliki aturan navigasi kembali yang berbeda dalam memisahkan status jendela tugas tergantung pada dependensi antara aktivitas atau bagaimana pengguna memicu peristiwa kembali, misalnya:
- Bersama: Jika aktivitas terkait, dan salah satu tidak boleh ditampilkan tanpa yang lain, navigasi kembali dapat dikonfigurasi untuk menyelesaikan keduanya.
- Sendiri: Jika aktivitas sepenuhnya bersifat independen, navigasi kembali pada aktivitas tidak memengaruhi status aktivitas lain di jendela tugas.
Peristiwa kembali dikirim ke aktivitas yang terakhir difokuskan saat menggunakan navigasi tombol.
Untuk navigasi berbasis gestur:
Android 14 (API level 34) dan yang lebih rendah — Peristiwa kembali dikirim ke aktivitas tempat gestur terjadi. Saat pengguna menggeser dari sisi kiri layar, peristiwa kembali dikirim ke aktivitas di sisi kiri di jendela terpisah. Saat pengguna menggeser dari sisi kanan layar, peristiwa kembali akan dikirim ke aktivitas di panel sebelah kanan.
Android 15 (level API 35) dan yang lebih tinggi
Saat menangani beberapa aktivitas dari aplikasi yang sama, gestur akan menyelesaikan aktivitas teratas, terlepas dari arah geser, sehingga memberikan pengalaman yang lebih terpadu.
Dalam skenario yang melibatkan dua aktivitas dari aplikasi yang berbeda (overlay), peristiwa kembali diarahkan ke aktivitas terakhir yang difokuskan, selaras dengan perilaku navigasi tombol.
Tata letak multi-panel
Jetpack WindowManager memungkinkan Anda membuat aktivitas yang menyematkan multipanel
tata letak pada perangkat layar besar dengan Android 12L (API level 32) atau yang lebih baru dan aktif
beberapa perangkat dengan
versi platform sebelumnya. Aplikasi yang sudah ada berdasarkan beberapa
aktivitas, bukan fragmen atau tata letak berbasis tampilan seperti
SlidingPaneLayout
dapat memberikan pengalaman pengguna yang lebih baik di layar besar
tanpa memfaktorkan ulang kode sumber.
Salah satu contoh umumnya adalah pemisahan detail daftar. Untuk memastikan presentasi berkualitas tinggi, sistem akan memulai aktivitas daftar, lalu aplikasi akan segera memulai aktivitas detail. Sistem transisi menunggu hingga aktivitas digambar, lalu menampilkannya secara bersamaan. Bagi pengguna, kedua aktivitas tersebut akan diluncurkan sebagai satu aktivitas.
Atribut pemisahan
Anda dapat menentukan cara jendela tugas disejajarkan dengan antara penampung pemisahan dan bagaimana container disusun relatif terhadap satu sama lain.
Untuk aturan yang ditentukan dalam file konfigurasi XML, tetapkan atribut berikut:
splitRatio
: Menetapkan proporsi penampung. Nilainya berupa floating point angka dalam interval terbuka (0.0, 1.0).splitLayoutDirection
: Menentukan cara penampung pemisahan disusun secara relatif terhadap satu sama lain. Nilai mencakup:ltr
: Kiri ke kananrtl
: Kanan ke kirilocale
:ltr
ataurtl
ditentukan dari setelan lokalitas
Lihat bagian Konfigurasi XML untuk mengetahui contohnya.
Untuk aturan yang dibuat menggunakan WindowManager API, buat objek SplitAttributes
dengan SplitAttributes.Builder
dan panggil metode
builder berikut:
setSplitType()
: Menetapkan proporsi penampung pemisahan. LihatSplitAttributes.SplitType
untuk argumen yang valid, termasuk MetodeSplitAttributes.SplitType.ratio()
.setLayoutDirection()
: Menetapkan tata letak penampung. LihatSplitAttributes.LayoutDirection
untuk mengetahui kemungkinan nilai.
Lihat bagian WindowManager API untuk mengetahui contohnya.
Placeholder
Aktivitas placeholder adalah aktivitas sekunder kosong yang menempati area pemisahan aktivitas. Tujuannya agar aktivitas kosong tersebut diganti dengan aktivitas lain yang berisi konten. Misalnya, aktivitas {i>placeholder<i} bisa menempati sisi sekunder pemisahan aktivitas di tata letak daftar-detail hingga item dari daftar dipilih, yang pada saat itu aktivitas berisi detail informasi untuk item daftar yang dipilih akan menggantikan placeholder.
Secara default, sistem hanya menampilkan placeholder jika ada cukup ruang untuk pemisahan aktivitas. Placeholder otomatis selesai jika ukuran tampilan berubah menjadi lebar atau tinggi yang terlalu kecil untuk menampilkan pemisahan. Jika tempatnya memungkinkan, sistem meluncurkan kembali placeholder dengan status diinisialisasi ulang.
Namun, atribut stickyPlaceholder
dari metode SplitPlaceholderRule
atau
setSticky()
SplitPlaceholder.Builder
dapat mengganti
perilaku default. Jika atribut atau metode menentukan nilai true
, atribut
menampilkan {i>placeholder<i} sebagai aktivitas teratas di jendela tugas saat
ukuran layar diubah menjadi tampilan satu panel dari tampilan dua panel
(lihat Konfigurasi pemisahan untuk mengetahui contohnya).
Perubahan ukuran jendela
Saat perubahan konfigurasi perangkat, kurangi lebar jendela tugas agar tidak cukup besar untuk tata letak multipanel (misalnya, saat perangkat foldable layar besar perangkat dilipat dari ukuran tablet ke ukuran ponsel atau ukuran jendela aplikasi diubah mode multi-aplikasi), aktivitas non-placeholder di panel sekunder ditumpuk di atas aktivitas di panel utama.
Aktivitas placeholder hanya ditampilkan jika memiliki lebar tampilan yang cukup untuk pemisahan. Pada layar dengan ukuran lebih kecil, placeholder akan otomatis ditutup. Saat ukuran area layar menjadi cukup besar lagi, placeholder akan dibuat ulang. (Lihat bagian Placeholder.)
Penumpukan aktivitas dapat dilakukan karena WindowManager melakukan pengurutan z pada aktivitas di panel sekunder di atas aktivitas di panel utama.
Beberapa aktivitas di panel sekunder
Aktivitas B memulai aktivitas C tanpa flag intent tambahan:
yang menghasilkan aktivitas urutan z berikut dalam tugas yang sama:
Jadi, dalam jendela tugas yang lebih kecil, aplikasi akan dikecilkan satu aktivitas dengan C di bagian atas tumpukan:
Kembali ke jendela yang lebih kecil akan membuka aktivitas yang ditumpuk di atas aktivitas yang lain.
Jika konfigurasi jendela tugas dikembalikan ke ukuran lebih besar yang dapat mengakomodasi beberapa panel, aktivitas akan ditampilkan lagi secara berdampingan.
Pemisahan bertumpuk
Aktivitas B memulai aktivitas C ke samping dan menggeser pemisahan ke samping:
Hasilnya adalah aktivitas urutan z berikut dalam tugas yang sama:
Pada jendela tugas yang lebih kecil, aplikasi akan dikecilkan ke satu aktivitas dengan C pada atas:
Orientasi potret tetap
Setelan manifes android:screenOrientation memungkinkan aplikasi membatasi aktivitas menjadi orientasi potret atau lanskap. Untuk meningkatkan pengalaman pengguna di perangkat layar besar seperti tablet dan perangkat foldable, produsen perangkat (OEM) dapat mengabaikan permintaan orientasi layar dan menjadikan aplikasi tampilan lebar dalam mode potret orientasi pada tampilan lanskap atau orientasi lanskap pada tampilan potret.
Demikian pula, saat penyematan aktivitas diaktifkan, OEM dapat menyesuaikan perangkat ke aktivitas potret tetap tampilan lebar dalam orientasi lanskap di perangkat layar besar (lebar ≥ 600 dp). Saat aktivitas potret tetap meluncurkan aktivitas kedua, perangkat dapat menampilkan dua aktivitas secara berdampingan dalam tampilan dua panel.
Selalu tambahkan android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
ke file manifes aplikasi untuk memberi tahu perangkat yang didukung aplikasi Anda
penyematan aktivitas (lihat Konfigurasi pemisahan
). Perangkat yang disesuaikan OEM kemudian dapat menentukan apakah akan dijadikan tampilan lebar
aktivitas potret tetap.
Konfigurasi pemisahan
Aturan pemisahan mengonfigurasi pemisahan aktivitas. Anda menentukan aturan pemisahan dalam XML file konfigurasi atau dengan membuat Jetpack WindowManager API panggilan telepon.
Dalam kedua kasus tersebut, aplikasi harus mengakses library WindowManager dan harus memberi tahu aplikasi telah menerapkan penyematan aktivitas.
Lakukan hal berikut:
Menambahkan dependensi library WindowManager terbaru ke level modul aplikasi File
build.gradle
, misalnya:implementation 'androidx.window:window:1.1.0-beta02'
Library WindowManager menyediakan semua komponen yang diperlukan untuk aktivitas penyematan.
Beri tahu sistem bahwa aplikasi Anda telah menerapkan penyematan aktivitas.
Menambahkan properti
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
ke <application> file manifes aplikasi, dan mengatur dari nilai ke true, contohnya:<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>
Pada rilis WindowManager 1.1.0-alpha06 dan yang lebih baru, pemisahan penyematan aktivitas dinonaktifkan kecuali jika properti ditambahkan ke manifes dan ditetapkan ke true.
Juga, produsen perangkat menggunakan pengaturan untuk mengaktifkan kemampuan khusus untuk aplikasi yang mendukung penyematan aktivitas. Misalnya, perangkat dapat membuat tampilan lebar aktivitas khusus potret pada tampilan lanskap untuk mengorientasikan aktivitas untuk transisi ke tata letak dua panel saat aktivitas kedua dimulai (lihat Orientasi potret tetap).
Konfigurasi XML
Untuk membuat implementasi penyematan aktivitas berbasis XML, selesaikan langkah-langkah berikut:
Buat file resource XML yang melakukan hal berikut:
- Menentukan aktivitas yang membagikan pemisahan
- Mengonfigurasi opsi pemisahan
- Membuat placeholder untuk penampung sekunder pemisahan jika konten tidak tersedia
- Menentukan aktivitas yang tidak boleh menjadi bagian dari pemisahan
Contoh:
<!-- 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>
Buat penginisialisasi.
Komponen
RuleController
WindowManager menguraikan file konfigurasi XML dan membuat aturan tersedia untuk sistem. Library Jetpack StartupInitializer
membuat file XML tersedia untukRuleController
saat aplikasi dimulai sehingga aturan akan berlaku saat aktivitas dimulai.Untuk membuat penginisialisasi, lakukan hal berikut:
Menambahkan dependensi library Jetpack Startup terbaru ke level modul File
build.gradle
, misalnya:implementation 'androidx.startup:startup-runtime:1.1.1'
Buat class yang mengimplementasikan antarmuka
Initializer
.Penginisialisasi membuat aturan pemisahan tersedia untuk
RuleController
dengan meneruskan ID file konfigurasi XML (main_split_config.xml
) ke metodeRuleController.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(); } }
Membuat penyedia konten untuk definisi aturan.
Menambahkan
androidx.startup.InitializationProvider
ke file manifes aplikasi sebagai<provider>
. Sertakan referensi untuk penerapan PenginisialisasiRuleController
,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
menemukan dan melakukan inisialisasiSplitInitializer
sebelum metodeonCreate()
aplikasi dipanggil. Akibatnya, aturan pemisahan berlaku saat aktivitas utama aplikasi dimulai.
WindowManager API
Anda dapat mengimplementasikan penyematan aktivitas secara terprogram dengan beberapa panggilan
API. Melakukan panggilan di metode onCreate()
dari subclass
Application
untuk memastikan aturan berlaku sebelum aktivitas
diluncurkan.
Untuk membuat pemisahan aktivitas secara terprogram, lakukan hal berikut:
Buat aturan pemisahan:
Membuat
SplitPairFilter
yang mengidentifikasi aktivitas yang membagikan pemisahan: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 );
Tambahkan filter ke kumpulan filter:
Kotlin
val filterSet = setOf(splitPairFilter)
Java
Set<SplitPairFilter> filterSet = new HashSet<>(); filterSet.add(splitPairFilter);
Buat atribut tata letak untuk pemisahan:
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
membuat objek yang berisi atribut tata letak:setSplitType()
: Menentukan cara area tampilan yang tersedia yang dialokasikan ke setiap penampung aktivitas. Jenis pemisahan rasio menentukan proporsi area tampilan tersedia yang dialokasikan ke penampung utama; penampung sekunder menempati sisa area tampilan yang tersedia.setLayoutDirection()
: Menentukan cara penampung aktivitas disusun relatif terhadap satu sama lain, penampung utama terlebih dahulu.
Buat
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
membuat dan mengonfigurasi aturan:filterSet
: Berisi filter pasangan pemisahan yang menentukan kapan aturan diterapkan dengan mengidentifikasi aktivitas yang memiliki pemisahan yang sama.setDefaultSplitAttributes()
: Menerapkan atribut tata letak ke aturan.setMinWidthDp()
: Menetapkan lebar tampilan minimum (dalam piksel kepadatan mandiri, dp) yang memungkinkan pemisahan.setMinSmallestWidthDp()
: Menetapkan nilai minimum (dalam dp) yang ukuran yang lebih kecil dari dua dimensi tampilan harus memungkinkan terpisah, apa pun orientasi perangkatnya.setMaxAspectRatioInPortrait()
: Menetapkan rasio aspek tampilan maksimum (tinggi:lebar) dalam orientasi potret yang menampilkan pemisahan aktivitas. Jika rasio aspek tampilan potret melebihi rasio aspek maksimum, pemisahan akan dinonaktifkan terlepas dari lebar tampilan. Catatan: Nilai defaultnya adalah 1,4, yang menghasilkan aktivitas yang menempati seluruh jendela tugas dalam mode potret orientasi pada sebagian besar tablet. Lihat jugaSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
dansetMaxAspectRatioInLandscape()
. Nilai default untuk lanskap adalahALWAYS_ALLOW
.setFinishPrimaryWithSecondary()
: Menetapkan pengaruh penyelesaian semua aktivitas di penampung sekunder terhadap aktivitas di penampung utama.NEVER
menunjukkan sistem tidak boleh selesai di aktivitas utama ketika semua aktivitas di lingkungan sekunder penampung selesai (lihat Menyelesaikan aktivitas).setFinishSecondaryWithPrimary()
: Menetapkan pengaruh menyelesaikan semua aktivitas di penampung utama terhadap aktivitas di penampung sekunder.ALWAYS
menunjukkan bahwa sistem harus selalu menyelesaikan aktivitas dalam penampung sekunder saat semua aktivitas dalam penampung utama selesai (lihat Menyelesaikan aktivitas).setClearTop()
: Menentukan apakah semua aktivitas di penampung sekunder selesai saat aktivitas baru diluncurkan di container-nya. Nilaifalse
menentukan bahwa aktivitas baru ditumpuk di atas aktivitas yang sudah ada di penampung sekunder.
Dapatkan instance singleton WindowManager
RuleController
, dan tambahkan aturan:Kotlin
val ruleController = RuleController.getInstance(this) ruleController.addRule(splitPairRule)
Java
RuleController ruleController = RuleController.getInstance(this); ruleController.addRule(splitPairRule);
Buat placeholder untuk penampung sekunder saat konten tidak tersedia:
Buat
ActivityFilter
yang mengidentifikasi aktivitas yang digunakan placeholder untuk membagikan pemisahan jendela tugas:Kotlin
val placeholderActivityFilter = ActivityFilter( ComponentName(this, ListActivity::class.java), null )
Java
ActivityFilter placeholderActivityFilter = new ActivityFilter( new ComponentName(this, ListActivity.class), null );
Tambahkan filter ke kumpulan filter:
Kotlin
val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
Java
Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>(); placeholderActivityFilterSet.add(placeholderActivityFilter);
Buat
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
membuat dan mengonfigurasi aturan:placeholderActivityFilterSet
: Berisi filter aktivitas yang menentukan kapan aturan diterapkan dengan mengidentifikasi aktivitas yang terkait dengan aktivitas placeholder.Intent
: Menentukan peluncuran aktivitas placeholder.setDefaultSplitAttributes()
: Menerapkan atribut tata letak ke aturan.setMinWidthDp()
: Menetapkan lebar tampilan minimum (dalam piksel kepadatan mandiri, dp) yang memungkinkan pemisahan.setMinSmallestWidthDp()
: Menetapkan nilai minimum (dalam dp) yang lebih kecil dari kedua tampilan dimensi harus mengizinkan pemisahan, apa pun perangkatnya orientasi.setMaxAspectRatioInPortrait()
: Menetapkan rasio aspek tampilan maksimum (tinggi:lebar) dalam orientasi potret yang menampilkan pemisahan aktivitas. Catatan: nilai defaultnya adalah 1,4, yang menyebabkan aktivitas mengisi tugas dan jendela dalam orientasi potret di sebagian besar tablet. Lihat jugaSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
dansetMaxAspectRatioInLandscape()
. Nilai default untuk lanskap adalahALWAYS_ALLOW
.setFinishPrimaryWithPlaceholder()
: Menetapkan pengaruh penyelesaian aktivitas placeholder pada aktivitas di penampung utama. ALWAYS menunjukkan bahwa sistem harus selalu menyelesaikan aktivitas dalam penampung utama saat placeholder selesai (lihat Menyelesaikan aktivitas).setSticky()
: Menentukan apakah aktivitas placeholder akan muncul di atas tumpukan aktivitas pada tampilan layar kecil setelah placeholder pertama kali muncul dalam pemisahan dengan lebar minimum yang memadai.
Tambahkan aturan ke WindowManager
RuleController
:Kotlin
ruleController.addRule(splitPlaceholderRule)
Java
ruleController.addRule(splitPlaceholderRule);
Tentukan aktivitas yang tidak boleh menjadi bagian dari pemisahan:
Buat
ActivityFilter
yang mengidentifikasi aktivitas yang harus selalu menempati seluruh area tampilan tugas:Kotlin
val expandedActivityFilter = ActivityFilter( ComponentName(this, ExpandedActivity::class.java), null )
Java
ActivityFilter expandedActivityFilter = new ActivityFilter( new ComponentName(this, ExpandedActivity.class), null );
Tambahkan filter ke kumpulan filter:
Kotlin
val expandedActivityFilterSet = setOf(expandedActivityFilter)
Java
Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>(); expandedActivityFilterSet.add(expandedActivityFilter);
Buat
ActivityRule
:Kotlin
val activityRule = ActivityRule.Builder(expandedActivityFilterSet) .setAlwaysExpand(true) .build()
Java
ActivityRule activityRule = new ActivityRule.Builder( expandedActivityFilterSet ).setAlwaysExpand(true) .build();
ActivityRule.Builder
membuat dan mengonfigurasi aturan:expandedActivityFilterSet
: Berisi filter aktivitas yang menentukan kapan aturan diterapkan dengan mengidentifikasi aktivitas yang ingin Anda kecualikan dari pemisahan.setAlwaysExpand()
: Menentukan apakah aktivitas harus mengisi seluruh jendela tugas.
Tambahkan aturan ke WindowManager
RuleController
:Kotlin
ruleController.addRule(activityRule)
Java
ruleController.addRule(activityRule);
Penyematan lintas-aplikasi
Di Android 13 (API level 33) dan yang lebih baru, aplikasi dapat menyematkan aktivitas dari aplikasi lain. Penyematan aktivitas lintas-aplikasi, atau lintas-UID, memungkinkan integrasi visual aktivitas dari beberapa aplikasi Android. Sistem menampilkan aktivitas aplikasi host dan aktivitas tersemat dari aplikasi lain di layar secara berdampingan atau atas dan bawah seperti dalam penyematan aktivitas aplikasi tunggal.
Misalnya, aplikasi Setelan dapat menyematkan aktivitas pemilih wallpaper dari aplikasi WallpaperPicker:
Model kepercayaan
Proses host yang menyematkan aktivitas dari aplikasi lain dapat mendefinisikan ulang presentasi aktivitas tersemat, termasuk ukuran, posisi, pemangkasan, dan transparansi. Host berbahaya dapat menggunakan kemampuan ini untuk menyesatkan pengguna dan membuat serangan clickjacking atau penggantian UI lainnya.
Untuk mencegah penyalahgunaan penyematan aktivitas lintas aplikasi, Android mewajibkan aplikasi untuk memilih untuk memungkinkan penyematan aktivitas mereka. Aplikasi dapat menetapkan host sebagai tepercaya atau tidak dapat dipercaya.
Host tepercaya
Untuk mengizinkan aplikasi lain menyematkan dan mengontrol sepenuhnya presentasi
aktivitas dari aplikasi Anda, tentukan sertifikat SHA-256 aplikasi
host di atribut android:knownActivityEmbeddingCerts
dari
elemen <activity>
atau <application>
dari file manifes aplikasi Anda.
Setel nilai android:knownActivityEmbeddingCerts
sebagai string:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
... />
atau, untuk menentukan beberapa sertifikat, array string:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
... />
yang mereferensikan resource seperti berikut:
<resources>
<string-array name="known_host_certificate_digests">
<item>cert1</item>
<item>cert2</item>
...
</string-array>
</resources>
Pemilik aplikasi bisa mendapatkan ringkasan sertifikat SHA dengan menjalankan tugas
signingReport
Gradle. Ringkasan sertifikat adalah sidik jari SHA-256 tanpa
titik dua pemisah. Untuk mengetahui informasi selengkapnya, lihat Menjalankan laporan penandatanganan dan
Mengautentikasi Klien.
Host tidak tepercaya
Untuk mengizinkan aplikasi menyematkan aktivitas aplikasi dan mengontrol presentasinya,
tentukan atribut android:allowUntrustedActivityEmbedding
dalam
elemen <activity>
atau <application>
di manifes aplikasi, misalnya:
<activity
android:name=".MyEmbeddableActivity"
android:allowUntrustedActivityEmbedding="true"
... />
Nilai default atribut ini adalah false, yang mencegah penyematan aktivitas lintas-aplikasi.
Autentikasi kustom
Untuk mengurangi risiko penyematan aktivitas tidak tepercaya, buat
mekanisme otentikasi yang
memverifikasi identitas {i>host<i}. Jika Anda mengetahui sertifikat
host, gunakan library androidx.security.app.authenticator
untuk
melakukan autentikasi. Jika host mengautentikasi setelah aktivitas disematkan, Anda dapat
menampilkan konten yang sebenarnya. Jika tidak, Anda dapat memberi tahu
pengguna bahwa tindakan tersebut
tidak diizinkan dan memblokir konten tersebut.
Gunakan metode ActivityEmbeddingController#isActivityEmbedded()
dari
library Jetpack WindowManager untuk memeriksa apakah host menyematkan
aktivitas Anda, misalnya:
Kotlin
fun isActivityEmbedded(activity: Activity): Boolean { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity) }
Java
boolean isActivityEmbedded(Activity activity) { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity); }
Batasan ukuran minimum
Sistem Android menerapkan tinggi dan lebar minimum yang ditentukan dalam aplikasi
elemen <layout>
manifes ke aktivitas tersemat. Jika aplikasi melakukan
tidak menetapkan tinggi dan lebar minimum, nilai default sistem akan diterapkan
(sw220dp
)
Jika host mencoba mengubah ukuran penampung tersemat menjadi ukuran yang lebih kecil dari minimum, penampung tersemat akan diperluas untuk menempati seluruh batas tugas.
<activity-alias>
Agar penyematan aktivitas tepercaya atau tidak tepercaya berfungsi dengan elemen <activity-alias>
, android:knownActivityEmbeddingCerts
atau android:allowUntrustedActivityEmbedding
harus diterapkan ke aktivitas target, bukan alias. Kebijakan yang memverifikasi keamanan di server sistem didasarkan pada flag yang ditetapkan pada target, bukan alias.
Aplikasi host
Aplikasi host menerapkan penyematan aktivitas lintas aplikasi dengan cara yang sama seperti saat
menerapkan penyematan aktivitas aplikasi tunggal. Objek SplitPairRule
dan
SplitPairFilter
atau ActivityRule
dan ActivityFilter
menentukan aktivitas tersemat dan pemisahan jendela tugas. Aturan pemisahan ditentukan
secara statis di XML atau saat runtime menggunakan panggilan API
Jetpack WindowManager.
Jika aplikasi host mencoba menyematkan aktivitas yang belum ikut serta dalam penyematan lintas aplikasi, aktivitas tersebut menempati seluruh batas tugas. Hasilnya, aplikasi host perlu mengetahui apakah aktivitas target memungkinkan penyematan.
Jika aktivitas tersemat memulai aktivitas baru dalam tugas yang sama dan aktivitas baru belum memilih untuk ikut serta dalam penyematan lintas aplikasi, aktivitas tersebut akan menempati seluruh batas tugas, bukan menempatkan aktivitas dalam penampung tersemat.
Aplikasi host dapat menyematkan aktivitasnya sendiri tanpa batasan selama aktivitas diluncurkan dalam tugas yang sama.
Contoh pemisahan
Memisahkan dari jendela penuh
Tidak perlu memfaktorkan ulang. Anda dapat menentukan konfigurasi pemisahan
secara statis atau saat runtime, lalu memanggil Context#startActivity()
tanpa
parameter tambahan.
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Memisahkan secara default
Saat halaman landing aplikasi didesain untuk dibagi menjadi dua penampung pada layar besar, pengalaman pengguna akan optimal jika kedua aktivitas dibuat dan ditampilkan secara bersamaan. Namun, konten mungkin tidak tersedia untuk penampung sekunder pemisahan hingga pengguna berinteraksi dengan aktivitas di penampung utama (misalnya, pengguna memilih item dari menu navigasi). Aktivitas placeholder dapat mengisi kekosongan hingga konten dapat ditampilkan dalam penampung sekunder pemisahan (lihat bagian Placeholder).
Untuk membuat pemisahan dengan placeholder, buat placeholder dan kaitkan dengan aktivitas utama:
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
Pemisahan deep link
Saat aplikasi menerima intent, aktivitas target dapat ditampilkan sebagai bagian sekunder dari pemisahan aktivitas. Misalnya, permintaan untuk menampilkan layar detail dengan informasi tentang item dari suatu daftar. Pada layar kecil, detail ditampilkan di jendela tugas penuh; di perangkat yang lebih besar, di samping daftar tersebut.
Permintaan peluncuran harus diarahkan ke aktivitas utama, dan aktivitas detail target harus diluncurkan dalam pemisahan. Sistem secara otomatis memilih presentasi yang benar—ditumpuk atau berdampingan—berdasarkan lebar tampilan.
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)); }
Tujuan deep link mungkin satu-satunya aktivitas yang seharusnya tersedia pengguna di data navigasi sebelumnya, dan Anda sebaiknya tidak mengabaikan aktivitas detail dan hanya menyisakan aktivitas utama:
Sebagai gantinya, Anda dapat menyelesaikan kedua aktivitas secara bersamaan menggunakan
atribut finishPrimaryWithSecondary
:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
Lihat bagian Atribut konfigurasi.
Beberapa aktivitas di penampung terpisah
Dengan penumpukan beberapa aktivitas dalam penampung terpisah, pengguna dapat mengakses konten yang dalam. Misalnya, dengan pemisahan detail daftar, mungkin pengguna harus membuka bagian sub-detail, tetapi tetap mempertahankan aktivitas utama:
Kotlin
class DetailActivity { . . . fun onOpenSubDetail() { startActivity(Intent(this, SubDetailActivity::class.java)) } }
Java
public class DetailActivity { . . . void onOpenSubDetail() { startActivity(new Intent(this, SubDetailActivity.class)); } }
Aktivitas sub-detail ditempatkan di atas aktivitas detail, dengan menyembunyikannya:
Kemudian pengguna dapat kembali ke tingkat detail sebelumnya dengan menavigasi kembali melalui tumpukan:
Menumpuk aktivitas di atas aktivitas lain adalah perilaku default saat aktivitas diluncurkan dari aktivitas dalam penampung sekunder yang sama. Aktivitas yang diluncurkan dari penampung utama dalam pemisahan aktif juga akan berakhir di penampung sekunder di bagian atas tumpukan aktivitas.
Aktivitas dalam tugas baru
Saat aktivitas di jendela tugas terpisah memulai aktivitas di tugas baru, tugas baru dipisahkan dari tugas yang menyertakan pemisahan dan ditampilkan sebagai jendela penuh. Layar Terbaru akan menampilkan dua tugas: tugas di pemisahan dan tugas baru.
Penggantian aktivitas
Aktivitas dapat diganti di tumpukan penampung sekunder; misalnya, saat aktivitas utama digunakan untuk navigasi level atas dan aktivitas sekunder adalah tujuan yang dipilih. Setiap pilihan dari navigasi level atas harus memulai aktivitas baru di penampung sekunder dan menghapus aktivitas atau aktivitas yang sebelumnya ada di penampung tersebut.
Jika aplikasi tidak menyelesaikan aktivitas di penampung sekunder saat pilihan navigasi berubah, navigasi kembali mungkin membingungkan saat pemisahan diciutkan (saat perangkat dilipat). Misalnya, jika Anda memiliki menu di panel utama dan layar A dan B bertumpuk di panel sekunder, saat pengguna melipat ponsel, B berada di atas A, dan A berada di atas menu. Saat pengguna kembali dari B, A yang akan muncul, bukan menu.
Dalam kasus semacam ini, layar A harus dihapus dari data sebelumnya.
Perilaku default saat meluncurkan ke samping dalam penampung baru selama
pemisahan yang ada adalah menempatkan penampung sekunder baru di atas dan mempertahankan penampung lama
satu di data sebelumnya. Anda dapat mengonfigurasi pemisahan untuk menghapus
penampung sekunder sebelumnya dengan clearTop
dan meluncurkan aktivitas baru seperti biasa.
<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))); } }
Atau, gunakan aktivitas sekunder yang sama, dan dari utama (menu) aktivitas mengirim intent baru yang menyelesaikan instance yang sama tetapi memicu status atau pembaruan UI di penampung sekunder.
Beberapa pemisahan
Aplikasi dapat menyediakan navigasi mendalam multi-level dengan meluncurkan aktivitas tambahan ke samping.
Saat aktivitas di penampung sekunder meluncurkan aktivitas baru ke samping, pemisahan baru akan dibuat di atas pemisahan yang ada.
Data sebelumnya berisi semua aktivitas yang sebelumnya telah dibuka sehingga pengguna dapat membuka pemisahan A/B setelah menyelesaikan C.
Untuk membuat pemisahan baru, luncurkan aktivitas baru dari penampung sekunder yang ada ke samping. Mendeklarasikan konfigurasi untuk pemisahan A/B dan B/C dan meluncurkan aktivitas C biasanya dari 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)); } }
Merespons perubahan status pemisahan
Berbagai aktivitas dalam aplikasi dapat memiliki elemen UI yang melakukan fungsi yang sama; misalnya, kontrol yang membuka jendela yang berisi setelan akun.
Akan berlebihan jika dua aktivitas yang memiliki elemen UI yang sama dipisah dan mungkin membingungkan untuk menampilkan elemen di kedua aktivitas.
Untuk mengetahui waktu pemisahan aktivitas, periksa
alur SplitController.splitInfoList
atau daftarkan pemroses dengan
SplitControllerCallbackAdapter
untuk perubahan status terpisah. Kemudian,
sesuaikan UI sesuai dengan:
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); }); }
Coroutine dapat diluncurkan dalam status siklus proses apa pun, tetapi biasanya diluncurkan dalam
status STARTED
untuk menghemat resource (lihat Menggunakan coroutine Kotlin dengan
komponen yang mendukung siklus proses untuk informasi selengkapnya).
Callback dapat dibuat dalam status siklus proses apa pun, termasuk saat suatu aktivitas
dihentikan. Pemroses biasanya harus terdaftar di onStart()
dan tidak terdaftar
di onStop()
.
Modal jendela penuh
Beberapa aktivitas akan memblokir pengguna agar tidak berinteraksi dengan aplikasi hingga tindakan yang ditentukan dilakukan; misalnya, aktivitas layar login, layar konfirmasi kebijakan, atau pesan error. Aktivitas modal harus dicegah agar tidak muncul dalam pemisahan.
Suatu aktivitas dapat dipaksa untuk selalu mengisi jendela tugas menggunakan konfigurasi perluasan:
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
Menyelesaikan aktivitas
Pengguna dapat menyelesaikan aktivitas di kedua sisi pemisahan dengan menggeser dari tepi layar:
Jika perangkat disiapkan untuk menggunakan tombol kembali, bukan navigasi gestur, input akan dikirim ke aktivitas yang difokuskan—aktivitas yang disentuh atau diluncurkan terakhir.
Efek dari menyelesaikan semua aktivitas dalam penampung penampung bergantung pada konfigurasi pemisahan.
Atribut konfigurasi
Anda dapat menentukan atribut aturan pasangan pemisahan untuk mengonfigurasi bagaimana menyelesaikan semua aktivitas di satu sisi pemisahan memengaruhi aktivitas di sisi lain pemisahan. Atribut tersebut adalah:
window:finishPrimaryWithSecondary
— Bagaimana menyelesaikan semua aktivitas di penampung sekunder dapat memengaruhi aktivitas di penampung utamawindow:finishSecondaryWithPrimary
— Bagaimana menyelesaikan semua aktivitas di penampung utama dapat memengaruhi aktivitas di penampung sekunder
Kemungkinan nilai atribut meliputi:
always
— Selalu selesaikan aktivitas di penampung terkaitnever
— Jangan pernah menyelesaikan aktivitas di penampung terkaitadjacent
— Menyelesaikan aktivitas di penampung terkait saat dua penampung ditampilkan berdekatan, tetapi tidak saat dua penampung ditumpuk
Contoh:
<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>
Konfigurasi default
Saat semua aktivitas dalam satu penampung pemisahan selesai, penampung yang tersisa menempati seluruh jendela:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Menyelesaikan aktivitas bersama
Selesaikan aktivitas di penampung utama secara otomatis saat semua aktivitas di penampung sekunder selesai:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Selesaikan aktivitas di penampung sekunder secara otomatis saat semua aktivitas di penampung utama selesai:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Selesaikan aktivitas bersama jika semua aktivitas di penampung utama atau sekunder selesai:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Menyelesaikan beberapa aktivitas dalam penampung
Jika beberapa aktivitas ditumpuk dalam penampung terpisah, menyelesaikan aktivitas di bagian bawah tumpukan tidak otomatis menyelesaikan aktivitas di bagian atas.
Misalnya, jika dua aktivitas berada dalam penampung sekunder, C di atas B:
dan konfigurasi pemisahan ditentukan oleh konfigurasi aktivitas A dan B:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
menyelesaikan aktivitas teratas akan mempertahankan pemisahan.
Menyelesaikan aktivitas bagian bawah (root) dari penampung sekunder tidak menghapus aktivitas di atasnya; dan demikian, juga mempertahankan pemisahan.
Setiap aturan tambahan untuk menyelesaikan aktivitas secara bersamaan, seperti menyelesaikan aktivitas sekunder dengan aktivitas utama, juga akan dijalankan:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Ketika pemisahan dikonfigurasi untuk menyelesaikan penampung primer dan sekunder sekaligus:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Mengubah properti pemisahan saat runtime
Properti pemisahan yang aktif dan terlihat tidak dapat diubah. Mengubah aturan pemisahan akan memengaruhi peluncuran aktivitas tambahan dan penampung baru, tetapi tidak memengaruhi pemisahan yang sudah ada dan aktif.
Untuk mengubah properti pemisahan aktif, selesaikan aktivitas samping atau aktivitas dalam pemisahan dan luncurkan lagi ke samping menggunakan konfigurasi baru.
Properti pemisahan dinamis
Android 15 (API level 35) dan yang lebih tinggi yang didukung oleh Jetpack WindowManager 1.4 dan yang lebih tinggi menawarkan fitur dinamis yang memungkinkan konfigurasi pemisahan penyematan aktivitas, termasuk:
- Perluasan panel: Pemisah interaktif yang dapat ditarik memungkinkan pengguna mengubah ukuran panel dalam presentasi terpisah.
- Penyematan aktivitas: Pengguna dapat menyematkan konten dalam satu penampung dan memisahkan navigasi dalam penampung dari navigasi di penampung lain.
- Peredupan dialog layar penuh: Saat menampilkan dialog, aplikasi dapat menentukan apakah akan meredupkan seluruh jendela tugas atau hanya kontainer yang membuka dialog.
Perluasan panel
Perluasan panel memungkinkan pengguna menyesuaikan jumlah ruang layar yang dialokasikan kedua aktivitas dalam tata letak panel ganda.
Untuk menyesuaikan tampilan pemisah jendela dan rentang yang dapat ditarik, lakukan hal berikut:
Membuat instance
DividerAttributes
Sesuaikan atribut pemisah:
color
: Warna pemisah panel yang dapat ditarik.widthDp
: Lebar pemisah panel yang dapat ditarik. Tetapkan keWIDTH_SYSTEM_DEFAULT
untuk memungkinkan sistem menentukan lebar pemisah.Rentang tarik: Persentase minimum layar yang dapat diduduki panel. Dapat berkisar dari 0,33 hingga 0,66. Tetapkan ke
DRAG_RANGE_SYSTEM_DEFAULT
untuk memungkinkan sistem menentukan tarikan {i>range<i}.
Kotlin
val splitAttributesBuilder: SplitAttributes.Builder = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) if (WindowSdkExtensions.getInstance().extensionVersion >= 6) { splitAttributesBuilder.setDividerAttributes( DividerAttributes.DraggableDividerAttributes.Builder() .setColor(getColor(context, R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ) } val splitAttributes: SplitAttributes = splitAttributesBuilder.build()
Java
SplitAttributes.Builder splitAttributesBuilder = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT); if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) { splitAttributesBuilder.setDividerAttributes( new DividerAttributes.DraggableDividerAttributes.Builder() .setColor(ContextCompat.getColor(context, R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ); } SplitAttributes splitAttributes = splitAttributesBuilder.build();
Penyematan aktivitas
Penyematan aktivitas memungkinkan pengguna menyematkan salah satu jendela terpisah sehingga aktivitas tetap seperti semula saat pengguna menavigasi dalam jendela lain. Penyematan aktivitas memberikan pengalaman multitasking yang ditingkatkan.
Untuk mengaktifkan penyematan aktivitas di aplikasi Anda, lakukan hal berikut:
Tambahkan tombol ke file tata letak aktivitas yang ingin Anda sematkan, misalnya, aktivitas detail tata letak daftar-detail:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/detailActivity" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" tools:context=".DetailActivity"> <TextView android:id="@+id/textViewItemDetail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="36sp" android:textColor="@color/obsidian" app:layout_constraintBottom_toTopOf="@id/pinButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatButton android:id="@+id/pinButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pin_this_activity" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/textViewItemDetail"/> </androidx.constraintlayout.widget.ConstraintLayout>
Dalam metode
onCreate()
aktivitas, tetapkan pemroses onclick pada tombol:Kotlin
pinButton = findViewById(R.id.pinButton) pinButton.setOnClickListener { val splitAttributes: SplitAttributes = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build() val pinSplitRule = SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build() SplitController.getInstance(applicationContext).pinTopActivityStack(taskId, pinSplitRule) }
Java
Button pinButton = findViewById(R.id.pinButton); pinButton.setOnClickListener( (view) => { SplitAttributes splitAttributes = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build(); SplitPinRule pinSplitRule = new SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build(); SplitController.getInstance(getApplicationContext()).pinTopActivityStack(getTaskId(), pinSplitRule); });
Redup layar penuh
Aktivitas biasanya meredupkan layar untuk menarik perhatian ke dialog. Dalam penyematan aktivitas, kedua panel tampilan panel ganda harus meredup, bukan hanya panel yang berisi aktivitas yang membuka dialog, untuk pengalaman UI terpadu.
Dengan WindowManager 1.4 dan yang lebih tinggi, seluruh jendela aplikasi meredup secara default saat
dialog terbuka (lihat EmbeddingConfiguration.DimAreaBehavior.ON_TASK
).
Untuk meredupkan hanya penampung aktivitas yang membuka dialog, gunakan
EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK
.
Mengekstrak aktivitas dari pemisahan ke jendela penuh
Buat konfigurasi baru yang menampilkan jendela penuh aktivitas samping, lalu meluncurkan kembali aktivitas dengan intent yang di-resolve ke instance yang sama.
Memeriksa dukungan pemisahan saat runtime
Penyematan aktivitas didukung di Android 12L (API level 32) dan yang lebih tinggi, tetapi
juga tersedia di beberapa perangkat
yang menjalankan versi platform sebelumnya. Untuk memeriksa
ketersediaan fitur pada runtime, gunakan
properti SplitController.splitSupportStatus
atau
metode 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. }
Jika pemisahan tidak didukung, aktivitas akan diluncurkan di atas aktivitas (dengan mengikuti model penyematan non-aktivitas).
Mencegah penggantian sistem
Produsen perangkat Android (pabrikan peralatan asli atau OEM), dapat mengimplementasikan penyematan aktivitas sebagai fungsi dari sistem perangkat. Sistem menentukan aturan terpisah untuk aplikasi multi-aktivitas, mengganti perilaku jendela aplikasi. Penggantian sistem memaksa aplikasi multi-aktivitas ke mode penyematan aktivitas yang ditentukan sistem.
Penyematan aktivitas sistem dapat meningkatkan penyajian aplikasi melalui tata letak multipanel, seperti daftar-detail, tanpa perubahan apa pun pada aplikasi. Namun, penyematan aktivitas sistem juga dapat menyebabkan kesalahan tata letak aplikasi, bug, atau konflik dengan penyematan aktivitas yang diimplementasikan oleh aplikasi.
Aplikasi Anda dapat mencegah atau mengizinkan penyematan aktivitas sistem dengan menyetel property di file manifes aplikasi, misalnya:
<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>
Nama properti ditentukan di objek WindowProperties
Jetpack WindowManager. Setel nilai ke false
jika aplikasi Anda menerapkan penyematan aktivitas, atau
jika Anda tidak ingin mencegah sistem menerapkan penyematan aktivitasnya
aturan ke aplikasi Anda. Setel nilai ke true
untuk mengizinkan sistem diterapkan
penyematan aktivitas yang ditentukan sistem ke aplikasi Anda.
Batasan, pembatasan, dan peringatan
- Hanya aplikasi host tugas yang diidentifikasi sebagai pemilik aktivitas root dalam tugas yang dapat mengatur dan menyematkan aktivitas lain dalam tugas. Jika aktivitas yang mendukung penyematan dan pemisahan berjalan di tugas milik aplikasi lain, penyematan dan pemisahan untuk aktivitas tersebut tidak akan berfungsi.
- Aktivitas hanya dapat diatur dalam satu tugas. Meluncurkan aktivitas dalam tugas baru akan selalu menempatkannya di jendela baru yang diperluas di luar pemisahan yang ada.
- Hanya aktivitas dalam proses sama yang dapat diatur dan dipisahkan. Callback
SplitInfo
hanya melaporkan aktivitas yang termasuk dalam proses yang sama, karena tidak ada cara untuk mengetahui aktivitas dalam proses yang berbeda. - Setiap aturan aktivitas yang berpasangan atau tunggal hanya berlaku untuk peluncuran aktivitas yang terjadi setelah aturan didaftarkan. Saat ini, tidak ada cara untuk memperbarui pemisahan yang sudah ada ataupun properti visualnya.
- Konfigurasi filter pasangan pemisahan harus cocok dengan intent yang digunakan saat meluncurkan seluruh aktivitas. Pencocokan terjadi pada saat aktivitas baru dimulai dari proses aplikasi sehingga mungkin tidak mengetahui nama komponen yang akan diselesaikan dalam proses sistem nantinya saat menggunakan intent implisit. Jika nama komponen tidak diketahui pada saat peluncuran, karakter pengganti dapat digunakan ("*/*") dan pemfilteran dapat dilakukan berdasarkan pada tindakan intent.
- Saat ini, tidak ada cara untuk memindahkan aktivitas antara penampung atau keluar-masuk pemisahan setelah dibuat. Pemisahan hanya dibuat oleh library WindowManager saat aktivitas baru dengan aturan yang cocok diluncurkan, dan pemisahan akan dihancurkan saat aktivitas terakhir dalam penampung terpisah telah selesai.
- Aktivitas dapat diluncurkan ulang ketika konfigurasi berubah sehingga saat pemisahan dibuat atau dihapus dan batas aktivitas berubah, aktivitas dapat melewati penghancuran total instance sebelumnya dan pembuatan instance baru. Oleh karena itu, developer aplikasi harus berhati-hati dengan hal-hal seperti meluncurkan aktivitas baru dari callback siklus proses.
- Perangkat harus menyertakan antarmuka ekstensi jendela untuk mendukung aktivitas penyematan. Hampir semua perangkat layar besar yang menjalankan Android 12L (API level 32) atau yang lebih tinggi menyertakan antarmuka. Namun, beberapa perangkat layar besar yang tidak dapat menjalankan beberapa aktivitas tidak menyertakan antarmuka ekstensi jendela. Jika perangkat layar besar tidak mendukung mode multi-aplikasi, perangkat tersebut mungkin tidak mendukung penyematan aktivitas.
Referensi lainnya
- Codelab:
- Jalur pembelajaran — Penyematan aktivitas
- Aplikasi contoh — activity-embedding