การฝังกิจกรรมจะเพิ่มประสิทธิภาพแอปในอุปกรณ์หน้าจอขนาดใหญ่โดยการแยกหน้าต่างงานของแอปพลิเคชันระหว่างกิจกรรม 2 รายการหรือ 2 อินสแตนซ์ของกิจกรรมเดียวกัน
หากแอปประกอบด้วยหลายกิจกรรม การฝังกิจกรรมจะช่วยให้คุณทำสิ่งต่อไปนี้ได้ เพื่อมอบประสบการณ์ของผู้ใช้ที่ดียิ่งขึ้นบนแท็บเล็ต อุปกรณ์แบบพับได้ และอุปกรณ์ ChromeOS
การฝังกิจกรรมไม่จําเป็นต้องเปลี่ยนรูปแบบโค้ด คุณกำหนดวิธีที่แอปแสดงกิจกรรมได้ ไม่ว่าจะเป็นแสดงควบคู่กันหรือซ้อนกัน โดยการสร้างไฟล์การกำหนดค่า XML หรือการเรียกใช้ Jetpack WindowManager API
ระบบจะยังคงรองรับหน้าจอขนาดเล็กโดยอัตโนมัติ เมื่อแอปอยู่ในอุปกรณ์ที่มีหน้าจอขนาดเล็ก ระบบจะวางกิจกรรมซ้อนกัน เปิด เมื่อมีหน้าจอขนาดใหญ่ กิจกรรมจะแสดงคู่กัน ระบบจะกำหนดการแสดงผลตามการกำหนดค่าที่คุณสร้างขึ้น โดยไม่จำเป็นต้องใช้ตรรกะการแยกย่อย
การฝังกิจกรรมรองรับการเปลี่ยนการวางแนวอุปกรณ์และทำงานได้อย่างราบรื่น บนอุปกรณ์แบบพับได้ การซ้อนและไม่เก็บกิจกรรมใดๆ ขณะอุปกรณ์พับ กางออก
การฝังกิจกรรมใช้ได้ในอุปกรณ์หน้าจอขนาดใหญ่ส่วนใหญ่ที่ใช้ Android 12L (API ระดับ 32) ขึ้นไป
หน้าต่างแยกงาน
กิจกรรมที่ฝังจะแยกหน้าต่างงานของแอปออกเป็น 2 คอนเทนเนอร์ ได้แก่ หลักและ รอง คอนเทนเนอร์มีกิจกรรมที่เปิดจากกิจกรรมหลักหรือ จากกิจกรรมอื่นๆ ที่มีอยู่แล้วในคอนเทนเนอร์
กิจกรรมจะซ้อนกันในคอนเทนเนอร์รองเมื่อเปิดใช้งาน และ คอนเทนเนอร์รองซ้อนอยู่ด้านบนของคอนเทนเนอร์หลักในหน้าจอขนาดเล็ก เพื่อให้การซ้อนกิจกรรมและการนำทางย้อนกลับสอดคล้องกับลำดับของ กิจกรรมที่มีอยู่แล้วในแอป
การฝังกิจกรรมช่วยให้คุณแสดงกิจกรรมได้หลายวิธี บัญชี แอปสามารถแยกหน้าต่างงานด้วยการเปิดกิจกรรม 2 รายการพร้อมกัน พร้อมกัน:
หรือกิจกรรมที่ครอบครองหน้าต่างงานทั้งหน้าต่างอาจสร้างการแยกโดยการเปิดกิจกรรมใหม่ควบคู่ไปด้วย
กิจกรรมที่แยกอยู่และแชร์หน้าต่างงานอยู่แล้วสามารถเปิดกิจกรรมอื่นๆ ได้ดังนี้
ที่ด้านข้างของกิจกรรมอื่น ให้ทำดังนี้
ไปด้านข้าง แล้วเลื่อนการแยกไปด้านข้างเพื่อซ่อนกิจกรรมหลักก่อนหน้า
เปิดกิจกรรมที่ด้านบน ซึ่งก็คือในสแต็กกิจกรรมเดียวกัน
เปิดกิจกรรมแบบเต็มหน้าต่างในงานเดียวกัน
การนำทางย้อนกลับ
แอปพลิเคชันประเภทต่างๆ อาจมีกฎการนำทางย้อนกลับที่แตกต่างกันใน สถานะของหน้าต่างงานแยกโดยขึ้นอยู่กับทรัพยากร Dependency ระหว่างกิจกรรมหรือวิธีการ ผู้ใช้จะทำให้เกิดเหตุการณ์การย้อนกลับ เช่น
- แสดงร่วมกัน: หากกิจกรรมมีความเกี่ยวข้องกันและไม่ควรแสดงกิจกรรมหนึ่งโดยไม่มีอีกกิจกรรมหนึ่ง คุณจะกำหนดค่าการไปยังส่วนหลังเพื่อให้ดูทั้ง 2 กิจกรรมจนจบได้
- ไปคนเดียว: หากกิจกรรมเป็นอิสระอย่างสิ้นเชิง ให้ย้อนกลับบน กิจกรรมจะไม่ส่งผลต่อสถานะของกิจกรรมอื่นในหน้าต่างงาน
ระบบจะส่งเหตุการณ์ย้อนกลับไปยังกิจกรรมที่โฟกัสล่าสุดเมื่อใช้ปุ่ม การนำทาง
สำหรับการนำทางด้วยท่าทางสัมผัส ให้ทำดังนี้
Android 14 (API ระดับ 34) และต่ำกว่า — ระบบจะส่งเหตุการณ์ "กลับ" ไปยังกิจกรรมที่เกิดท่าทางสัมผัส เมื่อผู้ใช้ปัดจากด้านซ้ายของหน้าจอ ระบบจะส่งเหตุการณ์ "กลับ" ไปยังกิจกรรมในแผงด้านซ้ายของหน้าต่างที่แยก เมื่อผู้ใช้ปัดจากด้านขวาของ เหตุการณ์ย้อนกลับจะส่งไปยังกิจกรรมในแผงด้านขวา
Android 15 (API ระดับ 35) ขึ้นไป
เมื่อจัดการกับกิจกรรมหลายอย่างจากแอปเดียวกัน ท่าทางสัมผัส สิ้นสุดกิจกรรมยอดนิยมไม่ว่าจะอยู่ในทิศทางใด ประสบการณ์ที่เป็นหนึ่งเดียวมากขึ้น
ในสถานการณ์ที่เกี่ยวข้องกับ 2 กิจกรรมจากแอปที่ต่างกัน (โฆษณาซ้อนทับ) เหตุการณ์ "ย้อนกลับ" จะไปยังกิจกรรมล่าสุดในโฟกัสโดยสอดคล้องกับ ลักษณะการทำงานของการนำทางด้วยปุ่ม
เลย์เอาต์แบบหลายหน้าต่าง
Jetpack WindowManager ช่วยให้คุณสร้างกิจกรรมที่ฝังเลย์เอาต์หลายแผงบนอุปกรณ์หน้าจอขนาดใหญ่ที่ใช้ Android 12L (API ระดับ 32) ขึ้นไป และในอุปกรณ์บางรุ่นที่ใช้แพลตฟอร์มเวอร์ชันเก่า แอปที่มีอยู่ซึ่งอิงตาม
กิจกรรมหลายอย่าง แทนที่จะเป็นส่วนย่อยหรือเลย์เอาต์ที่อิงตามมุมมอง เช่น
SlidingPaneLayout
สามารถช่วยปรับปรุงประสบการณ์ของผู้ใช้ที่มีหน้าจอขนาดใหญ่
โดยไม่ต้องเปลี่ยนโครงสร้างภายในโค้ดต้นฉบับ
ตัวอย่างที่พบบ่อยอย่างหนึ่งคือการแยกรายการเป็นรายละเอียด ระบบจะเริ่มกิจกรรมรายการ จากนั้นแอปพลิเคชันจะเริ่มกิจกรรมแบบละเอียดทันทีเพื่อให้การนำเสนอมีคุณภาพสูง ระบบการเปลี่ยนจะรอจนกว่า กิจกรรมจะถูกวาด แล้วแสดงพร้อมกัน สำหรับผู้ใช้ มีทั้ง 2 ประเภท รวมเป็นหนึ่ง
แอตทริบิวต์แยก
คุณสามารถระบุสัดส่วนของหน้าต่างงานระหว่างคอนเทนเนอร์ที่แบ่งได้ และการจัดวางคอนเทนเนอร์ให้สัมพันธ์กัน
สำหรับกฎที่กําหนดไว้ในไฟล์การกําหนดค่า XML ให้ตั้งค่าแอตทริบิวต์ต่อไปนี้
splitRatio
: กำหนดสัดส่วนคอนเทนเนอร์ ค่าคือตัวเลขทศนิยมในช่วงเปิด (0.0, 1.0)splitLayoutDirection
: ระบุวิธีจัดเลย์เอาต์คอนเทนเนอร์แบบแยก ที่เกี่ยวข้องกัน ค่าต่างๆ ได้แก่ltr
: จากซ้ายไปขวาrtl
: จากขวาไปซ้ายlocale
: ระบุltr
หรือrtl
จากการตั้งค่าภาษา
ดูตัวอย่างได้ที่ส่วนการกําหนดค่า XML
สําหรับกฎที่สร้างโดยใช้ WindowManager API ให้สร้างออบเจ็กต์ SplitAttributes
ด้วย SplitAttributes.Builder
แล้วเรียกใช้เมธอดผู้สร้างต่อไปนี้
setSplitType()
: กำหนดสัดส่วนของคอนเทนเนอร์ที่แยก ดูอาร์กิวเมนต์ที่ถูกต้อง รวมถึงเมธอดSplitAttributes.SplitType.ratio()
ในSplitAttributes.SplitType
setLayoutDirection()
: ตั้งค่าเลย์เอาต์ของคอนเทนเนอร์ โปรดดูค่าที่เป็นไปได้ในSplitAttributes.LayoutDirection
โปรดดูตัวอย่างในส่วน WindowManager API
ตัวยึดตําแหน่ง
กิจกรรมตัวยึดตำแหน่งคือกิจกรรมรองที่ว่างเปล่าซึ่งใช้พื้นที่ของ แยกกิจกรรม ในท้ายที่สุด กิจกรรมเหล่านี้จะแทนที่ด้วยกิจกรรมอื่น ที่มีเนื้อหา ตัวอย่างเช่น กิจกรรมตัวยึดตําแหน่งอาจอยู่ด้านรองของกิจกรรมที่แยกในเลย์เอาต์รายการแบบละเอียดจนกว่าจะมีการเลือกรายการจากรายการ เมื่อถึงจุดนั้น กิจกรรมที่มีข้อมูลรายละเอียดสําหรับรายการในรายการที่เลือกจะแทนที่ตัวยึดตําแหน่ง
โดยค่าเริ่มต้น ระบบจะแสดงตัวยึดตำแหน่งเฉพาะเมื่อมีพื้นที่เพียงพอสำหรับ การแยกกิจกรรม ตัวยึดตําแหน่งจะสิ้นสุดโดยอัตโนมัติเมื่อขนาดการแสดงผลเปลี่ยนไปเป็นความกว้างหรือความสูงที่เล็กเกินกว่าที่จะแสดงการแยก เมื่อมีพื้นที่เพียงพอ ระบบจะเปิดใช้งานตัวยึดตำแหน่งอีกครั้งโดยมีสถานะเริ่มต้นอีกครั้ง
อย่างไรก็ตาม แอตทริบิวต์ stickyPlaceholder
ของเมธอด SplitPlaceholderRule
หรือ setSticky()
ของ SplitPlaceholder.Builder
สามารถลบล้างลักษณะการทำงานเริ่มต้นได้ เมื่อแอตทริบิวต์หรือเมธอดระบุค่าเป็น true
ระบบจะแสดงตัวยึดตําแหน่งเป็นกิจกรรมบนสุดในหน้าต่างงานเมื่อปรับขนาดการแสดงผลเป็นหน้าจอเดียวจากหน้าจอแบบ 2 แผง (ดูตัวอย่างที่การกําหนดค่าแบบแยก)
การเปลี่ยนแปลงขนาดหน้าต่าง
เมื่อการเปลี่ยนแปลงการกำหนดค่าอุปกรณ์ทำให้หน้าต่างงานมีความกว้างไม่เพียงพอสำหรับเลย์เอาต์หลายแผง (เช่น เมื่ออุปกรณ์แบบพับหน้าจอขนาดใหญ่พับจากขนาดแท็บเล็ตเป็นขนาดโทรศัพท์ หรือหน้าต่างแอปมีการปรับขนาดในโหมดหลายหน้าต่าง) กิจกรรมที่ไม่ใช่ตัวยึดตำแหน่งในแผงรองของหน้าต่างงานจะซ้อนกันอยู่ด้านบนของกิจกรรมในแผงหลัก
กิจกรรมตัวยึดตําแหน่งจะแสดงเฉพาะเมื่อมีการแสดงผลกว้างพอสําหรับการแยก ในหน้าจอขนาดเล็ก ตัวยึดตำแหน่งจะปิดโดยอัตโนมัติ เมื่อ พื้นที่แสดงผลมีขนาดใหญ่พออีกครั้ง ตัวยึดตำแหน่งจะได้รับการสร้างขึ้นใหม่ (โปรดดู ตัวยึดตำแหน่ง)
การวางซ้อนกิจกรรมเป็นไปได้เนื่องจาก WindowManager จัดลําดับกิจกรรมในแผงรองเหนือกิจกรรมในแผงหลักตามลําดับ Z
กิจกรรมหลายรายการในแผงรอง
กิจกรรม ข เริ่มกิจกรรม ค แทนโดยไม่มี Flag Intent เพิ่มเติม
ส่งผลให้เกิด z-order ต่อไปนี้ของกิจกรรมในงานเดียวกัน
ดังนั้น ในหน้าต่างงานที่เล็กลง แอปพลิเคชันจะลดขนาดเหลือเพียงกิจกรรมเดียวโดยมี C ที่ด้านบนของกลุ่ม ให้ทำดังนี้
การย้อนกลับในหน้าต่างขนาดเล็กจะไปยังส่วนต่างๆ ของกิจกรรมที่ซ้อนกันอยู่ ทับกัน
หากคืนค่าการกำหนดค่าหน้าต่างงานเป็นขนาดที่ใหญ่ขึ้นซึ่งรองรับหลายแผง กิจกรรมจะแสดงคู่กันอีกครั้ง
การแยกส่วนแบบซ้อน
กิจกรรม ข เริ่มต้นกิจกรรม C ไปด้านข้าง และเปลี่ยนส่วนที่แยกออกด้านข้าง
ผลลัพธ์จะเป็นลำดับ Z ต่อไปนี้ของกิจกรรมในงานเดียวกัน
ในหน้าต่างงานที่เล็กลง แอปพลิเคชันจะลดขนาดลงเหลือเพียงกิจกรรมเดียวโดยเปิด C ด้านบน:
การวางแนวตั้งแบบคงที่
การตั้งค่าไฟล์ Manifest android:screenOrientation ช่วยให้แอปจำกัดกิจกรรมให้เป็นแนวตั้งหรือแนวนอนได้ ผู้ผลิตอุปกรณ์ (OEM) สามารถละเว้นคำขอการวางแนวหน้าจอและแสดงแอปในแนวตั้งบนจอแสดงผลแนวนอนหรือแนวนอนบนจอแสดงผลแนวตั้งได้ เพื่อปรับปรุงประสบการณ์ของผู้ใช้บนอุปกรณ์หน้าจอขนาดใหญ่ เช่น แท็บเล็ตและอุปกรณ์แบบพับได้
ในทำนองเดียวกัน เมื่อเปิดใช้การฝังกิจกรรม OEM จะปรับแต่งอุปกรณ์ให้แสดงกิจกรรมในแนวตั้งแบบ Letterbox แบบคงที่ในแนวนอนบนหน้าจอขนาดใหญ่ได้ (ความกว้าง ≥ 600dp) เมื่อกิจกรรมแนวตั้งแบบคงที่เปิดกิจกรรมที่ 2 อุปกรณ์จะแสดงกิจกรรมทั้ง 2 รายการควบคู่กันในการแสดงผลแบบ 2 แผง
เพิ่มพร็อพเพอร์ตี้ android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
ลงในไฟล์ Manifest ของแอปเสมอเพื่อแจ้งให้อุปกรณ์ทราบว่าแอปของคุณรองรับการฝังกิจกรรม (ดูส่วนการกำหนดค่าแบบแยก) จากนั้นอุปกรณ์ที่ OEM ออกแบบเองก็สามารถกำหนดได้ว่าจะใช้แถบดำด้านบน-ล่างของภาพหรือไม่
กิจกรรมภาพบุคคลแบบตายตัว
การกำหนดค่าการแยก
กฎการแยกจะกำหนดค่าการแยกกิจกรรม คุณกำหนดกฎการแยกในไฟล์การกำหนดค่า XML หรือโดยการเรียกใช้ WindowManager API ของ Jetpack
ไม่ว่าในกรณีใด แอปของคุณต้องเข้าถึงไลบรารี WindowManager และต้องแจ้งให้ระบบทราบว่าแอปได้ติดตั้งใช้งานการฝังกิจกรรมแล้ว
โดยทำดังนี้
เพิ่มทรัพยากร Dependency ของไลบรารี WindowManager เวอร์ชันล่าสุดลงในไฟล์
build.gradle
ระดับโมดูลของแอป เช่นimplementation 'androidx.window:window:1.1.0-beta02'
ไลบรารี WindowManager มีคอมโพเนนต์ทั้งหมดที่จําเป็นสําหรับการฝังกิจกรรม
แจ้งให้ระบบทราบว่าแอปของคุณใช้การฝังกิจกรรม
เพิ่มพร็อพเพอร์ตี้
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
ใน<แอปพลิเคชัน> ของไฟล์ Manifest ของแอป และตั้งค่า เป็นจริง เช่น<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application> <property android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED" android:value="true" /> </application> </manifest>
ใน WindowManager เวอร์ชัน 1.1.0-alpha06 ขึ้นไป ระบบจะปิดใช้การแยกการฝังกิจกรรม เว้นแต่จะมีการเพิ่มพร็อพเพอร์ตี้ลงในไฟล์ Manifest และตั้งค่าเป็น true
นอกจากนี้ ผู้ผลิตอุปกรณ์ยังใช้การตั้งค่านี้เพื่อเปิดใช้ความสามารถที่กำหนดเองสำหรับแอปที่รองรับการฝังกิจกรรม เช่น อุปกรณ์อาจแสดงกิจกรรมในแนวตั้งเท่านั้นในจอแสดงผลแนวนอนเพื่อปรับแนวของกิจกรรมสำหรับการเปลี่ยนไปใช้เลย์เอาต์แบบ 2 แผงเมื่อกิจกรรมที่ 2 เริ่มขึ้น (ดูการวางแนวแนวตั้งแบบคงที่)
การกำหนดค่า XML
หากต้องการสร้างการใช้งานการฝังกิจกรรมที่อิงตาม XML ให้ทําตามขั้นตอนต่อไปนี้
สร้างไฟล์ทรัพยากร XML ที่จะทําสิ่งต่อไปนี้
- กำหนดกิจกรรมที่ใช้การแบ่งฝั่ง
- กําหนดค่าตัวเลือกการแยก
- สร้างตัวยึดตำแหน่งสำหรับคอนเทนเนอร์รองของ การแยกเมื่อไม่มีเนื้อหา
- ระบุกิจกรรมที่ไม่ควรเป็นส่วนหนึ่งของการแยก
เช่น
<!-- 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>
สร้างตัวเริ่มต้น
คอมโพเนนต์ WindowManager
RuleController
จะแยกวิเคราะห์ XML ไฟล์การกำหนดค่าเซิร์ฟเวอร์ และทำให้กฎพร้อมใช้งานกับระบบ ไลบรารี Startup ของ JetpackInitializer
จะทำให้ไฟล์ XML พร้อมใช้งานสำหรับRuleController
เมื่อแอปเริ่มต้นขึ้นเพื่อให้กฎมีผลเมื่อกิจกรรมใดๆ เริ่มต้นขึ้นหากต้องการสร้างโปรแกรมเริ่มต้น ให้ทำดังนี้
เพิ่มทรัพยากร Dependency ของไลบรารี Jetpack Startup เวอร์ชันล่าสุดลงในไฟล์
build.gradle
ระดับโมดูล เช่นimplementation 'androidx.startup:startup-runtime:1.1.1'
สร้างคลาสที่ใช้อินเทอร์เฟซ
Initializer
โปรแกรมเริ่มต้นทำให้
RuleController
ใช้กฎการแยกได้โดย การส่ง ID ของไฟล์การกำหนดค่า XML (main_split_config.xml
) ไปยังเมธอดRuleController.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(); } }
สร้างผู้ให้บริการเนื้อหาสําหรับคําจํากัดความของกฎ
เพิ่ม
androidx.startup.InitializationProvider
ลงในไฟล์ Manifest ของแอป ในฐานะ<provider>
ระบุการอ้างอิงการติดตั้งใช้งาน โปรแกรมเริ่มต้นRuleController
,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
ค้นพบและเริ่มต้นSplitInitializer
ก่อน ระบบจะเรียกเมธอดonCreate()
ของแอป ดังนั้น กฎการแยกจะอยู่ใน จะมีผลเมื่อกิจกรรมหลักของแอปเริ่มขึ้น
API ของ WindowManager
คุณสามารถใช้การฝังกิจกรรมแบบเป็นโปรแกรมด้วย API จำนวนไม่มาก
เรียกใช้ในเมธอด onCreate()
ของคลาสย่อยของ
Application
เพื่อตรวจสอบว่ากฎมีผลก่อนกิจกรรมใดๆ
เปิดใช้งาน
หากต้องการสร้างการแยกกิจกรรมแบบเป็นโปรแกรม ให้ทําดังนี้
สร้างกฎการแยก
สร้าง
SplitPairFilter
ที่ระบุกิจกรรมที่ใช้การแบ่งฝั่ง ได้แก่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 );
เพิ่มตัวกรองลงในชุดตัวกรอง
Kotlin
val filterSet = setOf(splitPairFilter)
Java
Set<SplitPairFilter> filterSet = new HashSet<>(); filterSet.add(splitPairFilter);
สร้างแอตทริบิวต์เลย์เอาต์สำหรับการแยก
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
สร้างออบเจ็กต์ที่มีเลย์เอาต์ ดังนี้setSplitType()
: กำหนดพื้นที่แสดงผลที่ใช้ได้ ที่จัดสรรให้กับคอนเทนเนอร์กิจกรรมแต่ละรายการ ประเภทการแยกตามสัดส่วนจะระบุสัดส่วนพื้นที่โฆษณาที่มีอยู่ซึ่งจัดสรรให้กับคอนเทนเนอร์หลัก ส่วนคอนเทนเนอร์รองจะใช้พื้นที่โฆษณาที่เหลือsetLayoutDirection()
: ระบุวิธีที่คอนเทนเนอร์กิจกรรม วางเรียงๆ กัน โดยแสดงคอนเทนเนอร์หลักก่อน
สร้าง
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
สร้างและกำหนดค่ากฎ ดังนี้filterSet
: มีตัวกรองคู่แยกที่ใช้กำหนดช่วงเวลา ใช้กฎโดยระบุกิจกรรมที่ใช้การแบ่งส่วนแบ่งร่วมกันsetDefaultSplitAttributes()
: ใช้แอตทริบิวต์เลย์เอาต์กับ กฎsetMinWidthDp()
: ตั้งค่าความกว้างขั้นต่ำของการแสดงผล (หน่วย ความหนาแน่นของพิกเซลอิสระ, dp) ที่เปิดใช้การแยกsetMinSmallestWidthDp()
: กำหนดค่าต่ำสุด (เป็น dp) ที่ ขนาดเล็กจากขนาดที่แสดง 2 ขนาดต้องเปิดการใช้งาน แยกโดยไม่คำนึงถึงการวางแนวของอุปกรณ์setMaxAspectRatioInPortrait()
: ตั้งค่าสัดส่วนการแสดงผลสูงสุด (ความสูง:ความกว้าง) ในแนวตั้งที่จะแสดงการแยกกิจกรรม หากสัดส่วนภาพของการแสดงผลแนวตั้ง เกินสัดส่วนภาพสูงสุด การแยกจะปิดใช้งานโดยไม่คำนึงถึง ความกว้างของการแสดงผล หมายเหตุ: ค่าเริ่มต้นคือ 1.4 ซึ่ง ส่งผลให้เกิดกิจกรรมที่ใช้เวลาทั้งหน้าต่างงานในแนวตั้ง ของแท็บเล็ตส่วนใหญ่ โปรดดูSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
และsetMaxAspectRatioInLandscape()
ด้วย ค่าเริ่มต้นสำหรับแนวนอนคือALWAYS_ALLOW
setFinishPrimaryWithSecondary()
: ตั้งค่าว่าการทำกิจกรรมทั้งหมดในคอนเทนเนอร์รองส่งผลต่อกิจกรรมในคอนเทนเนอร์หลักอย่างไรNEVER
บ่งบอกว่าระบบไม่ควรสิ้นสุดกิจกรรมหลักเมื่อกิจกรรมทั้งหมดในคอนเทนเนอร์รองสิ้นสุด (ดูสิ้นสุดกิจกรรม)setFinishSecondaryWithPrimary()
: ตั้งค่าว่าการทำกิจกรรมทั้งหมดในคอนเทนเนอร์หลักส่งผลต่อกิจกรรมในคอนเทนเนอร์รองอย่างไรALWAYS
บ่งบอกว่าระบบควรทำกิจกรรมในคอนเทนเนอร์รองให้เสร็จสิ้นเสมอเมื่อกิจกรรมทั้งหมดในคอนเทนเนอร์หลักเสร็จสิ้น (ดูทำกิจกรรมให้เสร็จสิ้น)setClearTop()
: ระบุว่ากิจกรรมทั้งหมดในคอนเทนเนอร์รองจะสิ้นสุดลงหรือไม่เมื่อมีการเริ่มกิจกรรมใหม่ในคอนเทนเนอร์ ค่าfalse
ระบุว่ากิจกรรมใหม่ วางซ้อนบนกิจกรรมที่มีอยู่แล้วในคอนเทนเนอร์รอง
รับอินสแตนซ์แบบ Singleton ของ WindowManager
RuleController
และเพิ่มกฎKotlin
val ruleController = RuleController.getInstance(this) ruleController.addRule(splitPairRule)
Java
RuleController ruleController = RuleController.getInstance(this); ruleController.addRule(splitPairRule);
สร้างตัวยึดตำแหน่งสำหรับคอนเทนเนอร์รองเมื่อไม่มีเนื้อหา
สร้าง
ActivityFilter
ที่ระบุกิจกรรมที่มี ตัวยึดตำแหน่งจะแชร์การแยกหน้าต่างงาน ดังนี้Kotlin
val placeholderActivityFilter = ActivityFilter( ComponentName(this, ListActivity::class.java), null )
Java
ActivityFilter placeholderActivityFilter = new ActivityFilter( new ComponentName(this, ListActivity.class), null );
เพิ่มตัวกรองลงในชุดตัวกรอง
Kotlin
val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
Java
Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>(); placeholderActivityFilterSet.add(placeholderActivityFilter);
สร้าง
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
สร้างและกำหนดค่ากฎ ดังนี้placeholderActivityFilterSet
: มีตัวกรองกิจกรรมที่กําหนดเวลาที่จะใช้กฎโดยระบุกิจกรรมที่เชื่อมโยงกับกิจกรรมตัวยึดตําแหน่งIntent
: ระบุการเปิดตัวกิจกรรมของตัวยึดตําแหน่งsetDefaultSplitAttributes()
: ใช้แอตทริบิวต์การออกแบบกับกฎsetMinWidthDp()
: ตั้งค่าความกว้างขั้นต่ำของการแสดงผล (เป็นความหนาแน่นของพิกเซลอิสระ, dp) ที่ทำให้แบ่งได้setMinSmallestWidthDp()
: ตั้งค่าต่ำสุด (เป็น dp) ที่ขนาดการแสดงผลที่เล็กกว่าของ 2 ขนาดต้องมีขนาดเท่าใดจึงจะแยกหน้าจอได้ ไม่ว่าจะปรับแนวของอุปกรณ์เป็นแนวตั้งหรือแนวนอนsetMaxAspectRatioInPortrait()
: ตั้งค่าสัดส่วนการแสดงผลสูงสุด (ความสูง:ความกว้าง) ในแนวตั้งสำหรับการแสดงการแยกกิจกรรม หมายเหตุ: ค่าเริ่มต้นคือ 1.4 ซึ่งจะทำให้กิจกรรมเต็มหน้าต่างงานในแนวตั้งบนแท็บเล็ตส่วนใหญ่ โปรดดูSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
และsetMaxAspectRatioInLandscape()
ด้วย ค่าเริ่มต้นสำหรับแนวนอนคือALWAYS_ALLOW
setFinishPrimaryWithPlaceholder()
: ตั้งค่าว่าการดำเนินการตัวยึดตำแหน่งให้เสร็จสิ้นส่งผลต่อกิจกรรมอย่างไร ในคอนเทนเนอร์หลัก "ALWAYS" เป็นการระบุว่าระบบควร ทำกิจกรรมในคอนเทนเนอร์หลักให้เสร็จเมื่อตัวยึดตำแหน่ง เสร็จสิ้น (ดูสิ้นสุดกิจกรรม)setSticky()
: กำหนดว่ากิจกรรมตัวยึดตำแหน่งจะปรากฏที่ด้านบนของกองกิจกรรมบนจอแสดงผลขนาดเล็กหรือไม่ เมื่อตัวยึดตำแหน่งปรากฏขึ้นครั้งแรกในการแยกที่มีความกว้างขั้นต่ำเพียงพอ
เพิ่มกฎใน WindowManager
RuleController
:Kotlin
ruleController.addRule(splitPlaceholderRule)
Java
ruleController.addRule(splitPlaceholderRule);
ระบุกิจกรรมที่ไม่ควรเป็นส่วนหนึ่งของการแยก
สร้าง
ActivityFilter
ที่ระบุกิจกรรมที่ควรใช้พื้นที่แสดงงานทั้งหมดเสมอ โดยทำดังนี้Kotlin
val expandedActivityFilter = ActivityFilter( ComponentName(this, ExpandedActivity::class.java), null )
Java
ActivityFilter expandedActivityFilter = new ActivityFilter( new ComponentName(this, ExpandedActivity.class), null );
เพิ่มตัวกรองลงในชุดตัวกรอง
Kotlin
val expandedActivityFilterSet = setOf(expandedActivityFilter)
Java
Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>(); expandedActivityFilterSet.add(expandedActivityFilter);
สร้าง
ActivityRule
:Kotlin
val activityRule = ActivityRule.Builder(expandedActivityFilterSet) .setAlwaysExpand(true) .build()
Java
ActivityRule activityRule = new ActivityRule.Builder( expandedActivityFilterSet ).setAlwaysExpand(true) .build();
ActivityRule.Builder
สร้างและกําหนดค่ากฎexpandedActivityFilterSet
: มีตัวกรองกิจกรรมที่กําหนดเวลาที่จะใช้กฎโดยระบุกิจกรรมที่คุณต้องการยกเว้นจากการแยกsetAlwaysExpand()
: ระบุว่ากิจกรรมควรเติมโฆษณาหรือไม่ หน้าต่างงานทั้งหมด
เพิ่มกฎลงใน WindowManager
RuleController
Kotlin
ruleController.addRule(activityRule)
Java
ruleController.addRule(activityRule);
การฝังข้ามแอปพลิเคชัน
ใน Android 13 (API ระดับ 33) ขึ้นไป แอปจะฝังกิจกรรมจากแอปอื่นๆ ได้ การฝังกิจกรรมข้ามแอปหรือข้าม UID ช่วยในการผสานรวมภาพกิจกรรมจากแอปพลิเคชัน Android หลายรายการ ระบบจะแสดงกิจกรรมของแอปโฮสต์และกิจกรรมที่ฝังจาก แอปอื่นที่อยู่บนหน้าจอข้างๆ หรือด้านบนและด้านล่างเช่นเดียวกับในแอปเดียว กิจกรรมที่ฝัง
ตัวอย่างเช่น แอปการตั้งค่าอาจฝังกิจกรรมตัวเลือกวอลเปเปอร์จาก แอป Wallpaper Picker
รูปแบบความน่าเชื่อถือ
กระบวนการโฮสต์ที่ฝังกิจกรรมจากแอปอื่นๆ สามารถกำหนดการแสดงกิจกรรมที่ฝังใหม่ได้ ซึ่งรวมถึงขนาด ตำแหน่ง การครอบตัด และความโปร่งใส โฮสต์ที่เป็นอันตรายอาจใช้ความสามารถนี้ทำให้ผู้ใช้เข้าใจผิด และ สร้างการหลอกให้คลิกหรือการโจมตีอื่นๆ เพื่อแก้ไข UI
Android กำหนดให้แอปต้องเลือกใช้เพื่อป้องกันไม่ให้มีการฝังกิจกรรมข้ามแอปในทางที่ผิด เพื่ออนุญาตให้ฝังกิจกรรมของตนเอง แอปสามารถกำหนดให้โฮสต์เชื่อถือได้ หรือไม่น่าเชื่อถือ
โฮสต์ที่เชื่อถือได้
หากต้องการอนุญาตให้แอปพลิเคชันอื่นๆ ฝังและควบคุมการแสดงกิจกรรมจากแอปของคุณอย่างเต็มรูปแบบ ให้ระบุใบรับรอง SHA-256 ของแอปพลิเคชันโฮสต์ในแอตทริบิวต์ android:knownActivityEmbeddingCerts
ขององค์ประกอบ <activity>
หรือ <application>
ในไฟล์ Manifest ของแอป
ตั้งค่า android:knownActivityEmbeddingCerts
เป็นสตริง ดังนี้
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
... />
หรือหากต้องการระบุใบรับรองหลายใบ ให้ใช้อาร์เรย์ของสตริงดังนี้
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
... />
ซึ่งอ้างอิงทรัพยากรดังต่อไปนี้
<resources>
<string-array name="known_host_certificate_digests">
<item>cert1</item>
<item>cert2</item>
...
</string-array>
</resources>
เจ้าของแอปจะรับไดเจสต์ใบรับรอง SHA โดยเรียกใช้ Gradle
signingReport
งาน ไดเจสต์ของใบรับรองคือลายนิ้วมือ SHA-256 ที่ไม่มี
เครื่องหมายโคลอนคั่น ดูข้อมูลเพิ่มเติมได้ที่เรียกใช้รายงานการลงชื่อ และ
การตรวจสอบสิทธิ์ไคลเอ็นต์
โฮสต์ที่ไม่น่าเชื่อถือ
หากต้องการอนุญาตให้แอปฝังกิจกรรมของแอปและควบคุมงานนำเสนอได้
ระบุแอตทริบิวต์ android:allowUntrustedActivityEmbedding
ใน
องค์ประกอบ <activity>
หรือ <application>
ในไฟล์ Manifest ของแอป ตัวอย่างเช่น
<activity
android:name=".MyEmbeddableActivity"
android:allowUntrustedActivityEmbedding="true"
... />
ค่าเริ่มต้นของแอตทริบิวต์คือ false ซึ่งจะป้องกันกิจกรรมข้ามแอป การฝังวิดีโอ
การตรวจสอบสิทธิ์ที่กำหนดเอง
หากต้องการลดความเสี่ยงของการฝังกิจกรรมที่ไม่น่าเชื่อถือ ให้สร้างกลไกการตรวจสอบสิทธิ์ที่กำหนดเองซึ่งจะยืนยันตัวตนของโฮสต์ ถ้าคุณรู้จักโฮสต์
ให้ใช้ไลบรารี androidx.security.app.authenticator
เพื่อ
ตรวจสอบสิทธิ์แล้ว ถ้าโฮสต์ตรวจสอบสิทธิ์หลังจากฝังกิจกรรม คุณจะดำเนินการต่อไปนี้ได้
แสดงเนื้อหาจริง หากไม่ คุณสามารถแจ้งให้ผู้ใช้ทราบว่าการดำเนินการดังกล่าวไม่ได้รับอนุญาตและบล็อกเนื้อหาได้
ใช้เมธอด ActivityEmbeddingController#isActivityEmbedded()
จากไลบรารี WindowManager ของ Jetpack เพื่อตรวจสอบว่าโฮสต์ฝังกิจกรรมของคุณอยู่หรือไม่ เช่น
Kotlin
fun isActivityEmbedded(activity: Activity): Boolean { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity) }
Java
boolean isActivityEmbedded(Activity activity) { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity); }
ข้อจำกัดด้านขนาดขั้นต่ำ
ระบบ Android จะใช้ความสูงและความกว้างขั้นต่ำที่ระบุไว้ในแอป
ไฟล์ Manifest <layout>
ลงในกิจกรรมที่ฝัง หากแอปพลิเคชันไม่ได้ระบุความสูงและความกว้างขั้นต่ำ ระบบจะใช้ค่าเริ่มต้น (sw220dp
)
หากโฮสต์พยายามปรับขนาดคอนเทนเนอร์ที่ฝังให้เล็กกว่าขนาดขั้นต่ำ คอนเทนเนอร์ที่ฝังจะขยายขนาดให้เต็มขอบเขตของงาน
<ชื่อแทนกิจกรรม>
หากต้องการให้การฝังกิจกรรมที่เชื่อถือได้หรือไม่เชื่อถือได้ทํางานกับองค์ประกอบ <activity-alias>
คุณต้องใส่ android:knownActivityEmbeddingCerts
หรือ android:allowUntrustedActivityEmbedding
ลงในกิจกรรมเป้าหมายแทนที่จะเป็นอีเมลแทน นโยบายที่ยืนยันความปลอดภัยในเซิร์ฟเวอร์ระบบจะอิงตาม Flag ที่กําหนดในเป้าหมาย ไม่ใช่ Alias
แอปพลิเคชันโฮสต์
แอปพลิเคชันโฮสต์ใช้การฝังกิจกรรมข้ามแอปในลักษณะเดียวกับที่ใช้การฝังกิจกรรมในแอปเดียว ออบเจ็กต์ SplitPairRule
และ SplitPairFilter
หรือ ActivityRule
และ ActivityFilter
จะระบุกิจกรรมที่ฝังไว้และการแยกหน้าต่างงาน กำหนดกฎการแยกแล้ว
แบบคงที่ใน XML หรือขณะรันไทม์โดยใช้ Jetpack
การเรียก WindowManager API
หากแอปพลิเคชันโฮสต์พยายามฝังกิจกรรมที่ไม่ได้เลือกเข้าร่วม การฝังข้ามแอป กิจกรรมจะอยู่ในขอบเขตของงานทั้งหมด ด้วยเหตุนี้ แอปพลิเคชันที่โฮสต์จำเป็นต้องทราบว่ากิจกรรมเป้าหมายอนุญาตข้ามแอปหรือไม่ การฝังวิดีโอ
หากกิจกรรมที่ฝังเริ่มกิจกรรมใหม่ในแท็บงานเดียวกัน และกิจกรรมใหม่ไม่ได้เลือกใช้การฝังข้ามแอป กิจกรรมดังกล่าวจะครอบครองขอบเขตแท็บงานทั้งหมดแทนการวางซ้อนกิจกรรมในคอนเทนเนอร์ที่ฝัง
แอปพลิเคชันโฮสต์สามารถฝังกิจกรรมของตัวเองได้โดยไม่มีข้อจำกัด กิจกรรมจะเปิดในงานเดียวกัน
แยกตัวอย่าง
แยกจากหน้าต่างแบบเต็ม
ไม่ต้องมีการปรับโครงสร้าง คุณสามารถกําหนดค่าสําหรับการแยกแบบคงที่หรือขณะรันไทม์ แล้วเรียกใช้ Context#startActivity()
โดยไม่ต้องมีพารามิเตอร์เพิ่มเติม
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
แยกโดยค่าเริ่มต้น
เมื่อหน้า Landing Page ของแอปพลิเคชันออกแบบมาให้แบ่งออกเป็นคอนเทนเนอร์ 2 รายการบนหน้าจอขนาดใหญ่ ประสบการณ์ของผู้ใช้จะดีที่สุดเมื่อสร้างและแสดงกิจกรรมทั้ง 2 รายการพร้อมกัน อย่างไรก็ตาม เนื้อหาอาจไม่พร้อมใช้งานสําหรับคอนเทนเนอร์รองของการแยกจนกว่าผู้ใช้จะโต้ตอบกับกิจกรรมในคอนเทนเนอร์หลัก (เช่น ผู้ใช้เลือกรายการจากเมนูการนำทาง) กิจกรรมตัวยึดตําแหน่งสามารถแสดงแทนที่เนื้อหาได้จนกว่าเนื้อหาจะแสดงในคอนเทนเนอร์รองของการแยก (ดูส่วนตัวยึดตําแหน่ง)
หากต้องการสร้างการแยกกับตัวยึดตำแหน่ง ให้สร้างตัวยึดตำแหน่งและเชื่อมโยงกับ กิจกรรมหลัก:
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
การแยก Deep Link
เมื่อแอปได้รับ Intent กิจกรรมเป้าหมายจะแสดงเป็นส่วนรองของการแยกกิจกรรม เช่น คําขอแสดงหน้าจอรายละเอียดที่มีข้อมูลเกี่ยวกับรายการจากรายการ ในจอแสดงผลขนาดเล็ก รายละเอียดจะแสดงในหน้าต่างงานแบบเต็ม ส่วนในอุปกรณ์ขนาดใหญ่ รายละเอียดจะแสดงข้างรายการ
คำขอเปิดใช้งานควรกำหนดเส้นทางไปยังกิจกรรมหลัก และควรเปิดใช้งานกิจกรรมรายละเอียดเป้าหมายแบบแยก ระบบจะเลือก การนำเสนอที่ถูกต้อง ทั้งกองซ้อนหรือควบคู่กัน โดยพิจารณาจากข้อมูลที่ ความกว้างของการแสดงผล
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)); }
ปลายทางของ Deep Link อาจเป็นกิจกรรมเดียวที่ผู้ใช้ควรเข้าถึงได้ในกองการนำทางด้านหลัง และคุณอาจไม่ต้องการปิดกิจกรรมรายละเอียดและเหลือไว้เฉพาะกิจกรรมหลัก
แต่คุณสามารถทำกิจกรรมทั้ง 2 อย่างให้เสร็จสิ้นในเวลาเดียวกันได้โดยใช้
แอตทริบิวต์ finishPrimaryWithSecondary
:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
ดูส่วนแอตทริบิวต์การกำหนดค่า
กิจกรรมหลายรายการในคอนเทนเนอร์แบบแยกส่วน
การวางซ้อนกิจกรรมหลายรายการในคอนเทนเนอร์ที่แยกส่วนช่วยให้ผู้ใช้เข้าถึง เนื้อหา ตัวอย่างเช่น เมื่อแบ่งรายละเอียดรายการ ผู้ใช้อาจต้องไปที่ รายละเอียดย่อย แต่เก็บกิจกรรมหลักไว้ตามเดิม:
Kotlin
class DetailActivity { . . . fun onOpenSubDetail() { startActivity(Intent(this, SubDetailActivity::class.java)) } }
Java
public class DetailActivity { . . . void onOpenSubDetail() { startActivity(new Intent(this, SubDetailActivity.class)); } }
กิจกรรมรายละเอียดย่อยจะแสดงอยู่ด้านบนของกิจกรรมรายละเอียดโดยปกปิดไว้
จากนั้นผู้ใช้จะสามารถกลับไปยังระดับรายละเอียดก่อนหน้าได้โดยการย้อนกลับ ผ่านสแต็กด้วย
การวางกิจกรรมที่วางซ้อนกันเป็นลักษณะการทำงานเริ่มต้นเมื่อกิจกรรม เปิดขึ้นจากกิจกรรมในคอนเทนเนอร์รองเดียวกัน กิจกรรม ที่เปิดจากคอนเทนเนอร์หลักภายในการแยกที่ทำงานอยู่ก็ไปรวมอยู่ใน คอนเทนเนอร์รองที่ด้านบนของสแต็กกิจกรรม
กิจกรรมในงานใหม่
เมื่อกิจกรรมในหน้าต่างงานแบบแยกเริ่มกิจกรรมในงานใหม่ งานใหม่จะแยกจากงานที่มีการแยกและแสดงเต็มหน้าต่าง หน้าจอล่าสุดจะแสดงงาน 2 รายการ ได้แก่ งานในหน้าจอแยกและงานใหม่
การเปลี่ยนกิจกรรม
กิจกรรมสามารถแทนที่ในกองคอนเทนเนอร์รองได้ เช่น เมื่อใช้กิจกรรมหลักสำหรับการนําทางระดับบนสุดและกิจกรรมรองเป็นปลายทางที่เลือก การเลือกแต่ละรายการจากการนำทางระดับบนสุดควร เริ่มกิจกรรมใหม่ในคอนเทนเนอร์รอง และนำกิจกรรมนั้นออกหรือ กิจกรรมที่เคยอยู่ที่นั่น
หากแอปไม่ทำกิจกรรมในคอนเทนเนอร์รองให้เสร็จสิ้นเมื่อตัวเลือกการไปยังส่วนต่างๆ เปลี่ยนแปลง การนำทางกลับอาจทำให้เกิดความสับสนเมื่อยุบการแยก (เมื่อพับอุปกรณ์) เช่น หากคุณมีเมนูในแผงหลักและหน้าจอ A และ B ซ้อนกันในแผงรอง เมื่อผู้ใช้พับโทรศัพท์ หน้าจอ B จะวางอยู่ด้านบนของหน้าจอ A และหน้าจอ A จะวางอยู่ด้านบนของเมนู เมื่อผู้ใช้กลับไปจาก B ตัวเลือก A จะปรากฏขึ้นแทนเมนู
ในกรณีเช่นนี้ คุณต้องนำหน้าจอ ก ออกจากกองซ้อนด้านหลัง
ลักษณะการทำงานเริ่มต้นเมื่อเปิดในแนวนอนในคอนเทนเนอร์ใหม่เหนือการแยกที่มีอยู่คือการวางคอนเทนเนอร์รองใหม่ไว้ที่ด้านบนและเก็บคอนเทนเนอร์เก่าไว้ในกองซ้อนด้านหลัง คุณกำหนดค่าการแยกเพื่อล้าง
คอนเทนเนอร์รองที่มี clearTop
และเรียกใช้กิจกรรมใหม่ตามปกติ
<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))); } }
อีกวิธีหนึ่งคือใช้กิจกรรมรองเดียวกัน และจาก (เมนู) หลัก กิจกรรมจะส่ง Intent ใหม่ที่แก้ไขเป็นอินสแตนซ์เดียวกันแต่ทริกเกอร์สถานะ หรือการอัปเดต UI ในคอนเทนเนอร์รอง
การแยกหลายรายการ
แอปสามารถให้บริการนำทางแบบลึกหลายระดับได้ด้วยการเปิดตัวกิจกรรมเพิ่มเติม อยู่ด้านข้าง
เมื่อกิจกรรมในคอนเทนเนอร์รองเปิดกิจกรรมใหม่ด้านข้าง มีการสร้างการแยกใหม่ทับบนการแบ่งที่มีอยู่
กองซ้อนที่ย้อนกลับจะมีกิจกรรมทั้งหมดที่เปิดไว้ก่อนหน้านี้ เพื่อให้ผู้ใช้ไปยังการแยกกลุ่ม A/B ได้หลังจากทำ C เสร็จแล้ว
หากต้องการสร้างการแยกใหม่ ให้เปิดตัวกิจกรรมใหม่ต่อจากกิจกรรมที่มีอยู่ คอนเทนเนอร์รอง ประกาศการกําหนดค่าสําหรับทั้งกลุ่ม A/B และ B/C และเปิดใช้งานกิจกรรม C ตามปกติจาก 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)); } }
ตอบสนองต่อการเปลี่ยนแปลงสถานะแบบแยก
กิจกรรมต่างๆ ในแอปอาจมีองค์ประกอบ UI ที่ทํางานแบบเดียวกัน เช่น การควบคุมที่เปิดหน้าต่างที่มีการตั้งค่าบัญชี
หากกิจกรรม 2 รายการที่มีองค์ประกอบ UI เหมือนกันอยู่ 2 อย่าง ซ้ำซ้อนและอาจทำให้สับสนในการแสดงองค์ประกอบในทั้ง 2 กิจกรรม
หากต้องการทราบว่ากิจกรรมอยู่ในสถานะแยกหรือไม่ ให้ตรวจสอบโฟลว์ SplitController.splitInfoList
หรือลงทะเบียนโปรแกรมฟังกับ SplitControllerCallbackAdapter
เพื่อดูการเปลี่ยนแปลงในสถานะแยก จากนั้นปรับ UI ให้เหมาะสม ดังนี้
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 ได้ในสภาวะของวงจรชีวิตทุกแบบ แต่โดยทั่วไปจะเปิดตัวใน
สถานะ STARTED
เพื่ออนุรักษ์ทรัพยากร (ดูใช้โครูทีน Kotlin กับ
หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับคอมโพเนนต์ที่รับรู้ทุกวงจร)
คุณสามารถเรียกใช้การเรียกกลับได้ในสถานะวงจรใดก็ได้ รวมถึงเมื่อกิจกรรมหยุดลง โดยปกติแล้ว ผู้ฟังควรจดทะเบียนใน onStart()
และไม่ได้จดทะเบียนใน onStop()
โมดัลหน้าต่างเต็ม
บางกิจกรรมจะบล็อกไม่ให้ผู้ใช้โต้ตอบกับแอปพลิเคชันจนกว่าจะ มีการดำเนินการที่ระบุ เช่น กิจกรรมในหน้าจอเข้าสู่ระบบ นโยบาย หน้าจอรับทราบ หรือข้อความแสดงข้อผิดพลาด ควรป้องกันกิจกรรมโมดัล ออกจากการแสดงแบบแยกส่วน
คุณสามารถบังคับให้กิจกรรมเติมหน้าต่างงานเสมอด้วยการใช้ปุ่มขยาย การกำหนดค่า:
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
กิจกรรมเสร็จสิ้น
ผู้ใช้สามารถทำงานให้เสร็จสมบูรณ์ในแต่ละด้านของการแยกหน้าจอโดยการปัดจากขอบของจอแสดงผล ดังนี้
หากอุปกรณ์ได้รับการตั้งค่าให้ใช้ปุ่มย้อนกลับแทนการนำทางด้วยท่าทางสัมผัส ระบบจะส่งข้อมูลไปยังกิจกรรมที่โฟกัส ซึ่งก็คือกิจกรรมที่มีการแตะ หรือ เปิดตัวล่าสุด
ผลจากการสิ้นสุดกิจกรรมทั้งหมดในคอนเทนเนอร์มีต่อฝ่ายตรงข้าม ขึ้นอยู่กับการกำหนดค่าการแยก
แอตทริบิวต์การกําหนดค่า
คุณสามารถระบุแอตทริบิวต์กฎคู่แยกเพื่อกําหนดค่าผลที่การสิ้นสุดกิจกรรมทั้งหมดในฝั่งหนึ่งของการแยกมีผลต่อกิจกรรมในฝั่งอื่นของการแยก แอตทริบิวต์ดังกล่าวมีดังนี้
window:finishPrimaryWithSecondary
— ผลกระทบที่การทํากิจกรรมทั้งหมดในคอนเทนเนอร์รองต่อกิจกรรมในคอนเทนเนอร์หลักwindow:finishSecondaryWithPrimary
— สิ้นสุดกิจกรรมทั้งหมดใน คอนเทนเนอร์หลักส่งผลต่อกิจกรรมในคอนเทนเนอร์รอง
ค่าที่เป็นไปได้ของแอตทริบิวต์ ได้แก่
always
— ทำกิจกรรมในคอนเทนเนอร์ที่เกี่ยวข้องให้เสร็จสิ้นเสมอnever
— ไม่เคยทำกิจกรรมในคอนเทนเนอร์ที่เกี่ยวข้องให้เสร็จadjacent
— ดำเนินกิจกรรมในคอนเทนเนอร์ที่เชื่อมโยงให้เสร็จเมื่อ คอนเทนเนอร์ 2 รายการจะแสดงติดกัน แต่ไม่แสดงเมื่อ คอนเทนเนอร์ 2 รายการซ้อนกัน
เช่น
<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>
การกำหนดค่าเริ่มต้น
เมื่อกิจกรรมทั้งหมดในคอนเทนเนอร์หนึ่งของการแยกเสร็จสิ้น คอนเทนเนอร์ที่เหลือ กินพื้นที่หน้าต่างทั้งหมด:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
ทำกิจกรรมร่วมกันให้เสร็จ
ทำกิจกรรมในคอนเทนเนอร์หลักให้เสร็จโดยอัตโนมัติเมื่อกิจกรรมทั้งหมด ในคอนเทนเนอร์รองเสร็จสิ้น:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
ทำกิจกรรมในคอนเทนเนอร์รองให้เสร็จโดยอัตโนมัติเมื่อทั้งหมด กิจกรรมในคอนเทนเนอร์หลักเสร็จสิ้น:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
ทำกิจกรรมให้เสร็จร่วมกันเมื่อกิจกรรมทั้งหมดในกิจกรรมหลักหรือ ทำให้คอนเทนเนอร์รองเสร็จสิ้น:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
ทํากิจกรรมหลายอย่างในคอนเทนเนอร์ให้เสร็จ
หากมีกิจกรรมหลายรายการซ้อนกันในคอนเทนเนอร์แบบแยก การทำกิจกรรมที่ด้านล่างของกองให้เสร็จสมบูรณ์จะไม่ทำให้กิจกรรมที่ด้านบนเสร็จสมบูรณ์โดยอัตโนมัติ
ตัวอย่างเช่น หากมีกิจกรรม 2 รายการอยู่ในคอนเทนเนอร์รอง โดย C อยู่ด้านบนของ B
และการกำหนดค่าการแยกจะกำหนดโดยการกำหนดค่ากิจกรรม ก และ ข:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
การสิ้นสุดกิจกรรมยอดนิยมจะเก็บการแยกไว้
การดำเนินการเสร็จสิ้นกิจกรรมด้านล่าง (ราก) ของคอนเทนเนอร์รองจะไม่นำออก กิจกรรมนอกเหนือจากนั้น และจะยังเก็บฝั่งที่แยกไว้
ระบบจะดำเนินการตามกฎเพิ่มเติมสำหรับการสิ้นสุดกิจกรรมร่วมกัน เช่น การสิ้นสุดกิจกรรมรองด้วยกิจกรรมหลัก
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
และเมื่อกำหนดค่าการแยกให้จบทั้งประถมศึกษาและรองพร้อมกันแล้ว
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
เปลี่ยนพร็อพเพอร์ตี้การแยกขณะรันไทม์
คุณจะเปลี่ยนพร็อพเพอร์ตี้ของการแยกที่ใช้งานอยู่และมองเห็นได้ไม่ได้ การเปลี่ยน กฎการแยกมีผลต่อการเรียกใช้กิจกรรมเพิ่มเติมและคอนเทนเนอร์ใหม่ แต่ไม่มีผลกับ การแยกที่มีอยู่และใช้งานอยู่
หากต้องการเปลี่ยนพร็อพเพอร์ตี้ของการแยกที่ใช้งานอยู่ ให้ทํากิจกรรมในแถบข้างให้เสร็จแล้วเปิดแถบข้างอีกครั้งด้วยการกำหนดค่าใหม่
พร็อพเพอร์ตี้การแยกแบบไดนามิก
Android 15 (API ระดับ 35) ขึ้นไปที่ Jetpack รองรับ WindowManager 1.4 และที่สูงกว่านำเสนอฟีเจอร์แบบไดนามิก ที่ช่วยให้กำหนดค่ากิจกรรมได้ การแยกการฝัง รวมถึง
- การขยายแพ็กเกจ: ตัวแบ่งแบบอินเทอร์แอกทีฟที่ลากได้ช่วยให้ผู้ใช้ทำสิ่งต่างๆ ต่อไปนี้ได้ ปรับขนาดแผงในงานนำเสนอแบบแยก
- การปักหมุดกิจกรรม: ผู้ใช้สามารถปักหมุดเนื้อหาในคอนเทนเนอร์หนึ่งและแยกการไปยังส่วนต่างๆ ในคอนเทนเนอร์นั้นจากการไปยังส่วนต่างๆ ในคอนเทนเนอร์อื่น
- การหรี่แสงกล่องโต้ตอบแบบเต็มหน้าจอ: เมื่อแสดงกล่องโต้ตอบ แอปสามารถระบุ จะหรี่แสงหน้าต่างงานทั้งหมด หรือเฉพาะคอนเทนเนอร์ที่เปิดหน้าต่างงาน กล่องโต้ตอบ
การขยายแผง
การขยายแผงช่วยให้ผู้ใช้ปรับจำนวนพื้นที่หน้าจอที่จัดสรรให้ กิจกรรมทั้ง 2 รายการในเค้าโครงแบบ 2 แผง
หากต้องการปรับแต่งลักษณะที่ปรากฏของตัวแบ่งหน้าต่างและตั้งค่าช่วงการลากของตัวแบ่ง ให้ทำดังนี้
สร้างอินสแตนซ์ของ
DividerAttributes
ปรับแต่งแอตทริบิวต์ตัวแบ่ง ดังนี้
color
: สีของตัวคั่นแผงแบบลากได้widthDp
: ความกว้างของตัวคั่นแผงแบบลากได้ ตั้งค่าเป็นWIDTH_SYSTEM_DEFAULT
เพื่อให้ระบบกำหนดความกว้างของส่วนแบ่งช่วงการลาก: เปอร์เซ็นต์ขั้นต่ำของหน้าจอที่แผงใดก็ได้สามารถ ครอบครองอยู่ มีค่าได้ตั้งแต่ 0.33-0.66 กำหนดเป็น
DRAG_RANGE_SYSTEM_DEFAULT
เพื่อให้ระบบระบุการลาก
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();
การปักหมุดกิจกรรม
การปักหมุดกิจกรรมช่วยให้ผู้ใช้ปักหมุดหน้าต่างแยกหน้าจอรายการใดรายการหนึ่งเพื่อให้กิจกรรมคงอยู่เหมือนเดิมขณะที่ผู้ใช้ไปยังส่วนต่างๆ ในหน้าต่างอีกบาน กิจกรรม ปักหมุด จะมอบประสบการณ์การทำงานหลายอย่างพร้อมกันที่ดีขึ้น
หากต้องการเปิดใช้การปักหมุดกิจกรรมในแอป ให้ทำดังนี้
เพิ่มปุ่มลงในไฟล์เลย์เอาต์ของกิจกรรมที่ต้องการปักหมุด ตัวอย่างเช่น กิจกรรมรายละเอียดของเลย์เอาต์รายละเอียดรายการ
<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>
ในเมธอด
onCreate()
ของกิจกรรม ให้ตั้งค่า Listener ของ onclick ในปุ่ม ดังนี้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); });
ปรับความสว่างแบบเต็มหน้าจอ
โดยทั่วไป กิจกรรมจะหรี่แสงจอแสดงผลเพื่อดึงดูดความสนใจมาที่กล่องโต้ตอบ ใน กิจกรรมที่ฝัง หน้าจอทั้ง 2 แผงควรหรี่แสง ไม่ใช่ เฉพาะแผงที่มีกิจกรรมที่เปิดกล่องโต้ตอบ สำหรับ UI แบบรวม ประสบการณ์การใช้งาน
เมื่อใช้ WindowManager 1.4 ขึ้นไป หน้าต่างแอปทั้งหมดจะสลัวลงโดยค่าเริ่มต้นเมื่อกล่องโต้ตอบเปิดขึ้น (ดู EmbeddingConfiguration.DimAreaBehavior.ON_TASK
)
หากต้องการหรี่เฉพาะคอนเทนเนอร์ของกิจกรรมที่เปิดกล่องโต้ตอบ ให้ใช้
EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK
ดึงข้อมูลกิจกรรมจากหน้าต่างที่แยกออกเป็นแบบเต็มหน้าจอ
สร้างการกำหนดค่าใหม่ที่แสดงกิจกรรมด้านข้างแบบเต็มหน้าต่าง จากนั้น เรียกกิจกรรมอีกครั้งด้วย Intent ที่แก้ไขเป็นอินสแตนซ์เดียวกัน
ตรวจสอบการรองรับการแยกขณะรันไทม์
การฝังกิจกรรมใช้ได้ใน Android 12L (API ระดับ 32) ขึ้นไป แต่จะใช้ได้ในอุปกรณ์บางรุ่นที่ใช้แพลตฟอร์มเวอร์ชันเก่ากว่าด้วย หากต้องการตรวจสอบความพร้อมใช้งานของฟีเจอร์ขณะรันไทม์ ให้ใช้พร็อพเพอร์ตี้ SplitController.splitSupportStatus
หรือเมธอด 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. }
หากไม่รองรับการแยก กิจกรรมจะเปิดขึ้นพร้อมกับกิจกรรม สแต็ก (ตามโมเดลการฝังที่ไม่ใช่กิจกรรม)
ป้องกันการลบล้างระบบ
ผู้ผลิตอุปกรณ์ Android (ผู้ผลิตอุปกรณ์ดั้งเดิมหรือ OEM) สามารถใช้การฝังกิจกรรมเป็นฟังก์ชันของระบบอุปกรณ์ได้ ระบบระบุกฎการแยกสำหรับแอปที่มีกิจกรรมหลายรายการ โดยจะลบล้างกรอบเวลา พฤติกรรมของแอป การลบล้างของระบบจะบังคับให้แอปหลายกิจกรรมเข้าสู่โหมดการฝังกิจกรรมที่ระบบกําหนด
การฝังกิจกรรมของระบบจะช่วยปรับปรุงการนำเสนอแอปผ่านหลายหน้าต่าง เช่น list-detail โดยไม่ต้องเปลี่ยนแปลงแอป อย่างไรก็ตาม การฝังกิจกรรมของระบบยังอาจทำให้เกิดการจัดวางแอป ข้อบกพร่อง หรือ ขัดแย้งกับการฝังกิจกรรมที่แอปใช้
แอปของคุณสามารถป้องกันหรืออนุญาตการฝังกิจกรรมของระบบโดยการตั้งค่า พร็อพเพอร์ตี้ในไฟล์ Manifest ของแอป เช่น
<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>
ชื่อพร็อพเพอร์ตี้จะกำหนดไว้ใน Jetpack WindowManager WindowProperties
ออบเจ็กต์ ตั้งค่าเป็น false
หากแอปของคุณใช้การฝังกิจกรรม หรือหากต้องการป้องกันไม่ให้ระบบใช้กฎการฝังกิจกรรมกับแอปของคุณ ให้ตั้งค่าเป็น true
เพื่ออนุญาตให้ระบบใช้การฝังกิจกรรมที่ระบบกําหนดกับแอปของคุณ
ข้อจำกัด ข้อจํากัด และข้อควรระวัง
- เฉพาะแอปโฮสต์ของงานซึ่งระบุว่าเป็นเจ้าของกิจกรรมรูทในงานนี้เท่านั้นที่จะจัดระเบียบและฝังกิจกรรมอื่นๆ ในงานนี้ได้ หากกิจกรรมที่รองรับการฝังและการแยกทำงานในงานที่เป็น ไปยังแอปพลิเคชันอื่น การฝังและการแยกจะไม่ทำงาน กิจกรรมเหล่านั้น
- คุณจะจัดระเบียบกิจกรรมได้ภายในงานเดียวเท่านั้น การเริ่มกิจกรรมในแท็บงานใหม่จะวางกิจกรรมนั้นในหน้าต่างใหม่ที่ขยายออกเสมอ นอกเหนือไปจากการแยกที่มีอยู่
- คุณจะจัดระเบียบและแยกเฉพาะกิจกรรมที่อยู่ในกระบวนการเดียวกันได้
Callback ของ
SplitInfo
จะรายงานเฉพาะกิจกรรมที่เป็นของบัญชีเดียวกัน เนื่องจากไม่มีทางทราบเกี่ยวกับกิจกรรมต่างๆ ใน กระบวนการ - กฎกิจกรรมแต่ละคู่หรือกฎเดียวจะมีผลเฉพาะกับการเปิดตัวกิจกรรมที่ จะเกิดขึ้นหลังจากที่ลงทะเบียนกฎแล้ว ปัจจุบันยังไม่มีวิธี อัปเดตการแยกที่มีอยู่หรือคุณสมบัติการแสดงผล
- การกําหนดค่าตัวกรองคู่ที่แยกต้องตรงกับ Intent ที่ใช้เมื่อเปิดใช้งานกิจกรรมโดยสมบูรณ์ การจับคู่จะเกิดขึ้น ณ เวลาที่ กิจกรรมนั้นเริ่มต้นจากขั้นตอนการสมัคร จึงอาจไม่ทราบเกี่ยวกับ ชื่อคอมโพเนนต์ที่ได้รับการแก้ไขในภายหลังในกระบวนการของระบบเมื่อใช้ Intent แบบไม่เจาะจงปลายทาง หากไม่ทราบชื่อคอมโพเนนต์เมื่อเปิดตัว สามารถใช้ไวลด์การ์ดแทน ("*/*") และดำเนินการกรองได้ตาม เกี่ยวกับการดำเนินการผ่าน Intent
- ปัจจุบันยังไม่มีวิธีย้ายกิจกรรมระหว่างคอนเทนเนอร์ หรือย้ายกิจกรรมเข้าและออกจากการแยกหลังจากที่สร้างแล้ว การแยกถูกสร้างขึ้นโดย ไลบรารี WindowManager เมื่อมีการเปิดตัวกิจกรรมใหม่ที่มีกฎที่ตรงกัน และการแยกจะถูกทำลายเมื่อกิจกรรมล่าสุดในคอนเทนเนอร์ที่แบ่งเป็น เสร็จสิ้นแล้ว
- กิจกรรมจะเปิดอีกครั้งได้เมื่อการกำหนดค่ามีการเปลี่ยนแปลง มีการสร้างหรือนำออก และขอบเขตของกิจกรรมมีการเปลี่ยนแปลง ผ่านการทำลายอินสแตนซ์ก่อนหน้าโดยสมบูรณ์และการสร้าง อันใหม่นะ ดังนั้น นักพัฒนาแอปควรระมัดระวังเรื่องต่างๆ เช่น การเริ่มกิจกรรมใหม่จากการเรียกกลับของวงจร
- อุปกรณ์ต้องมีอินเทอร์เฟซส่วนขยายหน้าต่างเพื่อรองรับการฝังกิจกรรม อุปกรณ์หน้าจอขนาดใหญ่เกือบทั้งหมดที่ใช้ Android 12L (API ระดับ 32) ขึ้นไปจะมีอินเทอร์เฟซนี้ อย่างไรก็ตาม อุปกรณ์หน้าจอขนาดใหญ่บางรุ่นที่ไม่สามารถเรียกใช้กิจกรรมหลายรายการจะไม่มีอินเทอร์เฟซส่วนขยายหน้าต่าง หากอุปกรณ์ที่มีหน้าจอขนาดใหญ่ไม่รองรับหลายหน้าต่าง แสดงว่าอาจไม่รองรับการฝังกิจกรรม
แหล่งข้อมูลเพิ่มเติม
- Codelabs:
- เส้นทางการเรียนรู้ — การฝังกิจกรรม
- แอปตัวอย่าง — activity-embedding