Một số cấu hình thiết bị có thể thay đổi khi ứng dụng đang chạy. Những cấu hình này bao gồm nhưng không giới hạn ở:
- Kích thước trên màn hình của ứng dụng
- Hướng màn hình
- Cỡ chữ và độ đậm
- Ngôn ngữ
- Chế độ tối so với chế độ sáng
- Khả năng sử dụng bàn phím
Hầu hết các thay đổi về cấu hình này xảy ra do một số tương tác của người dùng. Ví dụ: việc xoay hoặc gập thiết bị sẽ thay đổi không gian màn hình hiện có cho ứng dụng. Tương tự, việc thay đổi các chế độ cài đặt của thiết bị như cỡ chữ, ngôn ngữ hoặc giao diện ưu tiên sẽ thay đổi các giá trị tương ứng trong đối tượng Configuration.
Những tham số này thường yêu cầu các thay đổi đủ lớn đối với giao diện người dùng của ứng dụng để nền tảng Android có cơ chế riêng khi những tham số này thay đổi.
Cơ chế này là tạo lại Activity.
Tạo lại hoạt động
Hệ thống sẽ tạo lại một Activity khi cấu hình thay đổi. Để thực hiện việc này, hệ thống sẽ gọi onDestroy và huỷ bỏ thực thể Activity hiện có. Sau đó, hệ thống sẽ tạo một thực thể mới bằng cách sử dụng onCreate và thực thể mới của Activity này sẽ được khởi động bằng cấu hình mới, cập nhật. Việc này cũng có nghĩa là hệ thống cũng tạo lại giao diện người dùng bằng cấu hình mới.
Thông thường, Activity đóng vai trò là một thành phần lưu trữ cho các thành phần kết hợp. Khi Activity được tạo lại, Compose cũng tạo lại giao diện người dùng bằng các giá trị cấu hình mới.
Hành vi tạo lại giúp ứng dụng của bạn thích ứng với các cấu hình mới bằng cách tự động tải lại ứng dụng có những tài nguyên thay thế khớp với cấu hình thiết bị mới.
Ví dụ về việc tạo lại
Hãy cân nhắc một thành phần kết hợp hiển thị tiêu đề tĩnh bằng cách sử dụng tài nguyên chuỗi:
// In the res/values/strings.xml file // <string name="compose">Jetpack Compose</string> // In your Compose code Text( text = stringResource(R.string.compose) )
Khi Activity được tạo, thành phần kết hợp Text sẽ đọc cấu hình hiện tại (chẳng hạn như ngôn ngữ) và phân giải tài nguyên chuỗi thích hợp.
Nếu ngôn ngữ thay đổi, hệ thống sẽ tạo lại hoạt động. Khi điều này xảy ra, Compose sẽ tạo lại giao diện người dùng. Vì stringResource đọc từ cấu hình hiện tại, nên tiêu đề sẽ tự động cập nhật thành giá trị đã bản địa hoá chính xác.
Việc tạo lại cũng sẽ xoá mọi trạng thái được giữ lại ở dạng trường trong Activity.
Để duy trì trạng thái giao diện người dùng khi cấu hình thay đổi, hãy sử dụng các mẫu quản lý trạng thái được đề xuất. Sử dụng ViewModel cho dữ liệu và logic nghiệp vụ, đồng thời sử dụng rememberSaveable cho trạng thái ở cấp giao diện người dùng. Với những cơ chế này, trạng thái của bạn vẫn tồn tại sau khi Activity được tạo lại trong khi giao diện người dùng cập nhật để phản ánh cấu hình mới.
Để biết thêm thông tin về cách lưu trạng thái trong Compose, hãy xem bài viết Lưu trạng thái giao diện người dùng trong Compose.
Kỳ vọng của người dùng
Người dùng ứng dụng mong muốn trạng thái được giữ nguyên. Nếu người dùng đang điền vào biểu mẫu và mở một ứng dụng khác ở chế độ nhiều cửa sổ để tham chiếu thông tin, thì họ sẽ gặp trải nghiệm người dùng không tốt nếu quay lại một biểu mẫu bị xoá hoặc chuyển đến nơi hoàn toàn khác trong ứng dụng. Là nhà phát triển, bạn phải mang đến trải nghiệm nhất quán cho người dùng khi thay đổi cấu hình và tạo lại hoạt động.
Để xác minh xem trạng thái có được giữ nguyên trong ứng dụng hay không, bạn có thể thực hiện các thao tác khiến cấu hình thay đổi cả khi ứng dụng đang chạy ở nền trước lẫn khi chạy trong nền. Các thao tác này bao gồm:
- Xoay thiết bị
- Chuyển sang chế độ nhiều cửa sổ
- Đổi kích thước của ứng dụng khi ở chế độ nhiều cửa sổ hoặc cửa sổ tuỳ ý
- Gập thiết bị có thể gập lại với nhiều màn hình
- Thay đổi giao diện của hệ thống, chẳng hạn như chế độ tối so với chế độ sáng
- Thay đổi cỡ chữ
- Thay đổi ngôn ngữ hệ thống hoặc ngôn ngữ ứng dụng
- Kết nối hoặc ngắt kết nối bàn phím phần cứng
- Kết nối hoặc ngắt kết nối đế sạc
Có một số cách tiếp cận mà bạn có thể thực hiện để duy trì trạng thái liên quan khi tạo lại Activity. Việc sử dụng cách tiếp cận nào tuỳ thuộc vào loại trạng thái mà bạn muốn duy trì:
- Cố định cục bộ để xử lý trường hợp bị buộc tắt đối với dữ liệu lớn hoặc phức tạp.
Bộ nhớ cục bộ ổn định bao gồm cơ sở dữ liệu hoặc
DataStore. - Các đối tượng được giữ lại như các thực thể
ViewModelđể xử lý trạng thái liên quan đến giao diện người dùng trong bộ nhớ khi người dùng đang dùng ứng dụng. rememberSaveableđể duy trì trạng thái giao diện người dùng tạm thời khi có các thay đổi về cấu hình và sự kiện bị buộc tắt do hệ thống gây ra. Điều này phù hợp với trạng thái phụ thuộc vào hoạt động đầu vào của người dùng, vị trí cuộn hoặc thao tác điều hướng nhưng không thuộcViewModel.
Để đọc chi tiết về các API cho từng trạng thái trong số này và thời điểm phù hợp để dùng mỗi trạng thái đó, hãy xem bài viết Lưu trạng thái giao diện người dùng.
Hạn chế việc tạo lại hoạt động
Bạn có thể ngăn việc tự động tạo lại hoạt động đối với một số thay đổi về cấu hình. Trong các ứng dụng hiện đại chỉ dùng Compose, giao diện người dùng của bạn sẽ được kết hợp lại theo cả hai cách, nhưng bạn nên xử lý trực tiếp thay đổi cấu hình.
Theo mặc định, một thay đổi về cấu hình sẽ buộc hệ thống hủy bỏ và tạo lại Hoạt động, bao gồm cả giao diện người dùng và mọi đối tượng bắt nguồn từ Hoạt động. Nếu bạn khai báo rằng Hoạt động của bạn tự xử lý thay đổi về cấu hình, hệ thống sẽ ngăn chặn điều này. Thay vào đó, chỉ đối tượng Configuration cập nhật và Compose kết hợp lại giao diện người dùng của bạn với các giá trị mới.
Việc xử lý các thay đổi về cấu hình trực tiếp trong Compose mang lại một số lợi ích:
- Cải thiện hiệu suất: Việc recomposition giao diện người dùng ít tốn kém hơn so với một chu kỳ tạo lại Hoạt động đầy đủ, đặc biệt là đối với những thay đổi nhỏ.
- Ảnh động mượt mà: Việc tránh khởi động lại Hoạt động cho phép bạn chạy ảnh động liên tục trong các thay đổi về cấu hình, chẳng hạn như các hiệu ứng chuyển đổi bố cục mượt mà trong quá trình xoay thiết bị.
- Duy trì trạng thái: Việc giữ lại thực thể Hoạt động giúp giảm nguy cơ mất trạng thái giao diện người dùng tạm thời trong một sự kiện như xoay màn hình. Xin lưu ý rằng bạn vẫn phải xử lý việc duy trì trạng thái cho sự kiện bị buộc tắt do hệ thống gây ra.
Để tắt tính năng tạo lại hoạt động cho các thay đổi cụ thể về cấu hình, hãy thêm loại cấu hình vào android:configChanges trong mục <activity> ở tệp AndroidManifest.xml của bạn. Các giá trị có thể có xuất hiện trong tài liệu về thuộc tính android:configChanges.
Mã tệp kê khai sau đây sẽ tắt tính năng tạo lại Activity cho MyActivity khi hướng màn hình và khả năng sử dụng bàn phím thay đổi:
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
Phản ứng với các thay đổi về cấu hình
Jetpack Compose giúp ứng dụng của bạn dễ dàng phản ứng với các thay đổi về cấu hình.
Tuy nhiên, nếu bạn tắt tính năng tạo lại Activity cho mọi thay đổi về cấu hình, ứng dụng của bạn vẫn phải xử lý đúng cách các thay đổi về cấu hình nếu có thể.
Đối tượng Configuration có trong hệ phân cấp giao diện người dùng Compose với thành phần kết hợp cục bộ LocalConfiguration. Bất cứ khi nào giá trị này thay đổi, các hàm có khả năng kết hợp đọc từ LocalConfiguration.current sẽ kết hợp lại. Để biết thông tin về cách hoạt động của thành phần kết hợp cục bộ, hãy xem bài viết Dữ liệu trong phạm vi cục bộ với CompositionLocal.
Ví dụ
Trong ví dụ sau, một thành phần kết hợp hiển thị một ngày có định dạng cụ thể.
Thành phần kết hợp phản ứng với các thay đổi về cấu hình ngôn ngữ hệ thống bằng cách gọi ConfigurationCompat.getLocales thông qua LocalConfiguration.current.
@Composable
fun DateText(year: Int, dayOfYear: Int) {
val dateTimeFormatter = DateTimeFormatter.ofPattern(
"MMM dd",
ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
)
Text(
dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
)
}
Để tránh việc tạo lại Activity khi ngôn ngữ thay đổi, Activity lưu trữ mã Compose cần chọn không thay đổi cấu hình ngôn ngữ. Để làm như vậy, bạn đặt android:configChanges thành locale|layoutDirection.
Các thay đổi về cấu hình: Các khái niệm chính và phương pháp hay nhất
Dưới đây là các khái niệm chính mà bạn cần biết khi xử lý các thay đổi về cấu hình:
- Cấu hình: Cấu hình thiết bị xác định cách giao diện người dùng xuất hiện với người dùng, chẳng hạn như kích thước hiển thị của ứng dụng, ngôn ngữ hoặc giao diện hệ thống. Trong Compose, bạn có thể truy cập vào các giá trị cấu hình bằng
LocalConfiguration. - Các thay đổi về cấu hình:cấu hình thay đổi khi có lượt tương tác của người dùng. Ví dụ: người dùng có thể thay đổi chế độ cài đặt của thiết bị hoặc cách họ tương tác thực tế với thiết bị. Không có cách nào để ngăn các thay đổi về cấu hình.
- Tạo lại
Activity: Theo mặc định, các thay đổi về cấu hình sẽ dẫn đến việc tạo lạiActivity. Đây là một cơ chế tích hợp sẵn để khởi động lại trạng thái ứng dụng cho cấu hình mới. - Huỷ bỏ
Activity: việc tạo lạiActivitysẽ khiến hệ thống huỷ bỏ thực thể cũ củaActivityvà tạo một thực thể mới tại vị trí đó. Thực thể cũ hiện đã lỗi thời. Tránh giữ lại các tham chiếu đến các đối tượng có phạm vi vòng đời ngoài phạm vi dự kiến của chúng. - Trạng thái: Trạng thái trong thực thể cũ của
Activitykhông có trong thực thể mới củaActivity, vì đây là 2 thực thể khác nhau của đối tượng. Thay vì liên kết trạng thái với Hoạt động, hãy sử dụng các API được đề xuất để duy trì trạng thái của ứng dụng và người dùng như mô tả trong bài viết Lưu trạng thái giao diện người dùng. - Chọn không sử dụng: Việc chọn không tạo lại hoạt động cho một loại thay đổi về cấu hình yêu cầu ứng dụng của bạn cập nhật đúng cách theo cấu hình mới. Đối với hầu hết các ứng dụng Compose, bạn không nên dùng cách này.
Để mang lại trải nghiệm tốt cho người dùng, hãy tuân thủ các phương pháp hay nhất sau:
- Phải chuẩn bị cho các thay đổi thường xuyên về cấu hình: Đừng giả định rằng các thay đổi về cấu hình là hiếm hoặc không bao giờ xảy ra, bất kể cấp độ API, hệ số hình dạng hoặc bộ công cụ giao diện người dùng. Khi người dùng khiến cấu hình thay đổi, họ mong muốn các ứng dụng cập nhật và tiếp tục hoạt động đúng cách với cấu hình mới này.
- Duy trì trạng thái: Đừng làm mất trạng thái của người dùng khi quá trình tạo lại
Activitydiễn ra. Duy trì trạng thái như mô tả trong bài viết Lưu trạng thái giao diện người dùng bằng cách sử dụng các API nhưViewModelvàrememberSaveable. - Tránh chọn không sử dụng tính năng sửa nhanh: Đừng chọn không sử dụng tính năng tạo lại
Activityở dạng lối tắt để tránh bị mất trạng thái. Việc chọn không tạo lại hoạt động sẽ yêu cầu bạn thực hiện cam kết xử lý thay đổi, và bạn vẫn có thể mất trạng thái do tạo lạiActivitytừ các thay đổi khác về cấu hình, trường hợp bị buộc tắt hoặc đóng ứng dụng. Bạn không thể tắt hoàn toàn tính năng tạo lạiActivity. Duy trì trạng thái như mô tả trong bài viết Lưu trạng thái giao diện người dùng. - Đừng tránh các thay đổi về cấu hình: Đừng đặt các quy định hạn chế về hướng, tỷ lệ khung hình hoặc khả năng đổi kích thước để tránh các thay đổi về cấu hình và tạo lại
Activity. Việc này sẽ tác động tiêu cực đến người dùng muốn sử dụng ứng dụng của bạn theo ý họ.
Xử lý các thay đổi về cấu hình dựa trên kích thước
Các thay đổi về cấu hình dựa trên kích thước có thể xảy ra bất cứ lúc nào và có nhiều khả năng là khi ứng dụng của bạn chạy trên một thiết bị màn hình lớn. Tại đây, người dùng có thể chuyển sang chế độ nhiều cửa sổ. Họ muốn ứng dụng của bạn hoạt động tốt trong môi trường đó.
Có 2 loại thay đổi chung về kích thước: đáng kể và không đáng kể. Thay đổi kích thước đáng kể là thay đổi trong đó một nhóm tài nguyên thay thế khác áp dụng cho cấu hình mới do sự khác biệt về kích thước màn hình, chẳng hạn như chiều rộng, chiều cao hoặc chiều rộng nhỏ nhất. Các tài nguyên này bao gồm những tài nguyên mà ứng dụng tự xác định và những tài nguyên từ bất kỳ thư viện nào của nó.
Hạn chế việc tạo lại hoạt động đối với các thay đổi về cấu hình dựa trên kích thước
Khi bạn tắt tính năng tạo lại Activity đối với các thay đổi về cấu hình dựa trên kích thước, hệ thống sẽ không tạo lại Activity. Thay vào đó, hệ thống sẽ nhận được một lệnh gọi đến Activity.onConfigurationChanged. Mọi thành phần kết hợp đọc LocalConfiguration.current đều tự động kết hợp lại để phản ánh kích thước mới.
Tính năng tạo lại Activity bị tắt đối với các thay đổi về cấu hình dựa trên kích thước khi bạn có android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" trong tệp kê khai.
Tài nguyên khác
Để biết thêm thông tin về cách xử lý các thay đổi về cấu hình, hãy xem các tài nguyên bổ sung sau: