Membuat widget lanjutan

Coba 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 biaya komputasi yang tinggi. Untuk menghemat konsumsi baterai, optimalkan jenis, frekuensi, dan waktu pembaruan.

Jenis update widget

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

Berikut ini menjelaskan setiap jenis pembaruan dan memberikan cuplikan kode untuk setiap jenis.

  • Update penuh: panggil AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) untuk mengupdate widget sepenuhnya. Tindakan ini menggantikan RemoteViews yang sebelumnya diberikan dengan RemoteViews baru. 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);
  • Update sebagian: panggil AppWidgetManager.partiallyUpdateAppWidget untuk memperbarui bagian widget. Tindakan ini menggabungkan RemoteViews baru dengan RemoteViews yang sebelumnya diberikan. Metode ini diabaikan jika widget tidak menerima setidaknya satu update 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);
  • Pembaruan data pengumpulan: panggil AppWidgetManager.notifyAppWidgetViewDataChanged untuk membatalkan validasi data tampilan koleksi di widget Anda. Tindakan ini akan memicu RemoteViewsFactory.onDataSetChanged. Sementara itu, data lama ditampilkan di widget. Anda dapat melakukan tugas berat secara sinkron dengan aman 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, asalkan aplikasi memiliki UID yang sama dengan class AppWidgetProvider yang sesuai.

Menentukan seberapa sering widget diperbarui

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

Update secara berkala

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

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

Anda dapat mengizinkan pengguna menyesuaikan frekuensi update dalam konfigurasi. Misalnya, mereka mungkin ingin mengupdate simbol saham setiap 15 menit atau hanya empat kali dalam satu hari. 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 Anda sendiri. Misalnya, jika Anda memilih Broadcast untuk PendingIntent, Anda dapat memilih siaran latar depan untuk memberikan prioritas BroadcastReceiver.

Memperbarui sebagai respons terhadap peristiwa siaran

Contoh peristiwa siaran yang memerlukan update widget 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 metode JobInfo.Builder.addTriggerContentUri.

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

Pertimbangan saat memperbarui widget dari BroadcastReceiver

Jika widget diupdate dari BroadcastReceiver, termasuk AppWidgetProvider, perhatikan pertimbangan berikut terkait durasi dan prioritas update widget.

Durasi update

Sebagai aturan, sistem memungkinkan penerima siaran, yang biasanya berjalan di thread utama aplikasi, berjalan hingga 10 detik sebelum menganggapnya tidak responsif dan memicu error Aplikasi Tidak Merespons (ANR). Untuk menghindari pemblokiran thread utama saat menangani siaran, gunakan metode goAsync. Jika widget memerlukan waktu lebih lama untuk diperbarui, 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 dan praktik terbaik keamanan untuk mengetahui informasi selengkapnya.

Prioritas update

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 tanda Intent.FLAG_RECEIVER_FOREGROUND ke Intent yang diteruskan ke PendingIntent.getBroadcast saat pengguna mengetuk bagian tertentu dari widget.