Tiện ích ứng dụng là các khung hiển thị thu nhỏ của ứng dụng mà bạn có thể nhúng vào các ứng dụng khác (chẳng hạn như màn hình chính) và nhận được các bản cập nhật định kỳ. Những khung hiển thị này được gọi là tiện ích trong giao diện người dùng và bạn có thể xuất bản một tiện ích bằng trình cung cấp tiện ích ứng dụng (hoặc trình cung cấp tiện ích). Một thành phần ứng dụng chứa các tiện ích khác được gọi là máy chủ tiện ích ứng dụng (hoặc máy chủ tiện ích). Hình 1 minh hoạ một tiện ích âm nhạc mẫu:
 
  Tài liệu này mô tả cách xuất bản một tiện ích bằng cách sử dụng trình cung cấp tiện ích. Để biết thông tin chi tiết về cách tạo AppWidgetHost của riêng bạn để lưu trữ các tiện ích ứng dụng, hãy xem phần Xây dựng một máy chủ tiện ích.
Để biết thông tin về cách thiết kế tiện ích, hãy xem bài viết Tổng quan về tiện ích ứng dụng.
Thành phần tiện ích
Để tạo một tiện ích, bạn cần có các thành phần cơ bản sau:
- Đối tượng AppWidgetProviderInfo
- Mô tả siêu dữ liệu cho một tiện ích, chẳng hạn như bố cục, tần suất cập nhật và lớp AppWidgetProvidercủa tiện ích.AppWidgetProviderInfođược xác định trong XML, như mô tả trong tài liệu này.
- Lớp AppWidgetProvider
- Xác định các phương thức cơ bản cho phép bạn tương tác với tiện ích theo cách lập trình. Thông qua đó, bạn sẽ nhận được thông báo khi tiện ích được cập nhật, bật, tắt hoặc xoá. Bạn khai báo AppWidgetProvidertrong tệp kê khai rồi triển khai nó, như mô tả trong tài liệu này.
- Bố cục chế độ xem
- Xác định bố cục ban đầu cho tiện ích. Bố cục được xác định trong XML, như mô tả trong tài liệu này.
Hình 2 cho thấy cách các thành phần này phù hợp với quy trình xử lý tiện ích ứng dụng tổng thể.
 
  Nếu tiện ích của bạn cần người dùng định cấu hình, hãy triển khai hoạt động định cấu hình tiện ích ứng dụng. Hoạt động này cho phép người dùng sửa đổi chế độ cài đặt tiện ích, chẳng hạn như múi giờ cho tiện ích đồng hồ.
- Kể từ Android 12 (API cấp 31), bạn có thể cung cấp cấu hình mặc định và cho phép người dùng định cấu hình lại tiện ích sau này. Hãy xem phần Sử dụng cấu hình mặc định của tiện ích và Cho phép người dùng định cấu hình lại các tiện ích đã đặt để biết thêm thông tin chi tiết.
- Trong Android 11 (API cấp 30) trở xuống, hoạt động này sẽ được khởi chạy mỗi khi người dùng thêm tiện ích vào màn hình chính.
Chúng tôi cũng đề xuất những điểm cải tiến sau: bố cục tiện ích linh hoạt, các điểm cải tiến khác, tiện ích nâng cao, tiện ích tập hợp và tạo một máy chủ lưu trữ tiện ích.
Khai báo XML AppWidgetProviderInfo
Đối tượng AppWidgetProviderInfo xác định những đặc điểm thiết yếu của một tiện ích.
Xác định đối tượng AppWidgetProviderInfo trong một tệp tài nguyên XML bằng cách sử dụng một phần tử <appwidget-provider> duy nhất và lưu đối tượng đó vào thư mục res/xml/ của dự án.
Lệnh này được minh hoạ trong ví dụ sau:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:targetCellWidth="1"
    android:targetCellHeight="1"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="120dp"
    android:updatePeriodMillis="86400000"
    android:description="@string/example_appwidget_description"
    android:previewLayout="@layout/example_appwidget_preview"
    android:initialLayout="@layout/example_loading_appwidget"
    android:configure="com.example.android.ExampleAppWidgetConfigurationActivity"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:widgetFeatures="reconfigurable|configuration_optional">
</appwidget-provider>
Thuộc tính định cỡ tiện ích
Màn hình chính mặc định sẽ đặt các tiện ích vào cửa sổ dựa trên một lưới ô có chiều cao và chiều rộng xác định. Hầu hết màn hình chính chỉ cho phép các tiện ích có kích thước là bội số nguyên của các ô lưới – ví dụ: 2 ô theo chiều ngang và 3 ô theo chiều dọc.
Các thuộc tính định cỡ tiện ích cho phép bạn chỉ định kích thước mặc định cho tiện ích và cung cấp giới hạn dưới và trên về kích thước của tiện ích. Trong ngữ cảnh này, kích thước mặc định của tiện ích là kích thước mà tiện ích sẽ có khi được thêm vào màn hình chính lần đầu tiên.
Bảng sau đây mô tả các thuộc tính <appwidget-provider> liên quan đến việc định cỡ tiện ích:
| Thuộc tính và nội dung mô tả | |
|---|---|
| targetCellWidthvàtargetCellHeight(Android 12),minWidthvàminHeight | 
 targetCellWidthvàtargetCellHeight, cũng nhưminWidthvàminHeight– để ứng dụng của bạn có thể quay lại sử dụngminWidthvàminHeightnếu thiết bị của người dùng không hỗ trợtargetCellWidthvàtargetCellHeight. Nếu được hỗ trợ, các thuộc tínhtargetCellWidthvàtargetCellHeightsẽ được ưu tiên hơn các thuộc tínhminWidthvàminHeight. | 
| minResizeWidthvàminResizeHeight | Chỉ định kích thước tối thiểu tuyệt đối của tiện ích. Các giá trị này chỉ định kích thước mà theo đó tiện ích không đọc được hoặc không sử dụng được. Khi sử dụng các thuộc tính này, người dùng có thể đổi kích thước tiện ích thành kích thước nhỏ hơn kích thước mặc định của tiện ích. Thuộc tính minResizeWidthsẽ bị bỏ qua nếu lớn hơnminWidthhoặc nếu bạn không bật tính năng đổi kích thước theo chiều ngang. Xem phầnresizeMode. Tương tự, thuộc tínhminResizeHeightsẽ bị bỏ qua nếu lớn hơnminHeighthoặc nếu bạn không bật tính năng đổi kích thước theo chiều dọc. | 
| maxResizeWidthvàmaxResizeHeight | Chỉ định kích thước tối đa được đề xuất của tiện ích. Nếu các giá trị không phải là bội số của kích thước ô lưới, thì các giá trị đó sẽ được làm tròn lên kích thước ô gần nhất. Thuộc tính maxResizeWidthsẽ bị bỏ qua nếu nhỏ hơnminWidthhoặc nếu bạn không bật tính năng đổi kích thước theo chiều ngang. Hãy xemresizeMode. Tương tự, thuộc tínhmaxResizeHeightsẽ bị bỏ qua nếu lớn hơnminHeighthoặc nếu bạn không bật tính năng đổi kích thước theo chiều dọc.
      Ra mắt trong Android 12. | 
| resizeMode | Chỉ định các quy tắc mà theo đó, bạn có thể đổi kích thước một tiện ích. Bạn có thể dùng thuộc tính này để thay đổi kích thước tiện ích trên màn hình chính theo chiều ngang, chiều dọc hoặc cả hai trục. Người dùng nhấn và giữ một tiện ích để hiện các ô điều khiển đổi kích thước, sau đó kéo các ô điều khiển ngang hoặc dọc để thay đổi kích thước của tiện ích trên lưới bố cục. Các giá trị cho thuộc tính resizeModebao gồmhorizontal,verticalvànone. Để khai báo một tiện ích có thể đổi kích thước theo chiều ngang và chiều dọc, hãy sử dụnghorizontal|vertical. | 
Ví dụ
Để minh hoạ cách các thuộc tính trong bảng trước ảnh hưởng đến việc định cỡ tiện ích, hãy giả định các thông số kỹ thuật sau:
- Một ô lưới có chiều rộng 30 dp và chiều cao 50 dp.
- Sau đây là quy cách thuộc tính được cung cấp:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="80dp"
    android:minHeight="80dp"
    android:targetCellWidth="2"
    android:targetCellHeight="2"
    android:minResizeWidth="40dp"
    android:minResizeHeight="40dp"
    android:maxResizeWidth="120dp"
    android:maxResizeHeight="120dp"
    android:resizeMode="horizontal|vertical" />
Bắt đầu từ Android 12:
Sử dụng các thuộc tính targetCellWidth và targetCellHeight làm kích thước mặc định của tiện ích.
Theo mặc định, kích thước của tiện ích là 2x2. Bạn có thể giảm kích thước tiện ích xuống 2x1 hoặc tăng lên 4x3.
Android 11 trở xuống:
Sử dụng các thuộc tính minWidth và minHeight để tính toán kích thước mặc định của tiện ích.
Độ rộng mặc định = Math.ceil(80 / 30) = 3
Chiều cao mặc định = Math.ceil(80 / 50) = 2
Theo mặc định, kích thước của tiện ích là 3x2. Bạn có thể đổi kích thước của tiện ích xuống 2x1 hoặc lên đến toàn màn hình.
Các thuộc tính bổ sung của tiện ích
Bảng sau đây mô tả các thuộc tính <appwidget-provider> liên quan đến các yếu tố chất lượng khác ngoài việc định cỡ tiện ích.
| Thuộc tính và nội dung mô tả | |
|---|---|
| updatePeriodMillis | Xác định tần suất khung tiện ích yêu cầu cập nhật từ AppWidgetProviderbằng cách gọi phương thức gọi lạionUpdate(). Bản cập nhật thực tế không được đảm bảo sẽ diễn ra đúng thời gian với giá trị này và bạn nên cập nhật càng ít càng tốt (không quá một lần mỗi giờ) để tiết kiệm pin.
      Để xem danh sách đầy đủ các yếu tố cần cân nhắc khi chọn khoảng thời gian cập nhật phù hợp, hãy xem bài viết Tối ưu hoá để cập nhật nội dung của tiện ích. | 
| initialLayout | Trỏ đến tài nguyên bố cục xác định bố cục của tiện ích. | 
| configure | Xác định hoạt động sẽ chạy khi người dùng thêm tiện ích, cho phép họ định cấu hình các thuộc tính của tiện ích. Xem phần Cho phép người dùng định cấu hình tiện ích. Kể từ Android 12, ứng dụng của bạn có thể bỏ qua cấu hình ban đầu. Hãy xem phần Sử dụng cấu hình mặc định của tiện ích để biết thông tin chi tiết. | 
| description | Chỉ định nội dung mô tả cho bộ chọn tiện ích để hiển thị cho tiện ích của bạn. Ra mắt trong Android 12. | 
| previewLayout(Android 12) vàpreviewImage(Android 11 trở xuống) | 
 previewImagevàpreviewLayoutđể ứng dụng của bạn có thể quay lại sử dụngpreviewImagenếu thiết bị của người dùng không hỗ trợpreviewLayout. Để biết thêm thông tin, hãy xem bài viết Khả năng tương thích ngược với bản xem trước của tiện ích có thể mở rộng. | 
| autoAdvanceViewId | Chỉ định mã nhận dạng khung hiển thị của khung hiển thị phụ của tiện ích do máy chủ của tiện ích tự động chuyển. | 
| widgetCategory | Khai báo xem tiện ích của bạn có thể xuất hiện trên màn hình chính ( home_screen), màn hình khoá (keyguard) hay cả hai. Đối với Android 5.0 trở lên, chỉhome_screenmới hợp lệ. | 
| widgetFeatures | Khai báo các tính năng mà tiện ích hỗ trợ. Ví dụ: nếu bạn muốn tiện ích sử dụng cấu hình mặc định khi người dùng thêm tiện ích đó, hãy chỉ định cả cờ configuration_optionalvàreconfigurable. Thao tác này sẽ bỏ qua việc chạy hoạt động định cấu hình sau khi người dùng thêm tiện ích. Sau đó, người dùng vẫn có thể định cấu hình lại tiện ích. | 
Sử dụng lớp AppWidgetProvider để xử lý thông báo truyền tin của tiện ích
Lớp AppWidgetProvider xử lý các thông báo truyền tin của tiện ích và cập nhật tiện ích để phản hồi các sự kiện trong vòng đời của tiện ích. Các phần sau đây mô tả cách khai báo AppWidgetProvider trong tệp kê khai rồi triển khai tệp kê khai đó.
Khai báo một tiện ích trong tệp kê khai
Trước tiên, hãy khai báo lớp AppWidgetProvider trong tệp AndroidManifest.xml của ứng dụng, như trong ví dụ sau:
<receiver android:name="ExampleAppWidgetProvider"
                 android:exported="false">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info" />
</receiver>
Phần tử <receiver> yêu cầu thuộc tính android:name, thuộc tính này chỉ định AppWidgetProvider mà tiện ích sử dụng. Bạn không được xuất thành phần, trừ phi một quy trình riêng biệt cần truyền đến AppWidgetProvider của bạn. Thường thì không phải như vậy.
Phần tử <intent-filter> phải có một phần tử <action> có thuộc tính android:name. Thuộc tính này chỉ định rằng AppWidgetProvider chấp nhận thông báo truyền tin ACTION_APPWIDGET_UPDATE. Đây là thông báo duy nhất mà bạn phải khai báo một cách rõ ràng. AppWidgetManager tự động gửi tất cả các thông báo khác của tiện ích đến AppWidgetProvider khi cần.
Phần tử <meta-data> chỉ định tài nguyên AppWidgetProviderInfo và yêu cầu các thuộc tính sau:
- android:name: chỉ định tên siêu dữ liệu. Sử dụng- android.appwidget.providerđể xác định dữ liệu là bộ mô tả- AppWidgetProviderInfo.
- android:resource: chỉ định vị trí tài nguyên- AppWidgetProviderInfo.
Triển khai lớp AppWidgetProvider
Lớp AppWidgetProvider mở rộng BroadcastReceiver dưới dạng một lớp tiện ích để xử lý các thông báo truyền tin của tiện ích. Nó chỉ nhận các thông báo sự kiện liên quan đến tiện ích, chẳng hạn như khi tiện ích được cập nhật, xoá, bật và tắt. Khi các sự kiện truyền tin này xảy ra, các phương thức AppWidgetProvider sau đây sẽ được gọi:
- onUpdate()
- Phương thức này được gọi để cập nhật tiện ích theo các khoảng thời gian do thuộc tính updatePeriodMillisxác định trongAppWidgetProviderInfo. Hãy xem bảng mô tả các thuộc tính bổ sung của tiện ích trên trang này để biết thêm thông tin.
- Phương thức này cũng được gọi khi người dùng thêm tiện ích, vì vậy, phương thức này thực hiện quá trình thiết lập cần thiết, chẳng hạn như xác định trình xử lý sự kiện cho các đối tượng Viewhoặc bắt đầu các công việc tải dữ liệu để hiển thị trong tiện ích. Tuy nhiên, nếu bạn khai báo một hoạt động liên quan đến cấu hình mà không có cờconfiguration_optional, thì phương thức này không được gọi khi người dùng thêm tiện ích, nhưng được gọi cho các bản cập nhật tiếp theo. Hoạt động định cấu hình có trách nhiệm thực hiện bản cập nhật đầu tiên khi quá trình định cấu hình hoàn tất. Hãy xem bài viết Cho phép người dùng định cấu hình tiện ích ứng dụng để biết thêm thông tin.
- Lệnh gọi lại quan trọng nhất là onUpdate(). Hãy xem phần Xử lý các sự kiện bằng lớponUpdate()trên trang này để biết thêm thông tin.
- onAppWidgetOptionsChanged()
- Phương thức này được gọi khi tiện ích được đặt lần đầu tiên và mỗi khi tiện ích được đổi kích thước. Sử dụng lệnh gọi lại này để hiện hoặc ẩn nội dung dựa trên các dải kích thước của tiện ích. Lấy các dải kích thước (và bắt đầu từ Android 12, danh sách các kích thước có thể có của một thực thể tiện ích) bằng cách gọi - getAppWidgetOptions(). Thao tác này sẽ trả về một- Bundlebao gồm những nội dung sau:- OPTION_APPWIDGET_MIN_WIDTH: chứa giới hạn dưới về chiều rộng (tính bằng đơn vị dp) của một phiên bản tiện ích.
- OPTION_APPWIDGET_MIN_HEIGHT: chứa giới hạn dưới về chiều cao (tính bằng đơn vị dp) của một thực thể tiện ích.
- OPTION_APPWIDGET_MAX_WIDTH: chứa giới hạn trên của chiều rộng, tính bằng đơn vị dp, của một phiên bản tiện ích.
- OPTION_APPWIDGET_MAX_HEIGHT: chứa giới hạn trên của chiều cao (tính bằng đơn vị dp) của một thực thể tiện ích.
- OPTION_APPWIDGET_SIZES: chứa danh sách các kích thước có thể có (- List<SizeF>), tính bằng đơn vị dp, mà một thực thể tiện ích có thể nhận. Ra mắt trong Android 12.
 
- onDeleted(Context, int[])
- Phương thức này được gọi mỗi khi một tiện ích bị xoá khỏi máy chủ lưu trữ tiện ích. 
- onEnabled(Context)
- Phương thức này được gọi khi một thực thể của tiện ích được tạo lần đầu tiên. Ví dụ: nếu người dùng thêm 2 phiên bản của tiện ích, thì phương thức này chỉ được gọi vào lần đầu tiên. Nếu bạn cần mở một cơ sở dữ liệu mới hoặc thực hiện một chế độ thiết lập khác chỉ cần diễn ra một lần cho tất cả các phiên bản tiện ích, thì đây là nơi phù hợp để thực hiện việc đó. 
- onDisabled(Context)
- Phương thức này được gọi khi phiên bản cuối cùng của tiện ích bị xoá khỏi máy chủ lưu trữ tiện ích. Đây là nơi bạn dọn dẹp mọi công việc đã thực hiện trong - onEnabled(Context), chẳng hạn như xoá cơ sở dữ liệu tạm thời.
- onReceive(Context, Intent)
- Phương thức này được gọi cho mọi thông báo truyền tin và trước mỗi phương thức gọi lại trước đó. Thông thường, bạn không cần triển khai phương thức này, vì quá trình triển khai - AppWidgetProvidermặc định sẽ lọc tất cả các thông báo truyền tin của tiện ích và gọi các phương thức trước đó khi thích hợp.
Bạn phải khai báo quá trình triển khai lớp AppWidgetProvider dưới dạng một broadcast receiver bằng cách sử dụng phần tử <receiver> trong AndroidManifest. Hãy xem phần Khai báo một tiện ích trong tệp kê khai trên trang này để biết thêm thông tin.
Xử lý các sự kiện bằng lớp onUpdate()
Lệnh gọi lại AppWidgetProvider quan trọng nhất là onUpdate(), vì lệnh gọi lại này được gọi khi mỗi tiện ích được thêm vào một máy chủ lưu trữ, trừ phi bạn sử dụng một hoạt động định cấu hình mà không có cờ configuration_optional. Nếu tiện ích của bạn chấp nhận mọi sự kiện tương tác của người dùng, hãy đăng ký trình xử lý sự kiện trong lệnh gọi lại này. Nếu tiện ích của bạn không tạo tệp hoặc cơ sở dữ liệu tạm thời hoặc thực hiện các thao tác khác cần dọn dẹp, thì onUpdate() có thể là phương thức gọi lại duy nhất mà bạn cần xác định.
Ví dụ: nếu muốn có một tiện ích có nút khởi chạy một hoạt động khi được nhấn, bạn có thể dùng cách triển khai AppWidgetProvider sau đây:
Kotlin
class ExampleAppWidgetProvider : AppWidgetProvider() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Perform this loop procedure for each widget that belongs to this // provider. appWidgetIds.forEach { appWidgetId -> // Create an Intent to launch ExampleActivity. val pendingIntent: PendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ Intent(context, ExampleActivity::class.java), /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // Get the layout for the widget and attach an onClick listener to // the button. val views: RemoteViews = RemoteViews( context.packageName, R.layout.appwidget_provider_layout ).apply { setOnClickPendingIntent(R.id.button, pendingIntent) } // Tell the AppWidgetManager to perform an update on the current // widget. appWidgetManager.updateAppWidget(appWidgetId, views) } } }
Java
public class ExampleAppWidgetProvider extends AppWidgetProvider { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Perform this loop procedure for each widget that belongs to this // provider. for (int i=0; i < appWidgetIds.length; i++) { int appWidgetId = appWidgetIds[i]; // Create an Intent to launch ExampleActivity Intent intent = new Intent(context, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( /* context = */ context, /* requestCode = */ 0, /* intent = */ intent, /* flags = */ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); // Get the layout for the widget and attach an onClick listener to // the button. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget_layout); views.setOnClickPendingIntent(R.id.button, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app // widget. appWidgetManager.updateAppWidget(appWidgetId, views); } } }
AppWidgetProvider này chỉ xác định phương thức onUpdate(), sử dụng phương thức này để tạo PendingIntent khởi chạy Activity và đính kèm Activity đó vào nút của tiện ích bằng cách sử dụng setOnClickPendingIntent(int,
PendingIntent). Nguồn cấp dữ liệu này bao gồm một vòng lặp lặp lại từng mục trong appWidgetIds, đây là một mảng gồm các mã nhận dạng xác định từng tiện ích do nhà cung cấp này tạo. Nếu người dùng tạo nhiều phiên bản của tiện ích, thì tất cả các phiên bản đó sẽ cập nhật đồng thời. Tuy nhiên, chỉ có một lịch biểu updatePeriodMillis được quản lý cho tất cả các phiên bản của tiện ích. Ví dụ: nếu lịch cập nhật được xác định là 2 giờ một lần và một phiên bản thứ hai của tiện ích được thêm vào 1 giờ sau phiên bản đầu tiên, thì cả hai phiên bản đều được cập nhật theo khoảng thời gian do phiên bản đầu tiên xác định và khoảng thời gian cập nhật thứ hai sẽ bị bỏ qua. Cả hai đều cập nhật 2 giờ một lần, chứ không phải 1 giờ một lần.
Hãy xem lớp mẫu ExampleAppWidgetProvider.java để biết thêm thông tin chi tiết.
Nhận ý định truyền tin của tiện ích
AppWidgetProvider là một lớp tiện ích. Nếu muốn nhận trực tiếp các thông báo của tiện ích, bạn có thể triển khai BroadcastReceiver của riêng mình hoặc ghi đè lệnh gọi lại onReceive(Context,Intent). Sau đây là những ý định mà bạn cần quan tâm:
- ACTION_APPWIDGET_UPDATE
- ACTION_APPWIDGET_DELETED
- ACTION_APPWIDGET_ENABLED
- ACTION_APPWIDGET_DISABLED
- ACTION_APPWIDGET_OPTIONS_CHANGED
Tạo bố cục tiện ích
Bạn phải xác định bố cục ban đầu cho tiện ích của mình trong XML và lưu bố cục đó vào thư mục res/layout/ của dự án. Tham khảo Nguyên tắc thiết kế để biết thông tin chi tiết.
Việc tạo bố cục tiện ích rất đơn giản nếu bạn đã quen thuộc với bố cục. Tuy nhiên, hãy lưu ý rằng bố cục tiện ích dựa trên RemoteViews, không hỗ trợ mọi loại bố cục hoặc tiện ích xem. Bạn không thể sử dụng các khung hiển thị tuỳ chỉnh hoặc các lớp con của khung hiển thị được RemoteViews hỗ trợ.
RemoteViews cũng hỗ trợ ViewStub. Đây là một View vô hình, có kích thước bằng 0 mà bạn có thể dùng để tăng cường từng phần tài nguyên bố cục trong thời gian chạy.
Hỗ trợ hành vi có trạng thái
Android 12 bổ sung tính năng hỗ trợ hành vi có trạng thái bằng cách sử dụng các thành phần hiện có sau đây:
Tiện ích này vẫn không có trạng thái. Ứng dụng của bạn phải lưu trữ trạng thái và đăng ký các sự kiện thay đổi trạng thái.
 
  Ví dụ về mã sau đây cho thấy cách triển khai các thành phần này.
Kotlin
// Check the view. remoteView.setCompoundButtonChecked(R.id.my_checkbox, true) // Check a radio group. remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2) // Listen for check changes. The intent has an extra with the key // EXTRA_CHECKED that specifies the current checked state of the view. remoteView.setOnCheckedChangeResponse( R.id.my_checkbox, RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent) )
Java
// Check the view. remoteView.setCompoundButtonChecked(R.id.my_checkbox, true); // Check a radio group. remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2); // Listen for check changes. The intent has an extra with the key // EXTRA_CHECKED that specifies the current checked state of the view. remoteView.setOnCheckedChangeResponse( R.id.my_checkbox, RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent));
Cung cấp 2 bố cục: một bố cục nhắm đến các thiết bị chạy Android 12 trở lên trong res/layout-v31 và bố cục còn lại nhắm đến Android 11 trở xuống trong thư mục res/layout mặc định.
Triển khai góc bo tròn
Android 12 giới thiệu các tham số hệ thống sau đây để đặt bán kính cho các góc bo tròn của tiện ích:
- system_app_widget_background_radius: bán kính góc của nền tiện ích, không bao giờ lớn hơn 28 dp.
- Bán kính bên trong, có thể được tính từ bán kính bên ngoài và khoảng đệm. Hãy xem đoạn mã sau: - /** * Applies corner radius for views that are visually positioned [widgetPadding]dp inside of the * widget background. */ @Composable fun GlanceModifier.appWidgetInnerCornerRadius(widgetPadding: Dp): GlanceModifier { if (Build.VERSION.SDK_INT < 31) { return this } val resources = LocalContext.current.resources // get dimension in float (without rounding). val px = resources.getDimension(android.R.dimen.system_app_widget_background_radius) val widgetBackgroundRadiusDpValue = px / resources.displayMetrics.density if (widgetBackgroundRadiusDpValue < widgetPadding.value) { return this } return this.cornerRadius(Dp(widgetBackgroundRadiusDpValue - widgetPadding.value)) } 
Để tính toán bán kính phù hợp cho nội dung bên trong của tiện ích, hãy sử dụng công thức sau: systemRadiusValue - widgetPadding
Những tiện ích cắt nội dung thành các hình dạng không phải hình chữ nhật nên sử dụng @android:id/background làm mã nhận dạng khung hiển thị của khung hiển thị nền có android:clipToOutline được đặt thành true.
Những điểm quan trọng cần cân nhắc đối với các góc bo tròn
- Trình chạy của bên thứ ba và nhà sản xuất thiết bị có thể ghi đè tham số system_app_widget_background_radiusđể nhỏ hơn 28 dp.
- Nếu tiện ích của bạn không sử dụng - @android:id/backgroundhoặc xác định một nền cắt nội dung dựa trên đường viền (với- android:clipToOutlineđược đặt thành- true), thì trình chạy sẽ tự động xác định nền và cắt tiện ích bằng cách sử dụng một hình chữ nhật có các góc bo tròn được đặt thành bán kính hệ thống.
- Các hình dạng không phải hình chữ nhật cần nằm trong vùng chứa đổi kích thước hình chữ nhật bo tròn để không bị cắt. 
- Kể từ Android 16, giá trị hệ thống AOSP cho - system_app_widget_background_radiuslà- 24dp. Trình chạy và nhà sản xuất thiết bị có thể cắt tiện ích thành- system_app_widget_background_radius.
- Nội dung bên trong của một tiện ích phải có khoảng đệm đủ để hỗ trợ các giá trị bán kính - system_app_widget_background_radiuslên đến- 28dpnhằm tránh việc các góc bo tròn cắt nội dung.
Để tiện ích tương thích với các phiên bản Android trước, bạn nên xác định các thuộc tính tuỳ chỉnh và sử dụng một giao diện tuỳ chỉnh để ghi đè các thuộc tính đó cho Android 12, như minh hoạ trong các tệp XML mẫu sau:
/values/attrs.xml
<resources>
  <attr name="backgroundRadius" format="dimension" />
</resources>
/values/styles.xml
<resources>
  <style name="MyWidgetTheme">
    <item name="backgroundRadius">@dimen/my_background_radius_dimen</item>
  </style>
</resources>
/values-31/styles.xml
<resources>
  <style name="MyWidgetTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
    <item name="backgroundRadius">@android:dimen/system_app_widget_background_radius</item>
  </style>
</resources>
/drawable/my_widget_background.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">
  <corners android:radius="?attr/backgroundRadius" />
  ...
</shape>
/layout/my_widget_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  android:background="@drawable/my_widget_background" />
 
  