Membuat widget lanjutan

Mencoba cara Compose
Jetpack Compose adalah toolkit UI yang direkomendasikan untuk Android. Pelajari cara membuat widget menggunakan API gaya Compose.

Halaman ini menjelaskan praktik yang direkomendasikan untuk membuat widget yang lebih canggih demi pengalaman pengguna yang lebih baik.

Pengoptimalan untuk memperbarui konten widget

Memperbarui konten widget dapat memerlukan banyak komputasi. Untuk menghemat konsumsi baterai, optimalkan jenis, frekuensi, dan waktu pembaruan.

Jenis pembaruan widget

Ada tiga cara untuk memperbarui widget: pembaruan penuh, pembaruan sebagian, dan, dalam kasus widget koleksi, refresh data. Setiap cara memiliki biaya komputasi dan konsekuensi yang berbeda.

Berikut ini penjelasan tentang setiap jenis pembaruan dan cuplikan kode untuk setiap jenis.

  • Pembaruan penuh: panggil AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) untuk memperbarui widget sepenuhnya. Tindakan ini akan mengganti yang sebelumnya diberikan RemoteViews dengan yang baru RemoteViews. Ini adalah pembaruan yang paling mahal secara komputasi.

    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);
  • Pembaruan sebagian: panggil AppWidgetManager.partiallyUpdateAppWidget untuk memperbarui bagian widget. Tindakan ini akan menggabungkan RemoteViews baru dengan RemoteViews yang sebelumnya diberikan. Metode ini diabaikan jika widget tidak menerima setidaknya satu pembaruan penuh melalui 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);
  • Refresh data koleksi: panggil AppWidgetManager.notifyAppWidgetViewDataChanged untuk membatalkan data tampilan koleksi di widget Anda. Tindakan ini akan memicu RemoteViewsFactory.onDataSetChanged. Sementara itu, data lama akan ditampilkan di widget. Anda dapat melakukan tugas yang mahal secara komputasi dengan aman secara sinkron menggunakan metode ini.

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

Anda dapat memanggil metode ini dari mana saja di aplikasi, selama aplikasi memiliki UID yang sama dengan class yang sesuai AppWidgetProvider.

Menentukan frekuensi pembaruan widget

Widget diperbarui secara berkala, bergantung pada nilai yang diberikan untuk atribut updatePeriodMillis. Widget dapat diperbarui sebagai respons terhadap interaksi pengguna, pembaruan siaran, atau keduanya.

Memperbarui secara berkala

Anda dapat mengontrol frekuensi pembaruan berkala dengan menentukan nilai untuk AppWidgetProviderInfo.updatePeriodMillis di XML appwidget-provider. Setiap pembaruan akan memicu metode AppWidgetProvider.onUpdate(), tempat Anda dapat menempatkan kode untuk memperbarui widget. Namun, pertimbangkan alternatif untuk pembaruan penerima siaran yang dijelaskan di bagian berikut jika widget Anda perlu memuat data secara asinkron atau memerlukan waktu lebih dari 10 detik untuk diperbarui, karena setelah 10 detik, sistem akan menganggap BroadcastReceiver tidak responsif.

updatePeriodMillis tidak mendukung nilai kurang dari 30 menit. Namun, jika ingin menonaktifkan pembaruan berkala, Anda dapat menentukan 0.

Anda dapat mengizinkan pengguna menyesuaikan frekuensi pembaruan dalam konfigurasi. Misalnya, mereka mungkin ingin simbol saham diperbarui setiap 15 menit atau hanya empat kali sehari. Dalam hal ini, tetapkan updatePeriodMillis ke 0 dan gunakan WorkManager sebagai gantinya.

Memperbarui sebagai respons terhadap interaksi pengguna

Berikut beberapa cara yang direkomendasikan untuk memperbarui widget berdasarkan interaksi pengguna:

  • Dari aktivitas aplikasi: panggil AppWidgetManager.updateAppWidget secara langsung sebagai respons terhadap interaksi pengguna, seperti ketukan pengguna.

  • Dari interaksi jarak jauh, seperti notifikasi atau widget aplikasi: buat PendingIntent, lalu perbarui widget dari Activity, Broadcast, atau Service yang dipanggil. Anda dapat memilih prioritas sendiri. Misalnya, jika memilih Broadcast untuk PendingIntent, Anda dapat memilih siaran latar depan untuk memberikan BroadcastReceiver prioritas.

Memperbarui sebagai respons terhadap peristiwa siaran

Contoh peristiwa siaran yang mengharuskan widget diperbarui adalah saat pengguna mengambil foto. Dalam hal ini, Anda ingin memperbarui widget saat foto baru terdeteksi.

Anda dapat menjadwalkan tugas dengan JobScheduler dan menentukan siaran sebagai pemicu menggunakan JobInfo.Builder.addTriggerContentUri metode.

Anda juga dapat mendaftarkan BroadcastReceiver untuk siaran—misalnya, mendengarkan ACTION_LOCALE_CHANGED. Namun, karena hal ini menggunakan resource perangkat, gunakan dengan hati-hati dan hanya dengarkan siaran tertentu. Dengan diperkenalkannya siaran batasan di Android 7.0 (API level 24) dan Android 8.0 (API level 26), aplikasi tidak dapat mendaftarkan siaran implisit dalam manifesnya, dengan pengecualian tertentu.

Pertimbangan saat memperbarui widget dari BroadcastReceiver

Jika widget diperbarui dari BroadcastReceiver, termasuk AppWidgetProvider, perhatikan pertimbangan berikut terkait durasi dan prioritas pembaruan widget.

Durasi pembaruan

Sebagai aturan, sistem memungkinkan penerima siaran, yang biasanya berjalan di thread utama aplikasi, berjalan hingga 10 detik sebelum dianggap tidak responsif dan memicu error Aplikasi Tidak Merespons (ANR). Untuk menghindari pemblokiran the main thread saat menangani siaran, gunakan the goAsync method. Jika memerlukan waktu lebih lama untuk memperbarui widget, pertimbangkan untuk menjadwalkan tugas menggunakan WorkManager.

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

Lihat Pertimbangan keamanan dan praktik terbaik untuk mengetahui informasi selengkapnya.

Prioritas pembaruan

Secara default, siaran—termasuk yang dibuat menggunakan AppWidgetProvider.onUpdate—berjalan sebagai proses latar belakang. Artinya, resource sistem yang kelebihan beban dapat menyebabkan penundaan dalam pemanggilan penerima siaran. Untuk memprioritaskan siaran, jadikan siaran sebagai proses latar depan.

Misalnya, tambahkan flag Intent.FLAG_RECEIVER_FOREGROUND ke Intent yang diteruskan ke PendingIntent.getBroadcast saat pengguna mengetuk bagian tertentu dari widget.