remember — khái niệm chính, giữ giá trị giữa các lần tái kết hợp

Tác giả: IT Sectr Đã đăng: 2026-06-28 Thời gian đọc: 8 phút

remember là một hàm trong Jetpack Compose cho phép bạn giữ lại một giá trị giữa các lần tái kết hợp, ngăn chặn việc đặt lại trạng thái mỗi khi khởi động lại hàm Composable. Nếu không có remember, tất cả các biến được khai báo bên trong hàm sẽ bị đặt lại mỗi khi UI được cập nhật, khiến trạng thái trở nên không ổn định và vô dụng. Theo Google Android Developers, 2026, việc sử dụng remember đúng cách là nền tảng của quản lý trạng thái chính xác trong UI khai báo.

Điểm Chính

  • remember giữ lại một giá trị trong slot kết hợp giữa các lần tái kết hợp của hàm
  • Khóa trong remember(key) xác định khi nào giá trị cần được tính toán lại
  • rememberSaveable giữ lại giá trị khi xoay màn hình và thu nhỏ ứng dụng
  • derivedStateOf tạo trạng thái dẫn xuất, tối ưu hóa tính toán trong quá trình tái kết hợp
  • Việc đặt lại remember chỉ xảy ra khi hàm rời khỏi kết hợp

Remember là gì trong Jetpack Compose

remember là một hàm tích hợp trong Jetpack Compose từ gói androidx.compose.runtime tạo ra một đối tượng giữ lại giá trị của nó giữa các lần gọi liên tiếp của một hàm Composable. Về mặt kỹ thuật, remember hoạt động với các slot — các ô nhớ đặc biệt được cấp phát cho mỗi vị trí gọi hàm trong cây UI. Miễn là hàm vẫn còn trong kết hợp (không bị xóa qua điều kiện if), remember sẽ trả về giá trị đã lưu ở mỗi lần tái kết hợp.

Cú pháp của remember rất đơn giản: bên trong dấu ngoặc nhọn, bạn chỉ định khối tính toán giá trị ban đầu. Khối chỉ được thực thi một lần — trong lần kết hợp đầu tiên của hàm. Tất cả các lần tái kết hợp tiếp theo trả về giá trị đã lưu mà không thực thi lại khối. Tuy nhiên, nếu một tham số khóa được chỉ định, khối sẽ được thực thi lại khi khóa thay đổi, cho phép tính toán lại giá trị dựa trên dữ liệu đầu vào.

remember không phải là phép thuật của Kotlin — nó là một hàm đơn giản với tham số khóa và lambda tính toán. Triển khai nội bộ của nó sử dụng Composer để đọc và ghi vào các slot. Trình biên dịch Kotlin, khi thấy một lệnh gọi remember, sẽ tạo ra mã truy cập vào CompositionContext hiện tại và quản lý các slot. Điều này có nghĩa là remember chỉ có thể được gọi bên trong hàm Composable hoặc một hàm khác trong ngữ cảnh kết hợp.

Các loại remember: remember, rememberSaveable, derivedStateOf

Trong Jetpack Compose, có ba biến thể chính của remember, mỗi loại có mục đích riêng. Remember cơ bản chỉ giữ lại giá trị trong bộ nhớ của tiến trình hiện tại — khi xoay màn hình (thay đổi cấu hình), Compose tạo lại Composition và tất cả các giá trị remember đều bị đặt lại. Để giữ lại dữ liệu trong quá trình thay đổi cấu hình và dừng tiến trình, người ta sử dụng rememberSaveable.

rememberSaveable tuần tự hóa giá trị vào Bundle thông qua cơ chế SavedStateHandle hoặc Parcelable. Điều này cho phép sống sót qua việc xoay màn hình, cài đặt "Không giữ hoạt động" và thậm chí cả việc thu nhỏ ứng dụng tạm thời. Tuy nhiên, rememberSaveable áp đặt các hạn chế về loại dữ liệu có thể lưu trữ: chúng phải là nguyên thủy, Parcelable, Serializable hoặc hỗ trợ bộ chuyển đổi Saver.

derivedStateOf không phải là cơ chế lưu giữ mà là một sự tối ưu hóa. Nó tạo ra một State có giá trị được tính toán từ các đối tượng State khác. derivedStateOf phản ứng với các thay đổi trong trạng thái nguồn nhưng chỉ tính toán lại giá trị khi có người đăng ký. Nếu lần tái kết hợp hiện tại không đọc derivedStateOf, việc tính toán sẽ không được thực hiện, tiết kiệm tài nguyên cho các cập nhật thường xuyên nhưng không cần thiết.

kotlin
@Composable
fun RememberVariants() {
    // 1. Remember cơ bản: tồn tại cho đến khi rời khỏi kết hợp
    val createdAt = remember { System.currentTimeMillis() }

    // 2. rememberSaveable: sống sót qua xoay màn hình
    var username by rememberSaveable { mutableStateOf("") }

    // 3. derivedStateOf: chỉ tính toán khi cần
    val isButtonVisible = remember {
        derivedStateOf { username.length() > 3 }
    }

    Text("Đã tạo: $createdAt")
    TextField(value = username, onValueChange = { username = it })

    if (isButtonVisible.value) {
        Text("Nút sẽ được hiển thị")
    }
}

remember vs rememberSaveable: khi nào dùng loại nào

Sự lựa chọn giữa remember và rememberSaveable phụ thuộc vào mức độ quan trọng của việc giữ lại dữ liệu trong quá trình thay đổi cấu hình. Đối với các trạng thái tạm thời không quan trọng nếu mất khi xoay (hoạt ảnh, vị trí cuộn hiện tại, trạng thái tiêu điểm) — remember thông thường là đủ. Đối với dữ liệu quan trọng (văn bản trong biểu mẫu, các mục đã chọn, hộp kiểm) — hãy sử dụng rememberSaveable.

Hiệu suất: rememberSaveable chậm hơn remember thông thường vì nó yêu cầu tuần tự hóa vào Bundle. Chỉ sử dụng rememberSaveable cho dữ liệu thực sự cần sống sót qua việc tạo lại Activity. Đối với mọi thứ khác — remember đơn giản. Việc sử dụng quá mức rememberSaveable dẫn đến chậm khi xoay màn hình và chuyển đổi giữa các ứng dụng.

Nếu bạn làm việc với các lớp không hỗ trợ Parcelable hoặc Serializable, hãy sử dụng Saver — một bộ chuyển đổi xác định cách lưu và khôi phục đối tượng. Saver được mô tả bằng một cặp lambda: save (chuyển đổi đối tượng thành loại có thể lưu trữ) và restore (khôi phục đối tượng từ dữ liệu đã lưu). Một Saver tiêu chuẩn đã được triển khai cho mutableStateListOf và mutableStateMapOf.

Đặc điểmrememberrememberSaveable
Giữ lại trong quá trình tái kết hợp
Giữ lại khi xoayKhông
Giữ lại khi dừng tiến trìnhKhông
Yêu cầu về loạiBất kỳParcelable, Serializable, Saver
Hiệu suấtCaoTrung bình

Ví dụ sử dụng remember trong dự án thực tế

Hãy xem xét một kịch bản điển hình — màn hình chỉnh sửa hồ sơ nơi remember được sử dụng cho nhiều mục đích: lưu trữ trạng thái của các trường biểu mẫu, tính toán các giá trị dẫn xuất và lưu vào bộ nhớ đệm các thao tác tốn kém về mặt tính toán.

kotlin
data class ProfileUiState(
    val name: String = "",
    val bio: String = "",
    val isSaving: Boolean = false
)

@Composable
fun ProfileEditor() {
    var state by rememberSaveable { mutableStateOf(ProfileUiState()) }
    val isValid = remember {
        derivedStateOf { state.name.isNotBlank() && state.bio.length() <= 500 }
    }

    val bioWarning = remember(state.bio) {
        if (state.bio.length() > 400) {
            "${500 - state.bio.length} chars left"
        } else null
    }

    Column(modifier = Modifier.padding(16.dp)) {
        OutlinedTextField(
            value = state.name,
            onValueChange = { state = state.copy(name = it) },
            label = { Text("Tên") }
        )

        OutlinedTextField(
            value = state.bio,
            onValueChange = { state = state.copy(bio = it) },
            label = { Text("Giới thiệu") }
        )

        bioWarning?.let { Text(it, color = MaterialTheme.colorScheme.error) }

        Button(onClick = { /* save */ },
            enabled = isValid.value) {
            Text("Lưu")
        }
    }
}

Trong ví dụ, trạng thái được lưu qua rememberSaveable — văn bản sẽ không bị mất khi xoay màn hình. isValid được tính toán qua derivedStateOf, ngăn chặn các tính toán không cần thiết trong quá trình tái kết hợp. bioWarning sử dụng remember với khóa bio — đây là một tính toán tốn kém (tùy chọn, để minh họa) chỉ được tính toán lại khi bio thay đổi, không phải mỗi lần tái kết hợp.

Trạng thái dẫn xuất và remember với khóa

Trạng thái dẫn xuất là các giá trị được tính toán từ các đối tượng State khác. Thay vì tính toán chúng ở mỗi lần tái kết hợp và lãng phí CPU cho các kết quả giống hệt nhau, remember với derivedStateOf chỉ tính toán giá trị khi các nguồn thay đổi. Điều này đặc biệt hữu ích cho việc lọc, sắp xếp và tổng hợp dữ liệu.

remember với khóa (remember(key) { calculation }) là một cơ chế tối ưu hóa khác. Nếu khóa không thay đổi kể từ lần tái kết hợp trước, khối tính toán sẽ không được thực thi và giá trị được lưu trong bộ nhớ đệm sẽ được trả về. Điều này thuận tiện cho việc lưu vào bộ nhớ đệm các đối tượng có việc tạo tốn kém: định dạng ngày tháng, phân tích JSON, tạo các bộ sưu tập bất biến lớn.

kotlin
@Composable
fun SearchResults(allItems: List<Item>, query: String) {
    // derivedStateOf: bộ lọc chỉ tính toán lại khi đầu vào thay đổi
    val filtered = remember {
        derivedStateOf {
            allItems.filter { it.title.contains(query, true) }
        }
    }

    // remember với khóa: thống kê được định dạng chỉ tính toán lại khi truy vấn thay đổi
    val statsText = remember(query) {
        "Results for query \"$query\": ${filtered.value.size}"
    }

    Text(statsText)
    LazyColumn {
        items(filtered.value, key = { it.id }) { item ->
            Text(item.title)
        }
    }
}

filtered là một derivedStateOf tự động tính toán lại khi allItems hoặc query thay đổi. statsText sử dụng remember(query) — việc định dạng chuỗi tốn kém chỉ được thực hiện khi truy vấn tìm kiếm thay đổi. Sự kết hợp giữa derivedStateOf và remember với khóa mang lại hiệu suất tối đa: trạng thái dẫn xuất chỉ được tính toán khi cần thiết và các đối tượng phức tạp được lưu vào bộ nhớ đệm cho đến khi khóa thay đổi.

Câu Hỏi Thường Gặp

Có thể sử dụng remember bên ngoài hàm Composable không?

Không, remember là một hàm từ gói compose.runtime yêu cầu CompositionContext. Nó chỉ có thể được gọi bên trong hàm @Composable hoặc bên trong một hàm khác được gọi từ Composable. Để lưu trữ dữ liệu bên ngoài kết hợp, hãy sử dụng ViewModel.

Điều gì xảy ra nếu không chỉ định khóa trong remember?

Không có khóa, remember thực thi khối tính toán chỉ một lần — trong lần kết hợp đầu tiên. Tất cả các lần tái kết hợp tiếp theo trả về giá trị đã lưu. Nếu bạn cần tính toán lại giá trị khi dữ liệu thay đổi, hãy đảm bảo chỉ định chúng làm khóa: remember(data) { compute(data) }.

Làm thế nào để buộc đặt lại remember?

Không có cách trực tiếp để đặt lại remember. Cách duy nhất là loại bỏ hàm khỏi kết hợp (ví dụ: ẩn nó bằng điều kiện if) và sau đó hiển thị lại. Khi vào lại, khối remember sẽ thực thi lại, tạo ra một giá trị ban đầu mới.

Remember khác ViewModel như thế nào?

remember lưu trữ trạng thái trong một slot của hàm Composable và tồn tại miễn là hàm còn trong kết hợp. ViewModel tồn tại miễn là vòng đời của màn hình còn. ViewModel được giữ lại khi xoay và được sử dụng cho logic nghiệp vụ. remember dành cho trạng thái UI cục bộ không cần thiết bên ngoài một hàm duy nhất.

Remember có hoạt động trong các thành phần Preview không?

Có, remember hoạt động chính xác trong các hàm @Preview Composable vì Preview tạo ra một CompositionContext đầy đủ. Tuy nhiên, rememberSaveable có thể không hoạt động chính xác trong Preview vì SavedStateHandle có thể không có trong môi trường xem trước.

Tổng Kết

  • remember giữ lại một giá trị trong slot kết hợp và sống sót qua các lần tái kết hợp của hàm
  • rememberSaveable bổ sung giữ lại giá trị khi xoay màn hình và dừng tiến trình
  • derivedStateOf tạo trạng thái dẫn xuất với tính toán lười biếng
  • Khóa trong remember(key) kiểm soát việc tính toán lại giá trị đã lưu trong bộ nhớ đệm
  • Việc đặt lại remember chỉ xảy ra khi hàm bị loại khỏi kết hợp
  • Hiệu suất: derivedStateOf và khóa ngăn chặn các tính toán không cần thiết trong quá trình tái kết hợp
  • Khuyến nghị: sử dụng rememberSaveable cho các trường nhập liệu và remember + derivedStateOf cho các giá trị được tính toán

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm