Bu sayfada, daha iyi bir kullanıcı deneyimi için daha gelişmiş bir widget oluşturmayla ilgili önerilen uygulamalar açıklanmaktadır.
Widget içeriğini güncellemek için optimizasyonlar
Widget içeriğini güncellemek işlem yükü açısından pahalı olabilir. Pil tüketiminden tasarruf etmek için güncelleme türünü, sıklığını ve zamanlamayı optimize edin.
Widget güncellemesi türleri
Widget'ları güncellemenin üç yolu vardır: tam güncelleme, kısmi güncelleme ve koleksiyon widget'ı kullanılıyorsa veri yenileme. Her birinin hesaplama maliyetleri ve sonuçları farklıdır.
Aşağıda, her güncelleme türü açıklanmakta ve her biri için kod snippet'leri sunulmaktadır.
Tam güncelleme: Widget'ı tam olarak güncellemek için
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)
numaralı telefonu arayın. Bu işlem, daha önce sağlananRemoteViews
değerini yeni birRemoteViews
ile değiştirir. Bu, işlem açısından en pahalı güncellemedir.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);
Kısmi güncelleme: Widget'ın bazı bölümlerini güncellemek için
AppWidgetManager.partiallyUpdateAppWidget
numaralı telefonu arayın. Bu işlem, yeniRemoteViews
öğesini daha önce sağlananRemoteViews
ile birleştirir. Bir widgetupdateAppWidget(int[], RemoteViews)
aracılığıyla en az bir tam güncelleme almıyorsa bu yöntem yoksayılır.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);
Koleksiyon verilerini yenileme: Widget'ınızdaki bir koleksiyon görünümünün verilerini geçersiz kılmak için
AppWidgetManager.notifyAppWidgetViewDataChanged
çağrısı yapın. Bu,RemoteViewsFactory.onDataSetChanged
öğesini tetikler. Bu sırada widget'ta eski veriler gösterilir. Bu yöntemle pahalı görevleri eş zamanlı olarak güvenli bir şekilde gerçekleştirebilirsiniz.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);
Uygulama, karşılık gelen AppWidgetProvider
sınıfıyla aynı UID'ye sahip olduğu sürece bu yöntemleri uygulamanızın herhangi bir yerinde çağırabilirsiniz.
Bir widget'ın ne sıklıkta güncelleneceğini belirleme
Widget'lar, updatePeriodMillis
özelliği için sağlanan değere bağlı olarak düzenli olarak güncellenir. Widget; kullanıcı etkileşimine, yayın güncellemelerine veya her ikisine göre güncellenebilir.
Düzenli aralıklarla güncelleme
appwidget-provider
XML'de AppWidgetProviderInfo.updatePeriodMillis
için bir değer belirterek periyodik güncellemenin sıklığını kontrol edebilirsiniz. Her güncelleme, AppWidgetProvider.onUpdate()
yöntemini tetikler. Bu yöntemde widget'ı güncellemek için kodu yerleştirebilirsiniz. Bununla birlikte, widget'ınızın verileri eşzamansız olarak yüklemesi gerekiyorsa veya
güncellenmesi 10 saniyeden uzun sürüyorsa bir sonraki bölümde
açıklanan yayın alıcı güncellemeleri için alternatifleri
göz önünde bulundurun. Bunun nedeni, 10 saniyeden sonra sistem
BroadcastReceiver
öğesinin yanıt vermediğini kabul etmesidir.
updatePeriodMillis
, 30 dakikadan kısa değerleri desteklemiyor. Ancak düzenli güncellemeleri devre dışı bırakmak isterseniz 0 değerini belirtebilirsiniz.
Kullanıcıların bir yapılandırmada güncellemelerin sıklığını ayarlamasına izin verebilirsiniz. Örneğin, bir hisse senedi takip cihazının 15 dakikada bir veya günde yalnızca dört kez güncellenmesini isteyebilir. Bu durumda, updatePeriodMillis
değerini 0 olarak ayarlayın ve bunun yerine WorkManager
kullanın.
Kullanıcı etkileşimine yanıt olarak güncelleme
Widget'ı kullanıcı etkileşimine göre güncellemek için önerilen yöntemlerden bazıları şunlardır:
Uygulamanın bir etkinliğinden: Kullanıcının dokunması gibi bir kullanıcı etkileşimine yanıt olarak doğrudan
AppWidgetManager.updateAppWidget
numarasını arayın.Bildirim veya uygulama widget'ı gibi uzaktan etkileşimlerden: Bir
PendingIntent
oluşturun, ardından widget'ı çağrılanActivity
,Broadcast
veyaService
işlevlerinden güncelleyin. Kendi önceliğinizi seçebilirsiniz. Örneğin,PendingIntent
için birBroadcast
seçersenizBroadcastReceiver
önceliğine vermek üzere bir ön plan yayını seçebilirsiniz.
Yayın etkinliğine yanıt olarak güncelleme
Widget'ın güncellenmesini gerektiren yayın etkinliklerine örnek olarak, kullanıcının fotoğraf çekmesi verilebilir. Bu durumda, yeni bir fotoğraf algılandığında widget'ı güncellemek istersiniz.
JobScheduler
ile bir iş planlayabilir ve JobInfo.Builder.addTriggerContentUri
yöntemini kullanarak tetikleyici olarak bir yayın belirtebilirsiniz.
Ayrıca yayın için bir BroadcastReceiver
kaydedebilirsiniz (örneğin, ACTION_LOCALE_CHANGED
dinlerken).
Ancak bu işlem cihaz kaynaklarını tükettiği için bunu yaparken dikkatli olun ve yalnızca ilgili yayını dinleyin. Android 7.0 (API düzeyi 24) ve Android 8.0'a (API düzeyi 26) eklenen yayın sınırlamaları sayesinde uygulamalar, belirli istisnalar dışında örtülü yayınları manifestlerinde kaydedemez.
BroadcastRecipientr'dan widget güncellerken dikkat edilmesi gereken noktalar
Widget, AppWidgetProvider
dahil olmak üzere bir BroadcastReceiver
üzerinden güncellenirse widget güncellemesinin süresi ve önceliğiyle ilgili aşağıdaki noktalara dikkat edin.
Güncelleme süresi
Sistem, kural olarak genellikle uygulamanın ana iş parçacığında çalışan yayın alıcılarının yanıt vermiyor olarak kabul edilip Uygulama Yanıt Vermiyor (ANR) hatasını tetiklemeden önce 10 saniyeye kadar çalışmasına izin verir. Widget'ın güncellenmesi daha uzun sürerse aşağıdaki alternatifleri değerlendirin:
WorkManager
kullanarak görev planlayın.goAsync
yöntemini kullanarak alıcıya daha fazla zaman tanıyın. Bu, alıcıların 30 saniye boyunca yürütmesini sağlar.
Daha fazla bilgi için Güvenlikle ilgili olarak göz önünde bulundurulması gereken noktalar ve en iyi uygulamalar bölümüne bakın.
Güncellemenin önceliği
Varsayılan olarak, AppWidgetProvider.onUpdate
kullanılarak yapılan yayınlar da dahil olmak üzere yayınlar arka plan işlemleri olarak çalışır. Bu, aşırı yüklenen sistem kaynaklarının yayın alıcısının çağrılmasında gecikmeye neden olabileceği anlamına gelir. Yayına öncelik vermek için yayını ön plan işlemi yapın.
Örneğin, kullanıcı widget'ın belirli bir bölümüne dokunduğunda PendingIntent.getBroadcast
öğesine iletilen Intent
öğesine Intent.FLAG_RECEIVER_FOREGROUND
işaretini ekleyin.
Dinamik öğeler içeren doğru önizlemeler oluşturun
Bu bölümde, koleksiyon görünümüne sahip bir widget'a (ListView
, GridView
veya StackView
kullanan bir widget) ilişkin widget önizlemesinde birden fazla öğe görüntülemek için önerilen yaklaşım açıklanmaktadır.
Widget'ınız bu görünümlerden birini kullanıyorsa gerçek widget düzenini doğrudan sağlayarak ölçeklenebilir bir önizleme oluşturmak, widget önizlemesi hiçbir öğe görüntülemediğinde deneyimi olumsuz etkiler. Bu durum, koleksiyon görünümü verilerinin çalışma zamanında dinamik olarak ayarlanması ve Şekil 1'de gösterilen resme benzemesinden kaynaklanır.
Koleksiyon görünümlerine sahip widget'ların önizlemelerinin, widget seçicide düzgün bir şekilde görüntülenmesini sağlamak için yalnızca önizleme için atanmış ayrı bir düzen dosyası tutmanızı öneririz. Bu ayrı düzen dosyası, gerçek widget düzenini ve sahte öğelerin bulunduğu bir yer tutucu koleksiyon görünümünü içerir. Örneğin, çeşitli sahte liste öğeleri içeren bir LinearLayout
yer tutucusu sağlayarak ListView
öğesini taklit edebilirsiniz.
ListView
örneğini göstermek için ayrı bir düzen dosyasıyla başlayın:
// 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>
AppWidgetProviderInfo
meta verilerinin previewLayout
özelliğini sağlarken önizleme düzeni dosyasını belirtin. Yine de initialLayout
özelliği için gerçek widget düzenini belirtir ve çalışma zamanında bir RemoteViews
oluştururken gerçek widget düzenini kullanırsınız.
<appwidget-provider
previewLayout="@layout/widget_previe"
initialLayout="@layout/widget_view" />
Karmaşık liste öğeleri
Önceki bölümdeki örnekte, liste öğeleri TextView
nesneleri olduğu için sahte liste öğeleri sağlanmaktadır. Öğeler karmaşık düzenlerse sahte öğelerin sağlanması daha karmaşık olabilir.
widget_list_item.xml
içinde tanımlanmış ve iki TextView
nesneden oluşan bir liste öğesini ele alalım:
<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>
Sahte liste öğeleri sağlamak için düzeni birden çok kez ekleyebilirsiniz, ancak bu durum her liste öğesinin aynı olmasına neden olur. Benzersiz liste öğeleri sağlamak için şu adımları izleyin:
Metin değerleri için bir özellik grubu oluşturun:
<resources> <attr name="widgetTitle" format="string" /> <attr name="widgetContent" format="string" /> </resources>
Metni ayarlamak için şu özellikleri kullanın:
<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>
Önizleme için gereken sayıda stil oluşturun. Her stildeki değerleri yeniden tanımlayın:
<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>
Önizleme düzenindeki sahte öğelere stil uygulayın:
<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>