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üncellemeyle ilgili optimizasyonlar
Widget içeriğini güncellemek bilgi işlem açısından pahalı olabilir. Pil tüketimini azaltmak için güncelleme türünü, sıklığını ve zamanlamasını optimize edin.
Widget güncelleme türleri
Widget'ları üç şekilde güncelleyebilirsiniz: tam güncelleme, kısmi güncelleme ve koleksiyon widget'ı durumunda veri yenileme. Her birinin farklı hesaplama maliyetleri ve sonuçları vardır.
Aşağıda her güncelleme türü açıklanmakta ve her biri için kod snippet'leri sağlanmaktadır.
Tam güncelleme: Widget'ı tamamen güncellemek için
AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews)
işlevini çağırın. Bu işlem, daha önce sağlananRemoteViews
değerini yeni birRemoteViews
değeriyle değiştirir. Bu, en pahalı hesaplama işlemi gerektiren 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 bölümlerini güncellemek için
AppWidgetManager.partiallyUpdateAppWidget
işlevini çağırın. Bu işlem, yeniRemoteViews
ile daha önce sağlananRemoteViews
'ü birleştirir. Bir widgetupdateAppWidget(int[], RemoteViews)
üzerinden en az bir tam güncelleme almazsa bu yöntem yok sayı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
işlevini çağırın. Bu işlem,RemoteViewsFactory.onDataSetChanged
tetikleyicisini etkinleştirir. Bu süre zarfında widget'ta eski veriler gösterilir. Bu yöntemle pahalı görevleri senkronize bir şekilde 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, ilgili AppWidgetProvider
sınıfıyla aynı UID'ye sahip olduğu sürece bu yöntemleri uygulamanızın herhangi bir yerinden çağırabilirsiniz.
Widget'ları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 aralıklarla güncellenir. Widget, kullanıcı etkileşimine yanıt olarak güncellenebilir, güncelleme yayınlayabilir veya her ikisini de yapabilir.
Düzenli olarak güncelleme
appwidget-provider
XML dosyasında AppWidgetProviderInfo.updatePeriodMillis
için bir değer belirterek düzenli güncellemenin sıklığını kontrol edebilirsiniz. Her güncelleme, widget'ı güncellemek için kodu yerleştirebileceğiniz AppWidgetProvider.onUpdate()
yöntemini tetikler. Ancak widget'ınızın verileri eşzamansız olarak yüklemesi gerekiyorsa veya güncellemesinin 10 saniyeden uzun sürmesi gerekiyorsa aşağıdaki bölümde açıklanan yayın alıcı güncellemeleri için alternatifleri göz önünde bulundurun. Çünkü sistem, 10 saniye sonra BroadcastReceiver
'yi yanıt vermiyor olarak kabul eder.
updatePeriodMillis
, 30 dakikadan kısa değerleri desteklemez. Ancak, düzenli güncellemeleri devre dışı bırakmak isterseniz 0 değerini belirtebilirsiniz.
Kullanıcıların bir yapılandırmadaki güncelleme sıklığını ayarlamalarına izin verebilirsiniz. Örneğin, bir hisse senedi akışının 15 dakikada bir veya yalnızca günde dört kez güncellenmesini isteyebilirler. 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üncellemenin önerilen bazı yolları ş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
çağrılır.Bildirim veya uygulama widget'ı gibi uzaktan etkileşimlerden:
PendingIntent
oluşturun, ardından çağrılanActivity
,Broadcast
veyaService
öğesinden widget'ı güncelleyin. Kendi önceliğinizi seçebilirsiniz. Örneğin,PendingIntent
için birBroadcast
seçersenizBroadcastReceiver
'e öncelik vermek üzere bir ön plan yayını seçebilirsiniz.
Yayın etkinliğine yanıt olarak güncelleme
Widget'ın güncellenmesini gerektiren bir yayın etkinliği örneği, kullanıcının fotoğraf çekmesidir. Bu durumda, yeni bir fotoğraf algılandığında widget'ı güncellemek istiyorsunuz.
JobScheduler
ile bir iş planlayabilir ve JobInfo.Builder.addTriggerContentUri
yöntemini kullanarak tetikleyici olarak bir yayın belirtebilirsiniz.
Yayın için bir BroadcastReceiver
de kaydedebilirsiniz. Örneğin, ACTION_LOCALE_CHANGED
için dinleme.
Ancak bu işlem cihaz kaynaklarını kullandığından bu özelliği dikkatli bir şekilde kullanın ve yalnızca belirli bir yayını dinleyin. Android 7.0 (API düzeyi 24) ve Android 8.0 (API düzeyi 26) sürümlerinde yayın sınırlamaları kullanıma sunulduğundan, uygulamalar belirli istisnalar dışında, manifest dosyalarında dolaylı yayın kaydedemez.
Bir widget'ı BroadcastReceiver'dan güncellerken dikkat edilmesi gerekenler
Widget, AppWidgetProvider
dahil olmak üzere bir BroadcastReceiver
'ten güncelleniyorsa widget güncellemesinin süresi ve önceliğiyle ilgili aşağıdaki hususları göz önünde bulundurun.
Güncellemenin süresi
Sistem, kural olarak genellikle uygulamanın ana iş akışında çalışan yayın alıcılarının yanıt vermediğini düşünmeden ve Uygulama Yanıt Vermiyor (ANR) hatası tetiklemeden önce 10 saniye boyunca çalışmasını sağlar. Widget'ın güncellenmesi daha uzun sürerse aşağıdaki alternatifleri değerlendirin:
WorkManager
simgesini kullanarak bir görev planlayın.goAsync
yöntemiyle alıcıya daha fazla zaman verin. Bu, alıcılara 30 saniye boyunca yürütme olanağı tanır.
Daha fazla bilgi için Güvenlikle ilgili dikkat edilmesi gereken noktalar ve en iyi uygulamalar başlıklı makaleyi inceleyin.
Güncellemenin önceliği
Varsayılan olarak, AppWidgetProvider.onUpdate
kullanılarak yapılanlar da dahil olmak üzere yayınlar arka plan işlemleri olarak çalışır. Bu, aşırı yüklenmiş 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 Intent
'e iletilen PendingIntent.getBroadcast
'e Intent.FLAG_RECEIVER_FOREGROUND
işaretini ekleyin.
Dinamik öğeler içeren doğru önizlemeler oluşturma
Bu bölümde, koleksiyon görünümü olan bir widget'ın (yani ListView
, GridView
veya StackView
kullanan bir widget'ın) widget önizlemesinde birden fazla öğe göstermek 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 önizlemesinde hiçbir öğe gösterilmediğinde deneyimi olumsuz etkiler. Bunun nedeni, koleksiyon görünümü verilerinin çalışma zamanında dinamik olarak ayarlanmasıdır ve Şekil 1'de gösterilen resme benzer.
Koleksiyon görünümleri içeren widget'ların önizlemelerinin widget seçicide düzgün şekilde gösterilmesi için yalnızca önizleme için ayrılmış ayrı bir düzen dosyası kullanmanızı öneririz. Bu ayrı düzen dosyası, gerçek widget düzenini ve sahte öğeler içeren bir yer tutucu koleksiyon görünümünü içerir. Örneğin, birkaç sahte liste öğesi içeren bir yer tutucu LinearLayout
sağlayarak bir ListView
'ü taklit edebilirsiniz.
ListView
örneğini açıklamak 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. initialLayout
özelliği için gerçek widget düzenini belirtmeye ve çalışma zamanında RemoteViews
oluştururken gerçek widget düzenini kullanmaya devam edersiniz.
<appwidget-provider
previewLayout="@layout/widget_previe"
initialLayout="@layout/widget_view" />
Karmaşık liste öğeleri
Liste öğeleri TextView
nesneleri olduğundan önceki bölümdeki örnekte sahte liste öğeleri sağlanmaktadır. Öğeler karmaşık düzenlerse sahte öğeler sağlamak daha karmaşık olabilir.
widget_list_item.xml
içinde tanımlanan ve iki TextView
nesnesinden oluşan bir liste öğesini düşünü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="@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, her liste öğesinin aynı olmasına neden olur. Benzersiz liste öğeleri sağlamak için aşağıdaki adımları uygulayın:
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 aşağıdaki ö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 stilleri 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>