Tạo tiện ích ứng dụng bằng tính năng Xem nhanh

tệp kê khai, siêu dữ liệu

Các phần sau đây mô tả cách tạo một tiện ích cơ bản cho ứng dụng bằng Glance.

Khai báo AppWidget trong tệp kê khai

Sau khi hoàn tất các bước thiết lập, hãy khai báo AppWidget và siêu dữ liệu của nó trong ứng dụng.

  1. Mở rộng bộ nhận AppWidget từ GlanceAppWidgetReceiver:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
        override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget")
    }

  2. Đăng ký nhà cung cấp tiện ích ứng dụng trong tệp AndroidManifest.xml và tệp siêu dữ liệu được liên kết:

        <receiver android:name=".glance.MyReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/my_app_widget_info" />
    </receiver>
    

Thêm siêu dữ liệu AppWidgetProviderInfo

Tiếp theo, hãy làm theo hướng dẫn Tạo một tiện ích để tạo và xác định thông tin tiện ích ứng dụng trong tệp @xml/my_app_widget_info.

Điểm khác biệt duy nhất đối với Glance là không có tệp XML initialLayout, nhưng bạn phải xác định một tệp. Bạn có thể sử dụng bố cục tải được xác định trước có trong thư viện:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>

Khai báo XML AppWidgetProviderInfo

Đối tượng AppWidgetProviderInfo xác định những đặc điểm thiết yếu của tiện ích. Xác định AppWidgetProviderInfo trong tệp tài nguyên siêu dữ liệu XML (res/xml/my_app_widget_info.xml) bên trong phần tử <appwidget-provider>:

<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/glance_default_loading_layout"
    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ả
targetCellWidthtargetCellHeight (Android 12), minWidthminHeight
  • Kể từ Android 12, các thuộc tính targetCellWidthtargetCellHeight chỉ định kích thước mặc định của tiện ích theo ô lưới. Các thuộc tính này sẽ bị bỏ qua trong Android 11 trở xuống và có thể bị bỏ qua nếu màn hình chính không hỗ trợ bố cục dựa trên lưới.
  • Thuộc tính minWidthminHeight chỉ định kích thước mặc định của tiện ích theo dp. Nếu các giá trị cho chiều rộng hoặc chiều cao tối thiểu của một tiện ích không khớp với kích thước của các ô, thì các giá trị sẽ được làm tròn lên đến kích thước ô gần nhất.
Bạn nên chỉ định cả hai nhóm thuộc tính – targetCellWidthtargetCellHeight, cũng như minWidthminHeight – để ứng dụng của bạn có thể quay lại sử dụng minWidthminHeight nếu thiết bị của người dùng không hỗ trợ targetCellWidthtargetCellHeight. Nếu được hỗ trợ, các thuộc tính targetCellWidthtargetCellHeight sẽ được ưu tiên hơn các thuộc tính minWidthminHeight.
minResizeWidthminResizeHeight 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 minResizeWidth sẽ bị bỏ qua nếu lớn hơn minWidth hoặc nếu bạn không bật tính năng đổi kích thước theo chiều ngang. Xem phần resizeMode. Tương tự, thuộc tính minResizeHeight sẽ bị bỏ qua nếu lớn hơn minHeight hoặc nếu bạn không bật tính năng đổi kích thước theo chiều dọc.
maxResizeWidthmaxResizeHeight 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 đến kích thước ô gần nhất. Thuộc tính maxResizeWidth sẽ bị bỏ qua nếu nhỏ hơn minWidth hoặc nếu bạn không bật tính năng đổi kích thước theo chiều ngang. Hãy xem resizeMode. Tương tự, thuộc tính maxResizeHeight sẽ bị bỏ qua nếu nhỏ hơn minHeight hoặ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 trên cả hai trục. Người dùng chạm và giữ một tiện ích để hiện các ô điều khiển thay đổ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 resizeMode bao gồm horizontal, verticalnone. Để 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ụng horizontal|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 thuộc tính targetCellWidthtargetCellHeight 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 minWidthminHeight để 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ể giảm kích thước của tiện ích xuống 2x1 hoặc tăng lê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ừ GlanceAppWidgetReceiver bằng cách gọi phương thức gọi lại onUpdate(). Bạn nên cập nhật ít thường xuyên nhất có thể (không quá một lần mỗi giờ) để tiết kiệm pin. Để biết thông tin chi tiết, hãy xem phần Thời điểm cập nhật tiện ích trong bài viết Quản lý trạng thái Glance.
initialLayout Chỉ đến tài nguyên bố cục xác định bố cục tải của tiện ích trước khi các thành phần giao diện người dùng Glance kết xuất. Bạn có thể sử dụng bố cục tải được xác định trước có trong thư viện: @layout/glance_default_loading_layout.
configure Xác định hoạt động định cấu hình sẽ chạy khi người dùng thêm tiện ích. Hãy xem phần Triển khai một Hoạt động định cấu hình tiện ích trên trang này.
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)
  • Kể từ Android 12, thuộc tính previewLayout chỉ định một bản xem trước có thể mở rộng mà bạn cung cấp dưới dạng một bố cục XML được đặt thành kích thước mặc định của tiện ích. Lý tưởng nhất là thao tác này sẽ trỏ đến một ánh xạ XML tĩnh phù hợp với bố cục thiết kế của bạn.
  • Trong Android 11 trở xuống, thuộc tính previewImage chỉ định ảnh chụp màn hình tĩnh của hình ảnh có thể vẽ về giao diện của tiện ích, xuất hiện trong bộ chọn tiện ích.
Bạn nên chỉ định cả hai để ứng dụng của bạn có thể hoạt động bình thường trên các nền tảng cũ. Đối với các nền tảng mới hơn (Android 15 trở lên), bạn có thể xác định bản xem trước được tạo trực tiếp bằng Kotlin bằng cách sử dụng `GlanceAppWidget.providePreview`. Hãy xem hướng dẫn về Bản xem trước được tạo.
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_screen mới hợp lệ.
widgetFeatures Khai báo các tính năng mà tiện ích hỗ trợ. Ví dụ: nếu cấu hình tiện ích của bạn là không bắt buộc, hãy chỉ định cả configuration_optionalreconfigurable.

Xác định GlanceAppWidget

  1. Tạo một lớp mới mở rộng từ GlanceAppWidget và ghi đè phương thức provideGlance. Đây là phương thức mà bạn có thể tải dữ liệu cần thiết để hiển thị tiện ích:

    class MyAppWidget : GlanceAppWidget() {
    
        override suspend fun provideGlance(context: Context, id: GlanceId) {
    
            // In this method, load data needed to render the AppWidget.
            // Use `withContext` to switch to another thread for long running
            // operations.
    
            provideContent {
                // create your AppWidget here
                Text("Hello World")
            }
        }
    }

  2. Tạo thực thể cho nó trong glanceAppWidget trên GlanceAppWidgetReceiver của bạn:

    class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
    
        // Let MyAppWidgetReceiver know which GlanceAppWidget to use
        override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
    }

Giờ đây, bạn đã định cấu hình AppWidget bằng Glance.

Sử dụng lớp AppWidgetProvider để xử lý thông báo truyền tin của tiện ích

Tiện ích GlanceAppWidgetReceiver toạ độ phát và cập nhật trạng thái nền tảng bằng cách mở rộng AppWidgetProvider cơ bản. Nó nhận các sự kiện nền tảng khi tiện ích của bạn được cập nhật, xoá, bật hoặc tắt, chuyển đổi các sự kiện đó thành các yêu cầu vòng đời Compose.

Khai báo một tiện ích trong tệp kê khai

Khai báo lớp con GlanceAppWidgetReceiver của bạn làm bộ nhận tín hiệu truyền tin trong tệp AndroidManifest.xml:

<receiver android:name="ExampleAppWidgetReceiver"
          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/my_app_widget_info" />
</receiver>

Phần tử <receiver> yêu cầu thuộc tính android:name. Thuộc tính này chỉ định lớp nhận. Receiver phải chấp nhận thao tác truyền tin ACTION_APPWIDGET_UPDATE bên trong <intent-filter>.

Phần tử <meta-data> phải xác định tên của phần tử đó là android.appwidget.provider và thuộc tính android:resource phải trỏ đến tài nguyên siêu dữ liệu XML AppWidgetProviderInfo (@xml/my_app_widget_info).

Triển khai lớp AppWidgetProvider

Trong Glance, bạn mở rộng GlanceAppWidgetReceiver thay vì AppWidgetProvider trực tiếp. Triển khai bằng cách liên kết bộ nhận với phiên bản GlanceAppWidget. Các lệnh gọi lại chính có trong GlanceAppWidgetReceiver hoạt động như sau:

  • onUpdate(): Tự động bị Glance ghi đè để thực thi các bản cập nhật thành phần. Nếu ghi đè onUpdate theo cách thủ công, bạn phải gọi super.onUpdate để Glance có thể khởi chạy các luồng thành phần một cách thành công.
  • onAppWidgetOptionsChanged(): Được gọi khi tiện ích được đặt hoặc đổi kích thước lần đầu tiên. Gói các mục tuỳ chọn đọc nhanh ở chế độ nền để bố cục của bạn điều chỉnh liền mạch dựa trên các phương diện thời gian chạy.
  • onDeleted(Context, IntArray): Được gọi bất cứ khi nào người dùng xoá một phiên bản tiện ích cụ thể.
  • onEnabled(Context): Kích hoạt khi phiên bản đầu tiên của tiện ích được tạo thành công. Rất phù hợp để chạy các quy trình di chuyển trên toàn cầu.
  • onDisabled(Context): Được gọi khi phiên bản hoạt động gần đây nhất của trình cung cấp bị xoá.
  • onReceive(Context, Intent): Chặn mọi thông báo truyền tin của nền tảng trước các phương thức gọi lại cụ thể. Bạn phải đảm bảo rằng mọi logic của receiver tuỳ chỉnh mà bạn viết đều gọi super.onReceive(context, intent)không bao giờ được gọi goAsync vì Glance tự động định tuyến công việc không đồng bộ.

Nhận ý định truyền tin của tiện ích

Theo cách không rõ ràng, GlanceAppWidgetReceiver sẽ lọc và xử lý các ý định truyền tin cơ bản sau đây của tiện ích nền tảng:

Tạo giao diện người dùng

Đoạn mã sau đây minh hoạ cách tạo giao diện người dùng:

/* Import Glance Composables
 In the event there is a name clash with the Compose classes of the same name,
 you may rename the imports per https://kotlinlang.org/docs/packages.html#imports
 using the `as` keyword.

import androidx.glance.Button
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.text.Text
*/
class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // Load data needed to render the AppWidget.
        // Use `withContext` to switch to another thread for long running
        // operations.

        provideContent {
            // create your AppWidget here
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        Column(
            modifier = GlanceModifier.fillMaxSize(),
            verticalAlignment = Alignment.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button(
                    text = "Home",
                    onClick = actionStartActivity<MyActivity>()
                )
                Button(
                    text = "Work",
                    onClick = actionStartActivity<MyActivity>()
                )
            }
        }
    }
}

Mã mẫu trên thực hiện những việc sau:

  • Trong Column cấp cao nhất, các mục được đặt theo chiều dọc, lần lượt sau nhau.
  • Column mở rộng kích thước để phù hợp với không gian có sẵn (thông qua GlanceModifier) và căn chỉnh nội dung của không gian đó lên trên cùng (verticalAlignment) và căn giữa theo chiều ngang (horizontalAlignment).
  • Nội dung của Column được xác định bằng lambda. Thứ tự rất quan trọng.
    • Mục đầu tiên trong Column là một thành phần Text12.dp khoảng đệm.
    • Mục thứ hai là một Row, trong đó các mục được đặt theo chiều ngang, lần lượt từng mục một, với hai Buttons được căn giữa theo chiều ngang (horizontalAlignment). Màn hình cuối cùng sẽ phụ thuộc vào không gian có sẵn. Hình ảnh sau đây là một ví dụ về giao diện của thẻ này:
destination_widget
Hình 1. Một ví dụ về giao diện người dùng.

Bạn có thể thay đổi các giá trị căn chỉnh hoặc áp dụng các giá trị đối tượng sửa đổi khác (chẳng hạn như khoảng đệm) để thay đổi vị trí và kích thước của các thành phần. Hãy xem tài liệu tham khảo để biết danh sách đầy đủ các thành phần, tham số và bộ sửa đổi có sẵn cho từng lớp.

Triển khai góc bo tròn

Android 12 giới thiệu các tham số hệ thống để tuỳ chỉnh bán kính góc của các tiện ích ứng dụng một cách linh hoạt:

  • system_app_widget_background_radius: Chỉ định bán kính góc của vùng chứa nền tiện ích (không bao giờ lớn hơn 28 dp).
  • Bán kính bên trong: Để ngăn nội dung bị cắt, hãy tính toán bán kính tỷ lệ cho nội dung bên trong dựa trên đường viền nền hệ thống:systemRadiusValue - widgetPadding

Trong Glance, bạn có thể áp dụng các thuộc tính định cỡ bán kính góc một cách linh động trong thành phần bằng cách sử dụng GlanceModifier.cornerRadius(android.R.dimen.system_app_widget_background_radius).

Để có khả năng tương thích ngược trên các thiết bị chạy Android 11 (cấp độ API 30) trở xuống, hãy triển khai các thuộc tính tuỳ chỉnh và các giải pháp dự phòng cho tài nguyên giao diện tuỳ chỉnh:

  • /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>