หน้านี้จะอธิบายแนวทางปฏิบัติที่แนะนำในการสร้างวิดเจ็ตขั้นสูงขึ้นสำหรับ ประสบการณ์ของผู้ใช้ที่ดีขึ้น
การเพิ่มประสิทธิภาพสำหรับการอัปเดตเนื้อหาวิดเจ็ต
การอัปเดตเนื้อหาของวิดเจ็ตอาจทำให้การคํานวณมีค่าใช้จ่ายสูง เพื่อประหยัดแบตเตอรี่ รวมถึงเพิ่มประสิทธิภาพของประเภท ความถี่ และช่วงเวลาของการอัปเดต
ประเภทการอัปเดตวิดเจ็ต
คุณสามารถอัปเดตวิดเจ็ตได้ 3 วิธี ได้แก่ การอัปเดตแบบเต็ม การอัปเดตบางส่วน และ ในกรณีของวิดเจ็ตคอลเล็กชัน จะมีการรีเฟรชข้อมูล โดยแต่ละประเภทมี ต้นทุนการคำนวณและผลที่ตามมา
ต่อไปนี้เป็นคำอธิบายการอัปเดตแต่ละประเภทและให้ข้อมูลโค้ดสำหรับแต่ละประเภท
อัปเดตเต็มรูปแบบ: โทร
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)
อัปเดตวิดเจ็ตโดยสมบูรณ์ ตัวเลือกนี้แทนที่ตัวเลือกก่อนหน้าRemoteViews
พร้อมรูปภาพRemoteViews
นี่เป็นการอัปเดตที่แพงที่สุดที่ใช้การประมวลผลKotlin
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.getPackageName(), R.layout.widgetlayout).also { setTextViewText(R.id.textview_widget_layout1, "Updated text1") setTextViewText(R.id.textview_widget_layout2, "Updated text2") } appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout); remoteViews.setTextViewText(R.id.textview_widget_layout1, "Updated text1"); remoteViews.setTextViewText(R.id.textview_widget_layout2, "Updated text2"); appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
การอัปเดตบางส่วน: การโทร
AppWidgetManager.partiallyUpdateAppWidget
เพื่ออัปเดตส่วนต่างๆ ของวิดเจ็ต การดำเนินการนี้จะรวมRemoteViews
ใหม่เข้ากับ ระบุไว้ก่อนหน้านี้RemoteViews
ระบบจะไม่สนใจวิธีนี้หากวิดเจ็ต ไม่ได้รับการอัปเดตเต็มรูปแบบอย่างน้อย 1 รายการผ่านupdateAppWidget(int[], RemoteViews)
Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) val remoteViews = RemoteViews(context.getPackageName(), R.layout.widgetlayout).also { setTextViewText(R.id.textview_widget_layout, "Updated text") } appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout); remoteViews.setTextViewText(R.id.textview_widget_layout, "Updated text"); appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews);
การรีเฟรชข้อมูลคอลเล็กชัน: การเรียกใช้
AppWidgetManager.notifyAppWidgetViewDataChanged
เพื่อเลิกใช้ข้อมูลของมุมมองคอลเล็กชันในวิดเจ็ต ทริกเกอร์นี้RemoteViewsFactory.onDataSetChanged
ในระหว่างนี้ ข้อมูลเก่าจะแสดงในวิดเจ็ต คุณสามารถ ทำงานที่มีค่าใช้จ่ายสูงพร้อมกันด้วยวิธีนี้Kotlin
val appWidgetManager = AppWidgetManager.getInstance(context) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
Java
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview);
คุณเรียกใช้วิธีการเหล่านี้ได้จากทุกที่ในแอปตราบใดที่แอป
UID เดียวกันกับที่ระบุ
AppWidgetProvider
กำหนดความถี่ในการอัปเดตวิดเจ็ต
วิดเจ็ตจะอัปเดตเป็นระยะตามค่าที่ระบุสำหรับ
updatePeriodMillis
วิดเจ็ตสามารถอัปเดตตามการโต้ตอบของผู้ใช้ ประกาศ
หรือทั้ง 2 อย่าง
อัปเดตเป็นระยะ
คุณสามารถควบคุมความถี่ของการอัปเดตเป็นระยะๆ ได้โดยการระบุค่าสำหรับ
AppWidgetProviderInfo.updatePeriodMillis
ใน XML ของ appwidget-provider
ชิ้น
อัปเดตจะทริกเกอร์เมธอด AppWidgetProvider.onUpdate()
ซึ่งคุณ
สามารถวางโค้ดเพื่ออัปเดตวิดเจ็ต อย่างไรก็ตาม ลองพิจารณาอีกทางเลือกสำหรับ
ข้อมูลอัปเดตจาก Broadcast Receiver ที่อธิบายไว้ใน
ต่อไปนี้ ถ้าวิดเจ็ตของคุณจำเป็นต้องโหลดข้อมูลไม่พร้อมกันหรือใช้เวลามากกว่า
มากกว่า 10 วินาที เพราะหลังจากผ่านไป 10 วินาที ระบบจะพิจารณาว่า
BroadcastReceiver
ไม่ตอบสนอง
updatePeriodMillis
ไม่รองรับค่าที่น้อยกว่า 30 นาที อย่างไรก็ตาม หาก
คุณต้องการปิดการอัปเดตเป็นระยะ ก็ระบุค่า 0 ได้
คุณอนุญาตให้ผู้ใช้ปรับความถี่ในการอัปเดตในการกำหนดค่าได้ สำหรับ
เช่น พวกเขาอาจต้องการให้แถบราคาหุ้นอัปเดตทุก 15 นาที หรือแค่ 4 ครั้ง
ครั้งต่อวัน ในกรณีนี้ ให้ตั้งค่า updatePeriodMillis
เป็น 0 แล้วใช้
WorkManager
แทน
อัปเดตตามการโต้ตอบของผู้ใช้
วิธีที่แนะนำในการอัปเดตวิดเจ็ตตามการโต้ตอบของผู้ใช้มีดังนี้
จากกิจกรรมของแอป: โทรโดยตรง
AppWidgetManager.updateAppWidget
เพื่อตอบกลับการโต้ตอบของผู้ใช้ เช่น เมื่อผู้ใช้แตะจากการโต้ตอบระยะไกล เช่น การแจ้งเตือนหรือวิดเจ็ตแอป สร้าง
PendingIntent
จากนั้นอัปเดตวิดเจ็ตจากที่เรียกActivity
,Broadcast
หรือService
คุณเลือกลำดับความสำคัญของตัวเองได้ สำหรับ เช่น หากคุณเลือกBroadcast
สำหรับPendingIntent
คุณสามารถเลือก การประกาศเบื้องหน้าเพื่อมอบ ลำดับความสำคัญBroadcastReceiver
อัปเดตตามเหตุการณ์ที่ออกอากาศ
ตัวอย่างของรายการออกอากาศที่ต้องมีวิดเจ็ตเพื่ออัปเดต ผู้ใช้ถ่ายภาพ ในกรณีนี้ คุณต้องการอัปเดตวิดเจ็ตเมื่อมีรูปภาพใหม่ ตรวจพบ
คุณสามารถกำหนดเวลางานกับ JobScheduler
และระบุการประกาศเป็น
โดยใช้เมธอด
JobInfo.Builder.addTriggerContentUri
คุณยังลงทะเบียน BroadcastReceiver
สำหรับการออกอากาศได้ด้วย ตัวอย่างเช่น
กำลังฟัง
ACTION_LOCALE_CHANGED
อย่างไรก็ตาม เนื่องจากการดำเนินการนี้ใช้ทรัพยากรของอุปกรณ์มาก โปรดใช้ความระมัดระวังและรอฟัง
ไปยังการออกอากาศที่เฉพาะเจาะจงเท่านั้น ด้วยการเริ่มใช้ broadcast
ข้อจำกัดใน Android
7.0 (API ระดับ 24) และ Android 8.0 (API ระดับ 26) แอปไม่สามารถลงทะเบียนโดยนัยได้
ในไฟล์ Manifest ของ Google
ข้อยกเว้น
ข้อควรพิจารณาเมื่ออัปเดตวิดเจ็ตจาก BroadcastReceiver
หากมีการอัปเดตวิดเจ็ตจาก BroadcastReceiver
ซึ่งรวมถึง
AppWidgetProvider
โปรดคำนึงถึงข้อควรพิจารณาต่อไปนี้เกี่ยวกับ
ระยะเวลาและลำดับความสำคัญของการอัปเดตวิดเจ็ต
ระยะเวลาการอัปเดต
ตามกฎแล้ว ระบบจะอนุญาตให้รับออกอากาศ ซึ่งปกติแล้วจะทำงานในแอป เทรดหลัก ให้ทํางานไม่เกิน 10 วินาทีก่อนที่จะพิจารณาว่าเทรดนั้นไม่ตอบสนองและ การทริกเกอร์ Application Not ข้อผิดพลาดในการตอบกลับ (ANR) หากใช้เวลานานกว่า อัปเดตวิดเจ็ต โปรดพิจารณาทางเลือกต่อไปนี้
กำหนดเวลางานโดยใช้
WorkManager
ให้เวลาผู้รับมากขึ้นด้วย
goAsync
ซึ่งช่วยให้ตัวรับทำงานเป็นเวลา 30 วินาที
โปรดดูข้อควรพิจารณาด้านความปลอดภัยและข้อแนะนำ แนวทางปฏิบัติเพิ่มเติม
ลำดับความสำคัญของการอัปเดต
โดยค่าเริ่มต้น การออกอากาศ ซึ่งรวมถึงการออกอากาศโดยใช้
AppWidgetProvider.onUpdate
ทำงานเป็นกระบวนการเบื้องหลัง ซึ่งหมายความว่า
ทรัพยากรระบบมากเกินไปอาจทำให้เกิดความล่าช้าในการเรียกใช้การออกอากาศ
รีซีฟเวอร์ หากต้องการจัดลำดับความสำคัญของการออกอากาศ ให้ตั้งค่าเป็นกระบวนการที่อยู่เบื้องหน้า
ตัวอย่างเช่น เพิ่มส่วน
Intent.FLAG_RECEIVER_FOREGROUND
แจ้งไปยัง Intent
ที่ส่งไปยัง PendingIntent.getBroadcast
เมื่อผู้ใช้
แตะส่วนใดส่วนหนึ่งของวิดเจ็ต
สร้างตัวอย่างที่ถูกต้องซึ่งมีรายการแบบไดนามิก
ส่วนนี้อธิบายวิธีที่แนะนำในการแสดงหลายรายการใน
ตัวอย่างวิดเจ็ตสำหรับวิดเจ็ตที่มี คอลเล็กชัน
มุมมอง ซึ่งก็คือวิดเจ็ตที่ใช้องค์ประกอบ
ListView
, GridView
หรือ StackView
หากวิดเจ็ตของคุณใช้มุมมองเหล่านี้ จะเป็นการสร้างหน้าตัวอย่างที่รองรับการปรับขนาดโดยตรง การให้วิดเจ็ตจริง เลย์เอาต์จะทำให้ฟังก์ชัน เมื่อการแสดงตัวอย่างวิดเจ็ตไม่แสดงรายการใดๆ ซึ่งเกิดขึ้นเนื่องจาก ข้อมูลพร็อพเพอร์ตี้สำหรับคอลเล็กชันมีการตั้งค่าแบบไดนามิกที่รันไทม์ และมีลักษณะคล้ายกับ ที่แสดงในรูปที่ 1
หากต้องการให้ตัวอย่างของวิดเจ็ตที่มีมุมมองคอลเล็กชันแสดงอย่างถูกต้องในวิดเจ็ต
เราขอแนะนำให้เก็บไฟล์เลย์เอาต์แยกต่างหากซึ่งกำหนดให้เฉพาะสำหรับ
เวอร์ชันตัวอย่าง ไฟล์เลย์เอาต์ที่แยกต่างหากนี้ประกอบด้วยเลย์เอาต์วิดเจ็ตและ
มุมมองคอลเล็กชันตัวยึดตำแหน่งที่มีรายการปลอม เช่น คุณสามารถเลียนแบบ
ListView
โดยการระบุตัวยึดตำแหน่ง LinearLayout
ที่มีลิสต์ปลอมหลายรายการ
รายการ
หากต้องการให้แสดงตัวอย่างสำหรับ ListView
ให้เริ่มต้นด้วยไฟล์เลย์เอาต์แยกต่างหาก ดังนี้
// res/layout/widget_preview.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/widget_background"
android:orientation="vertical">
// Include the actual widget layout that contains ListView.
<include
layout="@layout/widget_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
// The number of fake items you include depends on the values you provide
// for minHeight or targetCellHeight in the AppWidgetProviderInfo
// definition.
<TextView android:text="@string/fake_item1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="?attr/appWidgetInternalPadding" />
<TextView android:text="@string/fake_item2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="?attr/appWidgetInternalPadding" />
</LinearLayout>
ระบุไฟล์เลย์เอาต์ตัวอย่างเมื่อระบุแอตทริบิวต์ previewLayout
ของ
ข้อมูลเมตาของ AppWidgetProviderInfo
คุณยังคงระบุการออกแบบวิดเจ็ตจริง
สำหรับแอตทริบิวต์ initialLayout
และใช้เลย์เอาต์วิดเจ็ตจริงเมื่อ
การสร้าง RemoteViews
ขณะรันไทม์
<appwidget-provider
previewLayout="@layout/widget_previe"
initialLayout="@layout/widget_view" />
รายการที่ซับซ้อน
ตัวอย่างในส่วนก่อนหน้านี้มีรายการปลอมเนื่องจากรายการ
รายการคือออบเจ็กต์ TextView
รายการ สามารถทำได้
มีความซับซ้อนมากขึ้นในการจัดหาสินค้าปลอม หากสินค้าดังกล่าวมีรูปแบบที่ซับซ้อน
พิจารณารายการที่กำหนดไว้ใน widget_list_item.xml
และประกอบด้วย
ออบเจ็กต์ TextView
2 รายการ:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="@id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/fake_title" />
<TextView android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/fake_content" />
</LinearLayout>
ในการจัดทำรายการปลอม คุณสามารถใส่การจัดวางได้หลายครั้ง แต่ จะทำให้แต่ละรายการเหมือนกัน หากต้องการระบุรายการที่ไม่ซ้ำกัน ให้ทำตาม ขั้นตอนเหล่านี้:
สร้างชุดแอตทริบิวต์สำหรับค่าข้อความ
<resources> <attr name="widgetTitle" format="string" /> <attr name="widgetContent" format="string" /> </resources>
ใช้แอตทริบิวต์เหล่านี้เพื่อตั้งค่าข้อความ
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="?widgetTitle" /> <TextView android:id="@id/content" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="?widgetContent" /> </LinearLayout>
สร้างสไตล์ได้มากเท่าที่จำเป็นสำหรับการแสดงตัวอย่าง กําหนดค่าใหม่ใน แต่ละสไตล์:
<resources> <style name="Theme.Widget.ListItem"> <item name="widgetTitle"></item> <item name="widgetContent"></item> </style> <style name="Theme.Widget.ListItem.Preview1"> <item name="widgetTitle">Fake Title 1</item> <item name="widgetContent">Fake content 1</item> </style> <style name="Theme.Widget.ListItem.Preview2"> <item name="widgetTitle">Fake title 2</item> <item name="widgetContent">Fake content 2</item> </style> </resources>
นำสไตล์ไปใช้กับสินค้าปลอมในเลย์เอาต์ตัวอย่าง
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" ...> <include layout="@layout/widget_view" ... /> <include layout="@layout/widget_list_item" android:theme="@style/Theme.Widget.ListItem.Preview1" /> <include layout="@layout/widget_list_item" android:theme="@style/Theme.Widget.ListItem.Preview2" /> </LinearLayout>