ข่าวสารผลิตภัณฑ์

มีอะไรใหม่ใน Jetpack Compose รุ่นเดือนธันวาคม 2025

ใช้เวลาอ่าน 6 นาที
Nick Butcher
ผู้จัดการผลิตภัณฑ์

วันนี้ Jetpack Compose รุ่นเดือนธันวาคม 2025 พร้อมให้ใช้งานอย่างเสถียรแล้ว ซึ่งประกอบด้วยโมดูล Compose หลักเวอร์ชัน 1.10 และ Material 3 เวอร์ชัน 1.4 (ดูการแมป BOM แบบเต็ม) พร้อมเพิ่มฟีเจอร์ใหม่และการปรับปรุงประสิทธิภาพที่สำคัญ

หากต้องการใช้รุ่นที่เปิดตัวในวันนี้ ให้อัปเกรดเวอร์ชัน Compose BOM เป็น 2025.12.00 โดยทำดังนี้

implementation(platform("androidx.compose:compose-bom:2025.12.00"))

การปรับปรุงประสิทธิภาพ

เราทราบดีว่าประสิทธิภาพขณะรันไทม์ของแอปมีความสำคัญอย่างยิ่งต่อคุณและผู้ใช้ ทีม Compose จึงให้ความสำคัญกับประสิทธิภาพเป็นอันดับแรก การเปิดตัวนี้มาพร้อมการปรับปรุงหลายอย่าง และคุณจะได้รับการปรับปรุงทั้งหมดนี้เพียงแค่อัปเกรดเป็นเวอร์ชันล่าสุด การเปรียบเทียบการเลื่อนภายในของเราแสดงให้เห็นว่าตอนนี้ Compose มีประสิทธิภาพเทียบเท่ากับที่คุณจะเห็นหากใช้ Views ดังนี้

janky.png

การเปรียบเทียบประสิทธิภาพการเลื่อนระหว่าง Views กับ Jetpack Compose ใน Compose เวอร์ชันต่างๆ

การจัดองค์ประกอบที่หยุดชั่วคราวได้ในการดึงข้อมูลล่วงหน้าแบบเลซี่

ตอนนี้ระบบจะเปิดใช้การคอมโพสที่หยุดชั่วคราวได้ในการดึงข้อมูลล่วงหน้าแบบ Lazy โดยค่าเริ่มต้น การเปลี่ยนแปลงนี้เป็นการเปลี่ยนแปลงพื้นฐานเกี่ยวกับวิธีที่รันไทม์ของ Compose จัดกำหนดการงาน ซึ่งออกแบบมาเพื่อลดการกระตุกอย่างมากในระหว่างภาระงาน UI ที่หนัก

ก่อนหน้านี้ เมื่อเริ่มการคอมโพสแล้ว ก็ต้องดำเนินการให้เสร็จสมบูรณ์ หากการคอมโพสิตมีความซับซ้อน อาจบล็อกเทรดหลักนานกว่า 1 เฟรม ทำให้ UI ค้าง การคอมโพสที่หยุดชั่วคราวได้ทำให้รันไทม์สามารถ "หยุดชั่วคราว" การทำงานได้หากเวลาเหลือน้อย และกลับมาทำงานต่อในเฟรมถัดไป ซึ่งจะมีประสิทธิภาพเป็นพิเศษเมื่อใช้ร่วมกับการดึงข้อมูลล่วงหน้าของเลย์เอาต์แบบเลซีเพื่อเตรียมเฟรมล่วงหน้า API CacheWindow ของเลย์เอาต์แบบ Lazy ที่เปิดตัวใน Compose 1.9 เป็นวิธีที่ยอดเยี่ยมในการดึงข้อมูลเนื้อหาเพิ่มเติมล่วงหน้าและใช้ประโยชน์จากการจัดองค์ประกอบที่หยุดชั่วคราวได้เพื่อสร้างประสิทธิภาพ UI ที่ราบรื่นยิ่งขึ้น

pausable.gif

การคอมโพสที่หยุดชั่วคราวได้ร่วมกับการดึงข้อมูลล่วงหน้าแบบ Lazy จะช่วยลดอาการกระตุก

นอกจากนี้ เรายังได้เพิ่มประสิทธิภาพในส่วนอื่นๆ ด้วยการปรับปรุง Modifier.onPlaced, Modifier.onVisibilityChanged และการใช้ตัวแก้ไขอื่นๆ เราจะยังคงมุ่งมั่นปรับปรุงประสิทธิภาพของ Compose ต่อไป

ฟีเจอร์ใหม่

เก็บรักษา

Compose มี API หลายรายการสำหรับเก็บและจัดการสถานะในวงจรต่างๆ เช่น remember จะคงสถานะไว้ในคอมโพสิต และ rememberSavable/rememberSerializable จะคงสถานะไว้ในกิจกรรมหรือการสร้างกระบวนการใหม่ retain เป็น API ใหม่ที่อยู่ระหว่าง API เหล่านี้ ซึ่งช่วยให้คุณคงค่าไว้ได้เมื่อมีการเปลี่ยนแปลงการกำหนดค่าโดยไม่ต้องทำการซีเรียลไลซ์ แต่จะคงค่าไว้ไม่ได้เมื่อการประมวลผลสิ้นสุดลง เนื่องจาก retain ไม่ได้ทำให้สถานะของคุณเป็นแบบอนุกรม คุณจึงสามารถคงออบเจ็กต์ต่างๆ เช่น นิพจน์ Lambda, Flow และออบเจ็กต์ขนาดใหญ่ เช่น บิตแมป ซึ่งทำให้เป็นแบบอนุกรมได้ยาก เช่น คุณอาจใช้ retain เพื่อจัดการโปรแกรมเล่นสื่อ (เช่น ExoPlayer) เพื่อให้แน่ใจว่าการเล่นสื่อจะไม่ถูกขัดจังหวะเนื่องจากการเปลี่ยนแปลงการกำหนดค่า

@Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

    val exoPlayer = retain { ExoPlayer.Builder(applicationContext).apply { ... }.build() }

    ...

}

เราขอขอบคุณชุมชน AndroidDev (โดยเฉพาะทีม Circuit) ที่มีอิทธิพลและมีส่วนร่วมในการออกแบบฟีเจอร์นี้

เนื้อหา 1.4

เวอร์ชัน 1.4.0 ของไลบรารี material3 มีคอมโพเนนต์และการปรับปรุงใหม่ๆ ดังนี้

  • TextField ตอนนี้มีเวอร์ชันทดลองที่อิงตาม TextFieldState ซึ่งเป็นวิธีที่มีประสิทธิภาพมากขึ้นในการจัดการสถานะของข้อความ นอกจากนี้ เรายังมีตัวเลือก SecureTextField และ OutlinedSecureTextField ใหม่ให้เลือกด้วย ตอนนี้ Material Text Composable รองรับลักษณะการทำงานของ autoSize แล้ว
  • ตอนนี้คอมโพเนนต์ภาพสไลด์มีHorizontalCenteredHeroCarousel รูปแบบใหม่แล้ว
  • TimePicker รองรับการสลับระหว่างโหมดเครื่องมือเลือกและโหมดป้อนข้อมูลแล้ว
  • แฮนเดิลการลากแนวตั้งช่วยให้ผู้ใช้เปลี่ยนขนาดและ/หรือตำแหน่งของแผงแบบปรับได้
centered-hero-carousel.webp

ภาพสไลด์ฮีโร่แนวนอนตรงกลาง

โปรดทราบว่า API ของ Material 3 Expressive ยังคงได้รับการพัฒนาในรุ่นอัลฟ่าของไลบรารี material3 ดูข้อมูลเพิ่มเติมได้จากการพูดคุยล่าสุดนี้

ฟีเจอร์ภาพเคลื่อนไหวใหม่

เราจะขยาย API ของภาพเคลื่อนไหวต่อไป ซึ่งรวมถึงการอัปเดตสำหรับการปรับแต่งภาพเคลื่อนไหวขององค์ประกอบที่แชร์

องค์ประกอบที่ใช้ร่วมกันแบบไดนามิก

โดยค่าเริ่มต้น ภาพเคลื่อนไหว sharedElement() และ sharedBounds() จะพยายามเคลื่อนไหว

เลย์เอาต์จะเปลี่ยนเมื่อใดก็ตามที่พบคีย์ที่ตรงกันในสถานะเป้าหมาย อย่างไรก็ตาม คุณอาจต้องการปิดใช้ภาพเคลื่อนไหวนี้แบบไดนามิกตามเงื่อนไขบางอย่าง เช่น ทิศทางการนำทางหรือสถานะ UI ปัจจุบัน

หากต้องการควบคุมว่าจะให้มีการเปลี่ยนองค์ประกอบที่แชร์หรือไม่ ตอนนี้คุณสามารถปรับแต่ง SharedContentConfig ที่ส่งไปยัง rememberSharedContentState() ได้แล้ว พร็อพเพอร์ตี้ isEnabled จะกำหนดว่าองค์ประกอบที่แชร์ใช้งานอยู่หรือไม่

SharedTransitionLayout {

        val transition = updateTransition(currentState)

        transition.AnimatedContent { targetState ->

            // Create the configuration that depends on state changing.

            fun animationConfig() : SharedTransitionScope.SharedContentConfig {

                return object : SharedTransitionScope.SharedContentConfig {

                    override val SharedTransitionScope.SharedContentState.isEnabled: Boolean

                        get() =

                            // determine whether to perform a shared element transition

                }

            }

}

ดูข้อมูลเพิ่มเติมได้ในเอกสารประกอบ

Modifier.skipToLookaheadPosition()

เราได้เพิ่มตัวแก้ไขใหม่ Modifier.skipToLookaheadPosition() ในรุ่นนี้ ซึ่งจะคงตำแหน่งสุดท้ายของ Composable เมื่อทำการเปลี่ยนภาพองค์ประกอบที่แชร์ ซึ่งจะช่วยให้ทำการเปลี่ยนภาพได้ เช่น ภาพเคลื่อนไหวประเภท "เปิดเผย" ดังที่เห็นในตัวอย่าง Androidify ที่มีการเปิดเผยกล้องแบบค่อยๆ ดูข้อมูลเพิ่มเติมได้ที่เคล็ดลับวิดีโอที่นี่ 

ความเร็วเริ่มต้นในการเปลี่ยนภาพองค์ประกอบแบบใช้ร่วมกัน

การเปิดตัวนี้ได้เพิ่ม API การเปลี่ยนภาพองค์ประกอบที่ใช้ร่วมกันใหม่ prepareTransitionWithInitialVelocity ซึ่งช่วยให้คุณส่งความเร็วเริ่มต้น (เช่น จากท่าทางสัมผัส) ไปยังการเปลี่ยนภาพองค์ประกอบที่ใช้ร่วมกันได้

Modifier.fillMaxSize()

    .draggable2D(

        rememberDraggable2DState { offset += it },

        onDragStopped = { velocity ->

            // Set up the initial velocity for the upcoming shared element

            // transition.

            sharedContentStateForDraggableCat

                ?.prepareTransitionWithInitialVelocity(velocity)

            showDetails = false

        },

    )
fling-shared.gif

การเปลี่ยนภาพองค์ประกอบแบบใช้ร่วมกันที่เริ่มต้นด้วยความเร็วเริ่มต้นจากท่าทางสัมผัส

การเปลี่ยนฉากที่ซ่อนเร้น

EnterTransition และ ExitTransition จะกำหนดวิธีที่ Composable AnimatedVisibility/AnimatedContent ปรากฏหรือหายไป ตัวเลือกม่านบังตาแบบทดลองใหม่ช่วยให้คุณระบุสีเพื่อบังหรือกรองเนื้อหาได้ เช่น การค่อยๆ เพิ่ม/ลดเลเยอร์สีดำแบบกึ่งทึบแสงเหนือเนื้อหา

veil_2.gif

เนื้อหาภาพเคลื่อนไหวที่ซ่อนอยู่ - สังเกตม่านกึ่งโปร่งแสง (หรือฉากกั้น) เหนือเนื้อหาตารางระหว่างภาพเคลื่อนไหว

AnimatedContent(

    targetState = page,

    modifier = Modifier.fillMaxSize().weight(1f),

    transitionSpec = {

        if (targetState > initialState) {

            (slideInHorizontally { it } togetherWith

                    slideOutHorizontally { -it / 2 } + veilOut(targetColor = veilColor))

        } else {

            slideInHorizontally { -it / 2 } +

                    unveilIn(initialColor = veilColor) togetherWith slideOutHorizontally { it }

        }

    },

) { targetPage ->

    ...

}

การเปลี่ยนแปลงที่กำลังจะเกิดขึ้น

การเลิกใช้งาน Modifier.onFirstVisible

Compose 1.9 เปิดตัว Modifier.onVisibilityChanged และ Modifier.onFirstVisible หลังจากตรวจสอบความคิดเห็นของคุณแล้ว เราพบว่าไม่สามารถปฏิบัติตามสัญญาของ Modifier.onFirstVisible ได้อย่างแน่นอน โดยเฉพาะเมื่อรายการแรกปรากฏ เช่น เลย์เอาต์แบบ Lazy อาจทิ้งรายการที่เลื่อนออกจาก Viewport แล้วจึงจัดองค์ประกอบใหม่หากเลื่อนกลับมาในมุมมอง ในกรณีนี้ onFirstVisibleการเรียกกลับจะทำงานอีกครั้ง เนื่องจากเป็นรายการที่สร้างขึ้นใหม่ ลักษณะการทำงานที่คล้ายกันนี้จะเกิดขึ้นเมื่อกลับไปที่หน้าจอที่เข้าชมก่อนหน้านี้ซึ่งมี onFirstVisible ด้วยเหตุนี้ เราจึงตัดสินใจเลิกใช้งานตัวแก้ไขนี้ใน Compose รุ่นถัดไป (1.11) และขอแนะนำให้ย้ายข้อมูลไปยัง onVisibilityChanged ดูข้อมูลเพิ่มเติมในเอกสารประกอบ

การเรียกใช้โครูทีนในการทดสอบ

เราวางแผนที่จะเปลี่ยนการเรียกใช้โครูทีนในการทดสอบเพื่อปรับปรุงความไม่แน่นอนของการทดสอบและตรวจพบปัญหาต่างๆ ได้มากขึ้น ปัจจุบันการทดสอบใช้ UnconfinedTestDispatcher ซึ่งแตกต่างจากลักษณะการทำงานจริง เช่น เอฟเฟกต์อาจทำงานทันทีแทนที่จะอยู่ในคิว ในการเปิดตัวในอนาคต เรามีแผนที่จะเปิดตัว API ใหม่ที่ใช้ StandardTestDispatcher โดยค่าเริ่มต้นเพื่อให้ตรงกับลักษณะการทำงานของเวอร์ชันที่ใช้งานจริง คุณลองใช้ลักษณะการทำงานใหม่ได้ตอนนี้ในเวอร์ชัน 1.10

@get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

การใช้ StandardTestDispatcher จะจัดคิวงาน ดังนั้นคุณต้องใช้กลไกการซิงค์ เช่น composeTestRule.waitForIdle() หรือ composeTestRule.runOnIdle() หากการทดสอบใช้ runTest คุณต้องตรวจสอบว่า runTest และกฎ Compose ใช้อินสแตนซ์ StandardTestDispatcher เดียวกันเพื่อการซิงค์

// 1. Create a SINGLE dispatcher instance

val testDispatcher = StandardTestDispatcher()



// 2. Pass it to your Compose rule

@get:Rule

val composeRule = createComposeRule(effectContext = testDispatcher)



@Test

// 3. Pass the *SAME INSTANCE* to runTest

fun myTest() = runTest(testDispatcher) {

    composeRule.setContent { /* ... */ }

}

เครื่องมือ

API ที่ยอดเยี่ยมควรมีเครื่องมือที่ยอดเยี่ยม และ Android Studio ก็มีฟีเจอร์ใหม่ๆ ที่เพิ่มเข้ามาล่าสุดสำหรับนักพัฒนา Compose ดังนี้

หากต้องการดูการทำงานของเครื่องมือเหล่านี้ โปรดดูการสาธิตล่าสุดนี้

ขอให้สนุกกับการแต่งเพลง

เรายังคงลงทุนใน Jetpack Compose เพื่อมอบ API และเครื่องมือที่จำเป็นต่อการสร้าง UI ที่สวยงามและสมบูรณ์ให้แก่คุณ เราให้ความสำคัญกับความคิดเห็นของคุณ ดังนั้นโปรดแชร์ความคิดเห็นเกี่ยวกับการเปลี่ยนแปลงเหล่านี้หรือสิ่งที่คุณต้องการเห็นต่อไปในเครื่องมือติดตามปัญหา

เขียนโดย

อ่านต่อ