สร้างวิดเจ็ตแบบง่าย

วิดเจ็ตแอปคือมุมมองแอปขนาดเล็กที่คุณสามารถฝังในแอปอื่นๆ เช่น หน้าจอหลัก และรับการอัปเดตเป็นระยะ มุมมองเหล่านี้เรียกว่าวิดเจ็ตในอินเทอร์เฟซผู้ใช้ และคุณสามารถเผยแพร่มุมมองด้วยผู้ให้บริการวิดเจ็ตแอป (หรือผู้ให้บริการวิดเจ็ต) ส่วนประกอบแอปที่เก็บวิดเจ็ตอื่นๆ เรียกว่าโฮสต์วิดเจ็ตแอป (หรือโฮสต์วิดเจ็ต) รูปที่ 1แสดงตัวอย่างวิดเจ็ตเพลง

ตัวอย่างวิดเจ็ตเพลง
รูปที่ 1 ตัวอย่างวิดเจ็ตเพลง

เอกสารนี้อธิบายวิธีเผยแพร่วิดเจ็ตโดยใช้ผู้ให้บริการวิดเจ็ต โปรดดูรายละเอียดเกี่ยวกับการสร้าง AppWidgetHost ของคุณเองเพื่อโฮสต์วิดเจ็ตแอปที่หัวข้อสร้างโฮสต์วิดเจ็ต

ดูข้อมูลเกี่ยวกับวิธีออกแบบวิดเจ็ตได้ที่ภาพรวมวิดเจ็ตแอป

คอมโพเนนต์วิดเจ็ต

หากต้องการสร้างวิดเจ็ต คุณต้องมีองค์ประกอบพื้นฐานต่อไปนี้

ออบเจ็กต์ AppWidgetProviderInfo
อธิบายข้อมูลเมตาของวิดเจ็ต เช่น เลย์เอาต์ของวิดเจ็ต ความถี่ในการอัปเดต และคลาส AppWidgetProvider AppWidgetProviderInfo ได้รับการกำหนดไว้ใน XML ตามที่อธิบายไว้ในเอกสารนี้
ชั้นเรียน AppWidgetProvider
กําหนดเมธอดพื้นฐานที่ช่วยให้คุณโต้ตอบกับวิดเจ็ตแบบเป็นโปรแกรมได้ ซึ่งคุณจะได้รับการแจ้งเตือนเมื่อมีการอัปเดต เปิดตัว ปิดใช้ หรือลบวิดเจ็ต คุณต้องประกาศ AppWidgetProvider ในไฟล์ Manifest แล้วติดตั้งใช้งานตามที่อธิบายไว้ในเอกสารนี้
เลย์เอาต์ของมุมมอง
กําหนดเลย์เอาต์เริ่มต้นสําหรับวิดเจ็ต เลย์เอาต์จะกำหนดไว้ใน XML ตามที่อธิบายไว้ในเอกสารนี้

รูปที่ 2 แสดงวิธีที่คอมโพเนนต์เหล่านี้ทำงานร่วมกับขั้นตอนการประมวลผลวิดเจ็ตแอปโดยรวม

ขั้นตอนการประมวลผลวิดเจ็ตแอป
รูปที่ 2 ขั้นตอนการประมวลผลวิดเจ็ตแอป

หากวิดเจ็ตต้องมีการกําหนดค่าของผู้ใช้ ให้ใช้กิจกรรมการกําหนดค่าวิดเจ็ตแอป กิจกรรมนี้ช่วยให้ผู้ใช้แก้ไขการตั้งค่าวิดเจ็ตได้ เช่น เขตเวลาสำหรับวิดเจ็ตนาฬิกา

นอกจากนี้ เราขอแนะนำให้ปรับปรุงเลย์เอาต์วิดเจ็ตที่ยืดหยุ่น การเพิ่มประสิทธิภาพอื่นๆ วิดเจ็ตขั้นสูง วิดเจ็ตคอลเล็กชัน และการสร้างวิดเจ็ต โฮสต์

ประกาศ XML ของ AppWidgetProviderInfo

ออบเจ็กต์ AppWidgetProviderInfo จะกำหนดคุณภาพที่จำเป็นของวิดเจ็ต กําหนดออบเจ็กต์ AppWidgetProviderInfo ในไฟล์ทรัพยากร XML โดยใช้องค์ประกอบ <appwidget-provider> รายการเดียว แล้วบันทึกในโฟลเดอร์ res/xml/ ของโปรเจ็กต์

ดังที่แสดงในตัวอย่างต่อไปนี้

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

แอตทริบิวต์การปรับขนาดวิดเจ็ต

หน้าจอหลักเริ่มต้นจะจัดวางวิดเจ็ตในหน้าต่างโดยอิงตามตารางกริดของเซลล์ที่มีการกำหนดความสูงและความกว้าง หน้าจอหลักส่วนใหญ่อนุญาตให้วิดเจ็ตมีเฉพาะขนาดที่เป็นจำนวนเต็มหลายเท่าของเซลล์ตารางกริด เช่น 2 เซลล์ในแนวนอน 3 เซลล์ในแนวตั้ง

แอตทริบิวต์การปรับขนาดวิดเจ็ตช่วยให้คุณระบุขนาดเริ่มต้นสำหรับวิดเจ็ต รวมถึงระบุขอบเขตล่างและขอบเขตบนของขนาดวิดเจ็ตได้ ในบริบทนี้ ขนาดเริ่มต้นของวิดเจ็ตคือขนาดที่วิดเจ็ตใช้เมื่อเพิ่มลงในหน้าจอหลักเป็นครั้งแรก

ตารางต่อไปนี้อธิบายแอตทริบิวต์ <appwidget-provider> ที่เกี่ยวข้องกับการปรับขนาดวิดเจ็ต

แอตทริบิวต์และคําอธิบาย
targetCellWidth และ targetCellHeight (Android 12), minWidth และ minHeight
  • ตั้งแต่ Android 12 เป็นต้นไป แอตทริบิวต์ targetCellWidth และ targetCellHeight จะระบุขนาดเริ่มต้นของวิดเจ็ตในแง่ของเซลล์ตารางกริด ระบบจะไม่สนใจแอตทริบิวต์เหล่านี้ใน Android 11 และต่ำกว่า และสามารถไม่สนใจได้หากหน้าจอหลักไม่รองรับเลย์เอาต์แบบตารางกริด
  • แอตทริบิวต์ minWidth และ minHeight จะระบุขนาดเริ่มต้นของวิดเจ็ตเป็น dp หากค่าความกว้างหรือความสูงขั้นต่ำของวิดเจ็ตไม่ตรงกับขนาดของเซลล์ ระบบจะปัดเศษค่าขึ้นเป็นขนาดเซลล์ที่ใกล้ที่สุด
เราขอแนะนำให้ระบุแอตทริบิวต์ทั้ง 2 ชุด ได้แก่ targetCellWidth และ targetCellHeight รวมถึง minWidth และ minHeight เพื่อให้แอปใช้ minWidth และ minHeight แทนได้หากอุปกรณ์ของผู้ใช้ไม่รองรับ targetCellWidth และ targetCellHeight หากระบบรองรับ แอตทริบิวต์ targetCellWidth และ targetCellHeight จะมีความสําคัญเหนือกว่าแอตทริบิวต์ minWidth และ minHeight
minResizeWidth และ minResizeHeight ระบุขนาดขั้นต่ำแบบสัมบูรณ์ของวิดเจ็ต ค่าเหล่านี้ระบุขนาดที่วิดเจ็ตอ่านไม่ออกหรือไม่ใช้งานได้ การใช้แอตทริบิวต์เหล่านี้ช่วยให้ผู้ใช้ปรับขนาดวิดเจ็ตให้เล็กกว่าขนาดเริ่มต้นได้ ระบบจะละเว้นแอตทริบิวต์ minResizeWidth หากมีค่ามากกว่า minWidth หรือไม่เปิดใช้การปรับขนาดแนวนอน ดูresizeMode ในทํานองเดียวกัน ระบบจะละเว้นแอตทริบิวต์ minResizeHeight หากมีค่ามากกว่า minHeight หรือหากไม่ได้เปิดใช้การปรับขนาดแนวตั้ง
maxResizeWidth และ maxResizeHeight ระบุขนาดสูงสุดที่แนะนําของวิดเจ็ต หากค่าไม่ใช่ผลคูณของมิติข้อมูลเซลล์ตารางกริด ระบบจะปัดเศษค่าขึ้นเป็นขนาดเซลล์ที่ใกล้เคียงที่สุด ระบบจะละเว้นแอตทริบิวต์ maxResizeWidth หากมีขนาดเล็กกว่า minWidth หรือหากไม่ได้เปิดใช้การปรับขนาดแนวนอน โปรดดู resizeMode ในทํานองเดียวกัน ระบบจะละเว้นแอตทริบิวต์ maxResizeHeight หากมีค่ามากกว่า minHeight หรือหากไม่ได้เปิดใช้การปรับขนาดแนวตั้ง เปิดตัวใน Android 12
resizeMode ระบุกฎที่ใช้ปรับขนาดวิดเจ็ต คุณใช้แอตทริบิวต์นี้เพื่อทำให้วิดเจ็ตในหน้าจอหลักปรับขนาดได้ในแนวนอน แนวตั้ง หรือทั้ง 2 แกน ผู้ใช้แตะวิดเจ็ตค้างไว้เพื่อแสดงแถบปรับขนาด จากนั้นลากแถบแนวนอนหรือแนวตั้งเพื่อเปลี่ยนขนาดในตารางเลย์เอาต์ ค่าสำหรับแอตทริบิวต์ resizeMode ได้แก่ horizontal, vertical และ none หากต้องการประกาศให้วิดเจ็ตปรับขนาดได้ทั้งในแนวนอนและแนวตั้ง ให้ใช้ horizontal|vertical

ตัวอย่าง

ต่อไปนี้เป็นตัวอย่างที่แสดงให้เห็นว่าแอตทริบิวต์ในตารางก่อนหน้านี้ส่งผลต่อขนาดวิดเจ็ตอย่างไร โดยสมมติว่าข้อมูลจำเพาะมีดังนี้

  • เซลล์ตารางกริดกว้าง 30 dp และสูง 50 dp
  • ข้อมูลจำเพาะของแอตทริบิวต์มีดังนี้
<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" />

ตั้งแต่ Android 12 เป็นต้นไป

ใช้แอตทริบิวต์ targetCellWidth และ targetCellHeight เป็นขนาดเริ่มต้นของวิดเจ็ต

ขนาดของวิดเจ็ตคือ 2x2 โดยค่าเริ่มต้น วิดเจ็ตปรับขนาดได้ต่ำสุด 2x1 หรือสูงสุด 4x3

Android 11 และต่ำกว่า:

ใช้แอตทริบิวต์ minWidth และ minHeight เพื่อคํานวณขนาดเริ่มต้นของวิดเจ็ต

ความกว้างเริ่มต้น = Math.ceil(80 / 30) = 3

ความสูงเริ่มต้น = Math.ceil(80 / 50) = 2

ขนาดของวิดเจ็ตคือ 3x2 โดยค่าเริ่มต้น วิดเจ็ตปรับขนาดได้ตั้งแต่ 2x1 ไปจนถึงเต็มหน้าจอ

แอตทริบิวต์วิดเจ็ตเพิ่มเติม

ตารางต่อไปนี้อธิบายแอตทริบิวต์ <appwidget-provider> ที่เกี่ยวข้องกับคุณภาพอื่นๆ นอกเหนือจากการปรับขนาดวิดเจ็ต

แอตทริบิวต์และคําอธิบาย
updatePeriodMillis กำหนดความถี่ที่เฟรมเวิร์กวิดเจ็ตขอการอัปเดตจาก AppWidgetProvider โดยเรียกใช้เมธอด onUpdate() callback เราไม่รับประกันว่าการอัปเดตจริงจะเกิดขึ้นตรงกับค่านี้ทุกประการ และเราขอแนะนำให้อัปเดตให้น้อยที่สุดเท่าที่จะทำได้ โดยไม่เกิน 1 ครั้งต่อชั่วโมง เพื่อประหยัดแบตเตอรี่ ดูรายการข้อควรพิจารณาทั้งหมดในการเลือกระยะเวลาการอัปเดตที่เหมาะสมได้ที่การเพิ่มประสิทธิภาพสำหรับการอัปเดตเนื้อหาวิดเจ็ต
initialLayout ชี้ไปยังทรัพยากรเลย์เอาต์ที่กำหนดเลย์เอาต์วิดเจ็ต
configure กําหนดกิจกรรมที่จะเปิดขึ้นเมื่อผู้ใช้เพิ่มวิดเจ็ต ซึ่งจะช่วยให้ผู้ใช้กําหนดค่าพร็อพเพอร์ตี้ของวิดเจ็ตได้ ดูหัวข้ออนุญาตให้ผู้ใช้กำหนดค่าวิดเจ็ต ตั้งแต่ Android 12 เป็นต้นไป แอปจะข้ามการกำหนดค่าเริ่มต้นได้ ดูรายละเอียดได้ที่ใช้การกำหนดค่าเริ่มต้นของวิดเจ็ต
description ระบุคําอธิบายสําหรับเครื่องมือเลือกวิดเจ็ตที่จะแสดงสําหรับวิดเจ็ต เปิดตัวใน Android 12
previewLayout (Android 12) และ previewImage (Android 11 และต่ำกว่า)
  • ตั้งแต่ Android 12 เป็นต้นไป แอตทริบิวต์ previewLayout จะระบุตัวอย่างที่ปรับขนาดได้ ซึ่งคุณระบุเป็นเลย์เอาต์ XML ที่ตั้งค่าเป็นขนาดเริ่มต้นของวิดเจ็ต โดยหลักการแล้ว XML เลย์เอาต์ที่ระบุเป็นแอตทริบิวต์นี้ควรเป็น XML เลย์เอาต์เดียวกับวิดเจ็ตจริงที่มีค่าเริ่มต้นที่สมจริง
  • ใน Android 11 หรือต่ำกว่า แอตทริบิวต์ previewImage จะระบุตัวอย่างลักษณะที่วิดเจ็ตจะแสดงหลังจากกําหนดค่า ซึ่งผู้ใช้จะเห็นเมื่อเลือกวิดเจ็ตแอป หากไม่ระบุ ผู้ใช้จะเห็นไอคอน Launcher ของแอปแทน ช่องนี้สอดคล้องกับแอตทริบิวต์ android:previewImage ในองค์ประกอบ <receiver> ในไฟล์ AndroidManifest.xml
หมายเหตุ: เราขอแนะนำให้ระบุทั้งแอตทริบิวต์ previewImage และ previewLayout เพื่อให้แอปเปลี่ยนกลับไปใช้ previewImage ได้หากอุปกรณ์ของผู้ใช้ไม่รองรับ previewLayout โปรดดูรายละเอียดเพิ่มเติมที่หัวข้อความเข้ากันได้แบบย้อนหลังกับตัวอย่างวิดเจ็ตที่ปรับขนาดได้
autoAdvanceViewId ระบุรหัสมุมมองของมุมมองย่อยของวิดเจ็ตที่โฮสต์ของวิดเจ็ตเลื่อนไปโดยอัตโนมัติ
widgetCategory ประกาศว่าวิดเจ็ตจะแสดงบนหน้าจอหลัก (home_screen) หน้าจอล็อก (keyguard) หรือทั้ง 2 หน้าจอ สำหรับ Android 5.0 ขึ้นไป เฉพาะ home_screen เท่านั้นที่ใช้ได้
widgetFeatures ประกาศฟีเจอร์ที่วิดเจ็ตรองรับ ตัวอย่างเช่น หากต้องการให้วิดเจ็ตใช้การกำหนดค่าเริ่มต้นเมื่อผู้ใช้เพิ่ม ให้ระบุทั้ง Flag configuration_optional และ reconfigurable ซึ่งจะข้ามการเปิดใช้งานกิจกรรมการกําหนดค่าหลังจากที่ผู้ใช้เพิ่มวิดเจ็ต ผู้ใช้จะยังคงกำหนดค่าวิดเจ็ตอีกครั้งได้หลังจากนั้น

ใช้คลาส AppWidgetProvider เพื่อจัดการการออกอากาศวิดเจ็ต

คลาส AppWidgetProvider จะจัดการการออกอากาศวิดเจ็ตและอัปเดตวิดเจ็ตเพื่อตอบสนองต่อเหตุการณ์ในวงจรชีวิตของวิดเจ็ต ส่วนต่อไปนี้อธิบายวิธีประกาศ AppWidgetProvider ในไฟล์ Manifest แล้วนำไปใช้งาน

ประกาศวิดเจ็ตในไฟล์ Manifest

ก่อนอื่น ให้ประกาศคลาส AppWidgetProvider ในไฟล์ AndroidManifest.xml ของแอป ดังที่แสดงในตัวอย่างต่อไปนี้

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

องค์ประกอบ <receiver> ต้องมีแอตทริบิวต์ android:name ซึ่งระบุ AppWidgetProvider ที่วิดเจ็ตใช้ คุณต้องไม่ส่งออกคอมโพเนนต์ เว้นแต่ว่าจะต้องออกอากาศไปยัง AppWidgetProvider ด้วยกระบวนการแยกต่างหาก ซึ่งโดยปกติแล้วจะไม่จำเป็น

องค์ประกอบ <intent-filter> ต้องมีองค์ประกอบ <action> ที่แอตทริบิวต์ android:name แอตทริบิวต์นี้ระบุว่า AppWidgetProvider ยอมรับการออกอากาศACTION_APPWIDGET_UPDATE นี่เป็นรายการเดียวที่คุณต้องประกาศอย่างชัดเจน AppWidgetManager จะส่งการออกอากาศวิดเจ็ตอื่นๆ ทั้งหมดไปยัง AppWidgetProvider โดยอัตโนมัติตามที่จำเป็น

องค์ประกอบ <meta-data> จะระบุทรัพยากร AppWidgetProviderInfo และต้องใช้แอตทริบิวต์ต่อไปนี้

  • android:name: ระบุชื่อข้อมูลเมตา ใช้ android.appwidget.provider เพื่อระบุว่าข้อมูลเป็นข้อบ่งชี้ AppWidgetProviderInfo
  • android:resource: ระบุตำแหน่งแหล่งข้อมูล AppWidgetProviderInfo

ใช้คลาส AppWidgetProvider

คลาส AppWidgetProvider ขยายจาก BroadcastReceiver เป็นคลาสอำนวยความสะดวกในการจัดการการออกอากาศวิดเจ็ต โดยจะรับเฉพาะการออกอากาศเหตุการณ์ที่เกี่ยวข้องกับวิดเจ็ต เช่น เมื่อมีการอัปเดต วิดเจ็ตถูกลบ เปิดใช้ และปิดใช้ เมื่อเหตุการณ์การออกอากาศเหล่านี้เกิดขึ้น ระบบจะเรียกใช้วิธีต่อไปนี้ AppWidgetProvider

onUpdate()
การเรียกใช้นี้จะอัปเดตวิดเจ็ตเป็นระยะตามที่กำหนดโดยแอตทริบิวต์ updatePeriodMillis ใน AppWidgetProviderInfo ดูข้อมูลเพิ่มเติมได้ในตารางที่อธิบายแอตทริบิวต์วิดเจ็ตเพิ่มเติมในหน้านี้
นอกจากนี้ ระบบจะเรียกใช้เมธอดนี้เมื่อผู้ใช้เพิ่มวิดเจ็ตด้วย เพื่อทำการตั้งค่าที่จําเป็น เช่น การกําหนดตัวแฮนเดิลเหตุการณ์สําหรับออบเจ็กต์ View หรือเริ่มงานเพื่อโหลดข้อมูลเพื่อแสดงในวิดเจ็ต อย่างไรก็ตาม หากคุณประกาศกิจกรรมการกําหนดค่าโดยไม่มี Flag configuration_optional ระบบจะไม่เรียกใช้เมธอดนี้เมื่อผู้ใช้เพิ่มวิดเจ็ต แต่จะเรียกใช้เมธอดนี้สําหรับการอัปเดตในภายหลัง กิจกรรมการกําหนดค่ามีหน้าที่รับผิดชอบในการดําเนินการอัปเดตครั้งแรกเมื่อการกําหนดค่าเสร็จสมบูรณ์ โปรดดูข้อมูลเพิ่มเติมที่หัวข้ออนุญาตให้ผู้ใช้กำหนดค่าวิดเจ็ตแอป
การเรียกกลับที่สําคัญที่สุดคือ onUpdate() ดูข้อมูลเพิ่มเติมที่หัวข้อจัดการเหตุการณ์ด้วยคลาส onUpdate() ในหน้านี้
onAppWidgetOptionsChanged()

ฟังก์ชันนี้จะเรียกใช้เมื่อวางวิดเจ็ตเป็นครั้งแรกและทุกครั้งที่ปรับขนาดวิดเจ็ต ใช้การเรียกกลับนี้เพื่อแสดงหรือซ่อนเนื้อหาตามช่วงขนาดของวิดเจ็ต รับช่วงขนาด และตั้งแต่ Android 12 เป็นต้นไป ให้รับรายการขนาดที่อินสแตนซ์วิดเจ็ตใช้ได้โดยเรียกใช้ getAppWidgetOptions() ซึ่งจะแสดงผล Bundle ที่มีข้อมูลต่อไปนี้

  • OPTION_APPWIDGET_MIN_WIDTH: มีขอบเขตล่างของความกว้างในหน่วย dp ของอินสแตนซ์วิดเจ็ต
  • OPTION_APPWIDGET_MIN_HEIGHT: มีขีดจำกัดล่างของความสูงในหน่วย dp ของอินสแตนซ์วิดเจ็ต
  • OPTION_APPWIDGET_MAX_WIDTH: มีขีดจำกัดบนของความกว้างในหน่วย dp ของอินสแตนซ์วิดเจ็ต
  • OPTION_APPWIDGET_MAX_HEIGHT: มีขีดจำกัดบนของส่วนสูงในหน่วย dp ของอินสแตนซ์วิดเจ็ต
  • OPTION_APPWIDGET_SIZES: มีรายการขนาด (List<SizeF>) ที่เป็นไปได้ในหน่วย dp ที่อินสแตนซ์วิดเจ็ตใช้ เปิดตัวใน Android 12
onDeleted(Context, int[])

ซึ่งจะเรียกใช้ทุกครั้งที่ลบวิดเจ็ตออกจากโฮสต์วิดเจ็ต

onEnabled(Context)

ฟังก์ชันนี้จะเรียกใช้เมื่อมีการสร้างอินสแตนซ์ของวิดเจ็ตเป็นครั้งแรก เช่น หากผู้ใช้เพิ่มวิดเจ็ต 2 อินสแตนซ์ ระบบจะเรียกใช้เหตุการณ์นี้เพียงครั้งแรกเท่านั้น หากต้องการเปิดฐานข้อมูลใหม่หรือทำการตั้งค่าอื่นที่ต้องทำเพียงครั้งเดียวสำหรับอินสแตนซ์วิดเจ็ตทั้งหมด ตัวเลือกนี้เหมาะสําหรับการดำเนินการ

onDisabled(Context)

ฟังก์ชันนี้จะเรียกใช้เมื่ออินสแตนซ์สุดท้ายของวิดเจ็ตถูกลบออกจากโฮสต์วิดเจ็ต ในส่วนนี้คุณจะล้างข้อมูลงานที่ทำใน onEnabled(Context) เช่น ลบฐานข้อมูลชั่วคราว

onReceive(Context, Intent)

ฟังก์ชันนี้จะเรียกใช้สำหรับการออกอากาศทุกครั้งและก่อนการเรียกกลับแต่ละวิธีก่อนหน้า โดยปกติแล้วคุณไม่จําเป็นต้องใช้เมธอดนี้ เนื่องจากAppWidgetProviderการใช้งานเริ่มต้นจะกรองการออกอากาศวิดเจ็ตทั้งหมดและเรียกใช้เมธอดก่อนหน้าตามความเหมาะสม

คุณต้องประกาศการใช้งานคลาส AppWidgetProvider เป็นรีซีฟเวอร์การออกอากาศโดยใช้องค์ประกอบ <receiver> ใน AndroidManifest ดูข้อมูลเพิ่มเติมได้ในหัวข้อประกาศวิดเจ็ตในไฟล์ Manifest ในหน้านี้

จัดการเหตุการณ์ด้วยคลาส onUpdate()

AppWidgetProvider callback ที่สําคัญที่สุดคือ onUpdate() เนื่องจากระบบจะเรียกใช้เมื่อเพิ่มวิดเจ็ตแต่ละรายการลงในโฮสต์ เว้นแต่คุณจะใช้กิจกรรมการกําหนดค่าที่ไม่มี Flag configuration_optional หากวิดเจ็ตยอมรับเหตุการณ์การโต้ตอบของผู้ใช้ ให้ลงทะเบียนตัวแฮนเดิลเหตุการณ์ใน Callback นี้ หากวิดเจ็ตไม่ได้สร้างไฟล์หรือฐานข้อมูลชั่วคราว หรือทํางานอื่นๆ ที่จําเป็นต้องล้างข้อมูล onUpdate() อาจเป็นเมธอดการเรียกกลับเพียงรายการเดียวที่คุณต้องกําหนด

ตัวอย่างเช่น หากต้องการวิดเจ็ตที่มีปุ่มเปิดใช้งานกิจกรรมเมื่อแตะ คุณสามารถใช้ AppWidgetProvider ดังนี้

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 นี้จะกำหนดเฉพาะเมธอด onUpdate() โดยใช้เพื่อสร้าง PendingIntent ที่เปิด Activity และแนบกับปุ่มของวิดเจ็ตโดยใช้ setOnClickPendingIntent(int, PendingIntent) ซึ่งประกอบด้วยลูปที่วนผ่านรายการแต่ละรายการใน appWidgetIds ซึ่งเป็นอาร์เรย์รหัสที่ระบุวิดเจ็ตแต่ละรายการที่สร้างขึ้นโดยผู้ให้บริการรายนี้ หากผู้ใช้สร้างวิดเจ็ตมากกว่า 1 อินสแตนซ์ วิดเจ็ตทั้งหมดจะอัปเดตพร้อมกัน อย่างไรก็ตาม ระบบจะจัดการupdatePeriodMillisกําหนดเวลา เพียงรายการเดียวสําหรับอินสแตนซ์ทั้งหมดของวิดเจ็ต เช่น หากกําหนดกําหนดการอัปเดตเป็นทุก 2 ชั่วโมง และเพิ่มอินสแตนซ์ที่ 2 ของวิดเจ็ตหลังจากอินสแตนซ์แรก 1 ชั่วโมง ระบบจะอัปเดตทั้ง 2 รายการตามระยะเวลาที่กําหนดโดยอินสแตนซ์แรก และจะไม่สนใจระยะเวลาการอัปเดตที่ 2 โดยทั้ง 2 รายการจะอัปเดตทุก 2 ชั่วโมง ไม่ใช่ทุกชั่วโมง

ดูรายละเอียดเพิ่มเติมได้ในคลาสตัวอย่างของ ExampleAppWidgetProvider.java

รับ Intent การเผยแพร่วิดเจ็ต

AppWidgetProvider เป็นคลาสช่วยอำนวยความสะดวก หากต้องการรับการออกอากาศวิดเจ็ตโดยตรง คุณสามารถใช้ BroadcastReceiver ของคุณเองหรือลบล้างการเรียกกลับ onReceive(Context,Intent) เจตนาที่คุณควรให้ความสำคัญมีดังนี้

สร้างเลย์เอาต์วิดเจ็ต

คุณต้องกำหนดเลย์เอาต์เริ่มต้นสำหรับวิดเจ็ตใน XML และบันทึกไว้ในไดเรกทอรี res/layout/ ของโปรเจ็กต์ ดูรายละเอียดได้ในหลักเกณฑ์ด้านการออกแบบ

การสร้างเลย์เอาต์วิดเจ็ตนั้นง่ายดายหากคุณคุ้นเคยกับเลย์เอาต์ อย่างไรก็ตาม โปรดทราบว่าเลย์เอาต์วิดเจ็ตจะอิงตาม RemoteViews ซึ่งไม่รองรับเลย์เอาต์หรือวิดเจ็ตมุมมองบางประเภท คุณไม่สามารถใช้มุมมองที่กำหนดเองหรือคลาสย่อยของมุมมองที่ RemoteViews รองรับ

RemoteViews ยังรองรับ ViewStub ซึ่งเป็น View ที่ไม่มีขนาดและมองไม่เห็น ซึ่งคุณใช้เพื่อขยายทรัพยากรเลย์เอาต์แบบ Lazy Load ขณะรันไทม์ได้

รองรับลักษณะการทำงานที่มีสถานะ

Android 12 เพิ่มการรองรับลักษณะการทำงานที่มีสถานะโดยใช้คอมโพเนนต์ที่มีอยู่ต่อไปนี้

วิดเจ็ตยังคงเป็นแบบไม่มีสถานะ แอปของคุณต้องจัดเก็บสถานะและลงทะเบียนเพื่อรับเหตุการณ์การเปลี่ยนแปลงสถานะ

ตัวอย่างวิดเจ็ตรายการช็อปปิ้งที่แสดงลักษณะการทำงานที่มีสถานะ
รูปที่ 3 ตัวอย่างลักษณะการทำงานที่มีสถานะ

ตัวอย่างโค้ดต่อไปนี้แสดงวิธีใช้คอมโพเนนต์เหล่านี้

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));

ระบุเลย์เอาต์ 2 แบบ โดยแบบหนึ่งกำหนดเป้าหมายเป็นอุปกรณ์ที่ใช้ Android 12 ขึ้นไปใน res/layout-v31 และอีกแบบกำหนดเป้าหมายเป็น Android 11 หรือต่ำกว่าในโฟลเดอร์ res/layout เริ่มต้น

ใช้มุมมน

Android 12 เปิดตัวพารามิเตอร์ระบบต่อไปนี้เพื่อกำหนดรัศมีของมุมที่โค้งมนของวิดเจ็ต

  • system_app_widget_background_radius: รัศมีมุมของพื้นหลังวิดเจ็ต ซึ่งต้องไม่เกิน 28 dp

  • system_app_widget_inner_radius: รัศมีมุมของมุมมองภายในวิดเจ็ต ซึ่งน้อยกว่ารัศมีของพื้นหลัง 8 dp พอดี เพื่อให้จัดวางได้อย่างเหมาะสมเมื่อใช้ระยะขอบ 8 dp

ตัวอย่างต่อไปนี้แสดงวิดเจ็ตที่ใช้ system_app_widget_background_radius สำหรับมุมของวิดเจ็ต และ system_app_widget_inner_radius สำหรับมุมมองภายในวิดเจ็ต

วิดเจ็ตที่แสดงรัศมีของพื้นหลังวิดเจ็ตและมุมมองภายในวิดเจ็ต
รูปที่ 4 มุมมน

1 มุมของวิดเจ็ต

2 มุมของมุมมองภายในวิดเจ็ต

ข้อควรพิจารณาที่สำคัญสำหรับมุมมน

  • เครื่องมือเปิดของบุคคลที่สามและผู้ผลิตอุปกรณ์สามารถลบล้างพารามิเตอร์ system_app_widget_background_radius ให้เล็กกว่า 28 dp ได้ พารามิเตอร์ system_app_widget_inner_radius มีค่าน้อยกว่าค่าของ system_app_widget_background_radius เสมอ 8 dp
  • หากวิดเจ็ตไม่ได้ใช้ @android:id/background หรือกำหนดพื้นหลังที่จะตัดเนื้อหาตามขอบโดยตั้งค่า android:clipToOutline เป็น true โปรแกรมเปิดใช้จะระบุพื้นหลังโดยอัตโนมัติและตัดวิดเจ็ตโดยใช้สี่เหลี่ยมผืนผ้าที่มีมุมมนไม่เกิน 16 dp ดูตรวจสอบว่าวิดเจ็ตของคุณเข้ากันได้กับ Android 12

สำหรับความเข้ากันได้ของวิดเจ็ตกับ Android เวอร์ชันก่อนหน้า เราขอแนะนำให้กำหนดแอตทริบิวต์ที่กำหนดเองและใช้ธีมที่กำหนดเองเพื่อลบล้างแอตทริบิวต์เหล่านั้นสำหรับ Android 12 ดังที่แสดงในไฟล์ XML ตัวอย่างต่อไปนี้

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