Tin tức về sản phẩm

Có gì mới trong bản phát hành Jetpack Compose ngày 26 tháng 4

Đọc trong 5 phút
Meghan Mehta
Người hỗ trợ nhà phát triển, Android

Hôm nay, bản phát hành Jetpack Compose tháng 4 năm 2026 đã ổn định. Bản phát hành này chứa phiên bản 1.11 của các mô-đun Compose cốt lõi (xem ánh xạ BOM đầy đủ), các công cụ gỡ lỗi thành phần dùng chung, các sự kiện bàn di chuột và nhiều nội dung khác. Chúng tôi cũng có một số API thử nghiệm mà bạn nên dùng thử và gửi ý kiến phản hồi cho chúng tôi.

Để sử dụng bản phát hành hôm nay, hãy nâng cấp phiên bản Compose BOM lên:

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

Các thay đổi trong Compose 1.11.0

Thực thi coroutine trong các kiểm thử

Chúng tôi sắp ra mắt một bản cập nhật lớn về cách Compose xử lý thời gian kiểm thử. Sau thời gian chọn tham gia được thông báo trong Compose 1.10, các API kiểm thử phiên bản 2 hiện là mặc định và các API phiên bản 1 đã ngừng hoạt động. Thay đổi chính là sự thay đổi trong trình điều phối kiểm thử mặc định. Mặc dù các API v1 dựa vào UnconfinedTestDispatcher (thực thi coroutine ngay lập tức), nhưng các API v2 lại sử dụng StandardTestDispatcher. Điều này có nghĩa là khi một coroutine được khởi chạy trong các hoạt động kiểm thử, coroutine đó sẽ được đưa vào hàng đợi và không thực thi cho đến khi đồng hồ ảo được đẩy nhanh.

Điều này mô phỏng tốt hơn các điều kiện sản xuất, loại bỏ hiệu quả các tình huống tương tranh và giúp bộ kiểm thử của bạn mạnh mẽ hơn đáng kể và ít bị lỗi hơn.

Để đảm bảo các kiểm thử của bạn phù hợp với hành vi chuẩn của coroutine và tránh các vấn đề về khả năng tương thích trong tương lai, bạn nên di chuyển bộ kiểm thử. Hãy tham khảo hướng dẫn di chuyển toàn diện của chúng tôi để biết thông tin về mối liên kết giữa các API và các bản sửa lỗi thường gặp.

Cải thiện thành phần dùng chung và công cụ tạo ảnh động

Chúng tôi cũng đã thêm một số công cụ gỡ lỗi trực quan hữu ích cho các phần tử dùng chung và Modifier.animatedBounds. Giờ đây, bạn có thể thấy chính xác những gì đang diễn ra bên dưới (chẳng hạn như ranh giới mục tiêu, quỹ đạo của ảnh động và số lượng kết quả trùng khớp được tìm thấy), giúp bạn dễ dàng phát hiện lý do khiến một hiệu ứng chuyển đổi có thể không hoạt động như mong đợi. Để sử dụng công cụ mới này, bạn chỉ cần đặt SharedTransitionLayout trong thành phần kết hợp LookaheadAnimationVisualDebugging

LookaheadAnimationVisualDebugging(
    overlayColor = Color(0x4AE91E63),
    isEnabled = true,
    multipleMatchesColor = Color.Green,
    isShowKeylabelEnabled = false,
    unmatchedElementColor = Color.Red,
) {
    SharedTransitionLayout {
        CompositionLocalProvider(
            LocalSharedTransitionScope provides this,
        ) {
            // your content
        }
    }
}

Sự kiện trên bàn di chuột

Chúng tôi đã cải tiến khả năng hỗ trợ Compose cho bàn di chuột, chẳng hạn như bàn di chuột tích hợp trên máy tính xách tay, bàn di chuột có thể gắn vào máy tính bảng hoặc bàn di chuột bên ngoài/ảo. Giờ đây, các sự kiện cơ bản của bàn di chuột thường sẽ được coi là các sự kiện PointerType.Mouse, điều chỉnh hành vi của chuột và bàn di chuột để phù hợp hơn với mong đợi của người dùng. Trước đây, những sự kiện bàn di chuột này được diễn giải là ngón tay giả trên màn hình cảm ứng của PointerType.Touch, dẫn đến trải nghiệm người dùng gây nhầm lẫn. Ví dụ: khi bạn nhấp và kéo bằng bàn di chuột, thao tác này sẽ cuộn thay vì chọn. Bằng cách thay đổi loại con trỏ mà các sự kiện này có trong bản phát hành mới nhất của Compose, thao tác nhấp và kéo bằng bàn di chuột sẽ không còn cuộn nữa.

Chúng tôi cũng đã thêm tính năng hỗ trợ cho các cử chỉ phức tạp hơn trên bàn di chuột mà nền tảng nhận dạng được kể từ API 34, bao gồm cả thao tác vuốt bằng hai ngón tay và thao tác chụm. Những cử chỉ này sẽ được các thành phần như Modifier.scrollableModifier.transformable tự động nhận dạng để có hành vi phù hợp hơn với bàn di chuột.

Những thay đổi này cải thiện hành vi của bàn di chuột trên các thành phần tích hợp, loại bỏ độ trễ khi chạm thừa, cử chỉ bắt đầu kéo và thả trực quan hơn, lựa chọn nhấn đúp và nhấn ba lần trong các trường văn bản, cũng như trình đơn theo bối cảnh theo kiểu máy tính trong các trường văn bản.

Để kiểm thử hành vi của bàn di chuột, có các API kiểm thử mới với performTrackpadInput, cho phép xác thực hành vi của ứng dụng khi được dùng với bàn di chuột. Nếu bạn có trình phát hiện cử chỉ tuỳ chỉnh, hãy xác thực hành vi trên các loại thiết bị đầu vào, bao gồm cả màn hình cảm ứng, chuột, bàn di chuột và bút cảm ứng, đồng thời đảm bảo hỗ trợ con lăn chuột và cử chỉ trên bàn di chuột.

beforeAndAfter.webp

Giá trị mặc định của thành phần lưu trữ (thời gian chạy Compose)

Chúng tôi đã giới thiệu HostDefaultProvider, LocalHostDefaultProvider, HostDefaultKeyViewTreeHostDefaultKey để cung cấp các dịch vụ cấp máy chủ lưu trữ trực tiếp thông qua compose-runtime. Điều này giúp các thư viện không cần phải phụ thuộc vào compose-ui để tra cứu, hỗ trợ tốt hơn cho Kotlin Multiplatform. Để liên kết các giá trị này với cây thành phần, tác giả thư viện có thể sử dụng compositionLocalWithHostDefaultOf để tạo CompositionLocal phân giải các giá trị mặc định từ máy chủ lưu trữ.

Xem trước vùng bao bọc

Bản xem trước tuỳ chỉnh của Android Studio là một tính năng mới cho phép bạn xác định chính xác cách nội dung của bản xem trước Compose được hiển thị.

Bằng cách triển khai giao diện PreviewWrapperProvider và áp dụng chú thích @PreviewWrapper mới, bạn có thể dễ dàng chèn logic tuỳ chỉnh, chẳng hạn như áp dụng một Theme cụ thể. Bạn có thể áp dụng chú giải này cho một hàm được chú thích bằng @Composable@Preview hoặc @MultiPreview, cung cấp một giải pháp chung, dễ sử dụng, hoạt động trên các tính năng xem trước và giảm đáng kể mã lặp lại.

class ThemeWrapper: PreviewWrapper {
    @Composable
    override fun Wrap(content: @Composable (() -> Unit)) {
        JetsnackTheme {
            content()
        }
    }
}

@PreviewWrapperProvider(ThemeWrapper::class)
@Preview
@Composable
private fun ButtonPreview() {
    // JetsnackTheme in effect
    Button(onClick = {}) {
        Text(text = "Demo")
    }
}

Ngừng sử dụng và xoá

  • Như đã thông báo trong bài đăng trên blog về Compose 1.10, chúng tôi sẽ ngừng sử dụng Modifier.onFirstVisible(). Tên của thành phần này thường gây ra những hiểu lầm, đặc biệt là trong bố cục lười biếng, nơi thành phần này sẽ kích hoạt nhiều lần trong quá trình cuộn. Bạn nên di chuyển sang Modifier.onVisibilityChanged(). Thư viện này cho phép theo dõi thủ công chính xác hơn các trạng thái hiển thị phù hợp với các yêu cầu cụ thể về trường hợp sử dụng của bạn.
  • Cờ ComposeFoundationFlags.isTextFieldDpadNavigationEnabled đã bị xoá vì chế độ điều hướng bằng d-pad cho TextFields hiện luôn được bật theo mặc định. Hành vi mới này đảm bảo rằng các sự kiện trên D-pad của tay cầm chơi game hoặc điều khiển từ xa của TV sẽ di chuyển con trỏ theo hướng đã cho trước. Tiêu điểm chỉ có thể di chuyển đến một phần tử khác khi con trỏ chạm đến cuối văn bản.

Các API sắp ra mắt

Trong bản phát hành Compose 1.12.0 sắp tới, compileSdk sẽ được nâng cấp lên compileSdk 37, với AGP 9 và tất cả các ứng dụng cũng như thư viện phụ thuộc vào Compose đều phải đáp ứng yêu cầu này. Bạn nên cập nhật các phiên bản mới nhất đã phát hành, vì Compose hướng đến việc nhanh chóng áp dụng compileSdks mới để cung cấp quyền truy cập vào các tính năng mới nhất của Android. Hãy nhớ xem tài liệu tại đây để biết thêm thông tin về phiên bản AGP được hỗ trợ cho các cấp độ API khác nhau. 

Trong Compose 1.11.0, các API sau đây được giới thiệu dưới dạng @Experimental và chúng tôi rất mong nhận được ý kiến phản hồi của bạn khi bạn khám phá các API này trong ứng dụng của mình. Xin lưu ý rằng @Experimental APIs được cung cấp để đánh giá và nhận phản hồi sớm, đồng thời có thể trải qua những thay đổi đáng kể hoặc bị xóa trong các bản phát hành sau này.

Kiểu (Thử nghiệm)

Chúng tôi sẽ ra mắt một API nền tảng thử nghiệm mới để tạo kiểu. Style API là một mô hình mới để tuỳ chỉnh các phần tử trực quan của thành phần. Trước đây, việc này thường được thực hiện bằng các đối tượng sửa đổi. Thành phần này được thiết kế để giúp bạn tuỳ chỉnh sâu hơn và dễ dàng hơn bằng cách hiển thị một bộ thuộc tính có thể tạo kiểu tiêu chuẩn với kiểu dáng dựa trên trạng thái đơn giản và các hiệu ứng chuyển động. Với API mới này, chúng tôi đã nhận thấy những lợi ích hứa hẹn về hiệu suất. Chúng tôi dự định áp dụng Kiểu trong các thành phần Material sau khi Style API ổn định.

Ví dụ cơ bản về việc ghi đè nền kiểu trạng thái đã nhấn:

@Composable
fun LoginButton(modifier: Modifier = Modifier) {
    Button(
        onClick = {
            // Login logic
        },
        modifier = modifier,
        style = {
            background(
                Brush.linearGradient(
                    listOf(lightPurple, lightBlue)
                )
            )
            width(75.dp)
            height(50.dp)
            textAlign(TextAlign.Center)
            externalPadding(16.dp)

            pressed {
                background(
                    Brush.linearGradient(
                        listOf(Color.Magenta, Color.Red)
                    )
                )
            }
        }
    ){
        Text(
            text = "Login",
        )
    }
}
styles.webp

Hãy xem tài liệu và báo cáo mọi lỗi tại đây.

MediaQuery (Thử nghiệm)

API mediaQuery mới cung cấp một cách khai báo và hiệu quả để điều chỉnh giao diện người dùng cho phù hợp với môi trường. Thao tác này trừu tượng hoá quá trình truy xuất thông tin phức tạp thành các điều kiện đơn giản trong UiMediaScope, đảm bảo quá trình kết hợp lại chỉ diễn ra khi cần.

Với khả năng hỗ trợ nhiều tín hiệu môi trường (từ các khả năng của thiết bị như loại bàn phím và độ chính xác của con trỏ, đến các trạng thái theo bối cảnh như kích thước và tư thế của cửa sổ), bạn có thể tạo ra những trải nghiệm có khả năng thích ứng sâu sắc. Hiệu suất được tích hợp sẵn với derivedMediaQuery để xử lý các bản cập nhật tần suất cao, trong khi khả năng ghi đè các phạm vi giúp việc kiểm thử và xem trước diễn ra liền mạch trên các cấu hình phần cứng. Trước đây, để truy cập vào một số thuộc tính của thiết bị (chẳng hạn như nếu thiết bị ở chế độ trên bàn), bạn cần viết nhiều mã lặp lại để làm như vậy: 

@Composable
fun isTabletopPosture(
    context: Context = LocalContext.current
): Boolean {
    val windowLayoutInfo by
        WindowInfoTracker
            .getOrCreate(context)
            .windowLayoutInfo(context)
            .collectAsStateWithLifecycle(null)

    return windowLayoutInfo.displayFeatures.any { displayFeature ->
        displayFeature is FoldingFeature &&
            displayFeature.state == FoldingFeature.State.HALF_OPENED &&
            displayFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
    }
}

@Composable
fun VideoPlayer() {
    if(isTabletopPosture()) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Giờ đây, với UIMediaQuery, bạn có thể thêm cú pháp mediaQuery để truy vấn các thuộc tính của thiết bị, chẳng hạn như liệu thiết bị có đang ở chế độ mặt bàn hay không:

@OptIn(ExperimentalMediaQueryApi::class)
@Composable
fun VideoPlayer() {
    if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Hãy xem tài liệu và báo cáo mọi lỗi tại đây.

Lưới (Thử nghiệm)

Grid là một API mới mạnh mẽ để xây dựng các bố cục phức tạp, hai chiều trong Jetpack Compose. Mặc dù Row và Column rất phù hợp với các thiết kế tuyến tính, Grid mang đến cho bạn quyền kiểm soát cấu trúc cần thiết cho kiến trúc cấp màn hình và các thành phần phức tạp mà không cần đến danh sách có thể cuộn. Grid cho phép bạn xác định bố cục bằng cách sử dụng các đường kẻ, khoảng trống và ô, cung cấp các lựa chọn kích thước quen thuộc như Dp, tỷ lệ phần trăm, kích thước nội dung vốn có và các đơn vị "Fr" linh hoạt. 

@OptIn(ExperimentalGridApi::class)
@Composable
fun GridExample() {
    Grid(
        config = {
            repeat(4) { column(0.25f) }
            repeat(2) { row(0.5f) }
            gap(16.dp)
        }
    ) {
        Card1(modifier = Modifier.gridItem(rowSpan = 2)
        Card2(modifier = Modifier.gridItem(colmnSpan = 3)
        Card3(modifier = Modifier.gridItem(columnSpan = 2)
        Card4()
    }
}

Bạn có thể tự động đặt các mục hoặc đặt chúng một cách rõ ràng trên nhiều hàng và cột để có độ chính xác cao. Quan trọng nhất là bố cục này có khả năng thích ứng cao. Bạn có thể định cấu hình lại các khoảng và đường lưới một cách linh hoạt để phản hồi các trạng thái của thiết bị, chẳng hạn như chế độ trên bàn hoặc thay đổi hướng, đảm bảo giao diện người dùng của bạn trông đẹp mắt trên nhiều kiểu dáng.

Grid.gif

Hãy xem tài liệu và báo cáo mọi lỗi tại đây

FlexBox (Thử nghiệm)

FlexBox là một vùng chứa bố cục được thiết kế cho giao diện người dùng thích ứng có hiệu suất cao. Lớp này quản lý việc định cỡ mục và phân phối không gian dựa trên kích thước vùng chứa có sẵn.  Nó xử lý các tác vụ phức tạp như bao bọc (wrap) và căn chỉnh nhiều trục của các mục (justifyContent, alignItems, alignContent). Nó cho phép các mục tăng (grow) hoặc giảm (shrink) để lấp đầy vùng chứa. 

@OptIn(ExperimentalFlexBoxApi::class)
fun FlexBoxWrapping(){
    FlexBox(
        config = {
            wrap(FlexWrap.Wrap)
            gap(8.dp)
        }
    ) {
        RedRoundedBox()
        BlueRoundedBox()
        GreenRoundedBox(modifier = Modifier.width(350.dp).flex { grow(1.0f) })
        OrangeRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.7f) })
        PinkRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.3f) })
    }
}
AnimationGif.gif

Hãy xem tài liệu và báo cáo mọi lỗi tại đây.

Triển khai SlotTable mới (Thử nghiệm)

Chúng tôi đã triển khai một phiên bản mới của SlotTable. Phiên bản này sẽ bị tắt theo mặc định trong bản phát hành này. SlotTable là cấu trúc dữ liệu nội bộ mà thời gian chạy Compose dùng để theo dõi trạng thái của hệ phân cấp thành phần, theo dõi các lượt vô hiệu hoá/tái tạo giao diện, lưu trữ các giá trị đã ghi nhớ và theo dõi tất cả siêu dữ liệu của thành phần trong thời gian chạy. Cách triển khai mới này được thiết kế để cải thiện hiệu suất, chủ yếu là đối với các nội dung chỉnh sửa ngẫu nhiên.

Để dùng thử SlotTable mới, hãy bật ComposeRuntimeFlags.isLinkBufferComposerEnabled

Bắt đầu lập trình ngay hôm nay!

Với rất nhiều API mới thú vị trong Jetpack Compose và nhiều API khác sắp ra mắt, đây là thời điểm thích hợp nhất để di chuyển sang Jetpack Compose.  Như thường lệ, chúng tôi rất coi trọng ý kiến phản hồi và yêu cầu về tính năng của bạn (đặc biệt là về các tính năng @Experimental vẫn đang trong quá trình phát triển). Vui lòng gửi ý kiến phản hồi và yêu cầu tại đây. Chúc bạn sáng tác vui vẻ!

Tác giả:

Tiếp tục đọc