สร้างวิดเจ็ตขั้นสูง

ลองใช้วิธีแบบ Compose
Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนำสำหรับ Android ดูวิธีสร้างวิดเจ็ตโดยใช้ API สไตล์ Compose

หน้านี้อธิบายแนวทางปฏิบัติแนะนำสำหรับการสร้างวิดเจ็ตขั้นสูงขึ้นเพื่อประสบการณ์ของผู้ใช้ที่ดียิ่งขึ้น

การเพิ่มประสิทธิภาพสำหรับการอัปเดตเนื้อหาวิดเจ็ต

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

ประเภทการอัปเดตวิดเจ็ต

การอัปเดตวิดเจ็ตทำได้ 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 เพื่อล้างข้อมูลของ Collection View ในวิดเจ็ต ซึ่งจะทริกเกอร์ 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 มีลำดับความสำคัญ

อัปเดตเพื่อตอบสนองต่อเหตุการณ์การออกอากาศ

ตัวอย่างเหตุการณ์การออกอากาศที่ต้องให้อัปเดตวิดเจ็ตคือเมื่อผู้ใช้ถ่ายรูป ในกรณีนี้ คุณต้องการอัปเดตวิดเจ็ตเมื่อตรวจพบรูปภาพใหม่

คุณสามารถกำหนดเวลา Task ด้วย JobScheduler และระบุการออกอากาศเป็น ทริกเกอร์โดยใช้ JobInfo.Builder.addTriggerContentUri เมธอด

นอกจากนี้ คุณยังลงทะเบียน BroadcastReceiver สำหรับการออกอากาศได้ด้วย เช่น การฟัง ACTION_LOCALE_CHANGED อย่างไรก็ตาม เนื่องจากวิธีนี้ใช้ทรัพยากรของอุปกรณ์ จึงควรใช้อย่างระมัดระวังและฟังเฉพาะการออกอากาศที่เฉพาะเจาะจง เมื่อมีการเปิดตัวข้อจำกัดการออกอากาศใน Android 7.0 (ระดับ API 24) และ Android 8.0 (ระดับ API 26) แอปต่างๆ จะลงทะเบียนการออกอากาศโดยนัย ในไฟล์ Manifest ไม่ได้ ยกเว้นบาง กรณี

ข้อควรพิจารณาเมื่ออัปเดตวิดเจ็ตจาก BroadcastReceiver

หากอัปเดตวิดเจ็ตจาก BroadcastReceiver รวมถึง AppWidgetProvider โปรดทราบข้อควรพิจารณาต่อไปนี้เกี่ยวกับระยะเวลาและลำดับความสำคัญของการอัปเดตวิดเจ็ต

ระยะเวลาการอัปเดต

โดยปกติแล้ว ระบบจะอนุญาตให้ Broadcast Receiver ซึ่งมักจะทำงานใน Main Thread ของแอป ทำงานได้นานสูงสุด 10 วินาทีก่อนที่จะถือว่าไม่ตอบสนองและทริกเกอร์ข้อผิดพลาด Application Not Responding (ANR) หากต้องการหลีกเลี่ยงการบล็อก Main Thread ขณะจัดการการออกอากาศ ให้ใช้เมธอด goAsync หากการอัปเดตวิดเจ็ตใช้เวลานานกว่านั้น ให้พิจารณากำหนดเวลา Task โดยใช้ WorkManager

Caution: Any work you do here blocks further broadcasts until it completes,
so it can slow the receiving of later events.

ดูข้อมูลเพิ่มเติมได้ที่ข้อควรพิจารณาและแนวทางปฏิบัติแนะนำด้านความปลอดภัย

ลำดับความสำคัญของการอัปเดต

โดยค่าเริ่มต้น การออกอากาศ รวมถึงการออกอากาศที่ทำโดยใช้ AppWidgetProvider.onUpdate จะทำงานเป็นกระบวนการเบื้องหลัง ซึ่งหมายความว่าทรัพยากรระบบที่โหลดมากเกินไปอาจทำให้การเรียกใช้ Broadcast Receiver ล่าช้า หากต้องการจัดลำดับความสำคัญของการออกอากาศ ให้เปลี่ยนให้เป็นการออกอากาศเบื้องหน้า

ตัวอย่างเช่น ให้เพิ่มแฟล็ก Intent.FLAG_RECEIVER_FOREGROUND ลงใน Intent ที่ส่งไปยัง PendingIntent.getBroadcast เมื่อผู้ใช้ แตะส่วนใดส่วนหนึ่งของวิดเจ็ต