Gelişmiş widget oluşturma

Bu sayfada, daha iyi bir kullanıcı deneyimi sağlar.

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üncellemesi türleri

Bir widget'ı güncellemenin üç yolu vardır: tam güncelleme, kısmi güncelleme ve ise bir veri yenilemesi olduğunu varsayalım. Her biri farklı ve sonuçları.

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ğlanan RemoteViews değerini yeni bir RemoteViews 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 çağrısı yapın. Bu işlem, yeni RemoteViews ile daha önce sağlanan RemoteViews'ü birleştirir. Bir widget updateAppWidget(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 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);

Uygulamanızın herhangi bir yerindeyken bu yöntemleri çağırabilirsiniz. Önemli olan karşılık gelen ile aynı UID AppWidgetProvider sınıfı.

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

Periyodik güncellemenin sıklığını kontrol etmek için appwidget-provider XML'de AppWidgetProviderInfo.updatePeriodMillis. Her güncelleme, widget'ı güncellemek için kodu yerleştirebileceğiniz AppWidgetProvider.onUpdate() yöntemini tetikler. Ancak, projenizin alternatifleri olan yayın alıcı güncellemelerinin widget'ınızın verileri eşzamansız olarak yüklemesi gerekiyorsa veya daha fazla zaman alıyorsa 10 saniyeden uzun sürmez. Çünkü 10 saniyeden sonra, sistem BroadcastReceiver yanıt vermeyecek.

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ü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 çağrılır.

  • Bildirim veya uygulama widget'ı gibi uzaktan etkileşimlerden: bir PendingIntent oluşturun, ardından çağrılan Activity, Broadcast veya Service. Kendi önceliğinizi seçebilirsiniz. Örneğin, PendingIntent için bir Broadcast seçerseniz BroadcastReceiver'e öncelik vermek üzere bir ön plan yayını seçebilirsiniz.

Yayın etkinliğine yanıt olarak güncelleme

Widget'ın güncellenmesi gereken bir yayın etkinliğine örnek olarak, fotoğraf çektiğini varsayalım. Bu durumda, yeni bir fotoğraf eklendiğinde widget'ı tespit edilir.

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. Yayınların kullanıma sunulmasıyla birlikte sınırlamaları 7.0 (API düzeyi 24) ve Android 8.0 (API düzeyi 26) sürümleriyle uygulamalar örtülü kaydedemez bunların belirli bir kısmı, istisnalar.

Bir widget'ı BroadcastReceiver'dan güncellerken dikkat edilmesi gerekenler

Widget, aşağıdakiler dahil bir BroadcastReceiver üzerinden güncellenirse: AppWidgetProvider, güncellemenin süresini ve önceliğini kontrol edin.

Güncelleme süresi

Kural olarak, sistem genellikle uygulamanın içinde çalışan yayın alıcılarına izin verir. ana iş parçacığının, duyarlı olmadığını ve yanıt vermediğini kabul etmeden önce 10 saniyeye kadar çalıştırın bir Uygulama Değil Yanıt Verme (ANR) hatası. Daha uzun sürerse widget'ı güncelledikten sonra aşağıdaki alternatifleri göz önünde bulundurun:

  • WorkManager kullanarak 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: 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 PendingIntent.getBroadcast'e iletilen Intent'e Intent.FLAG_RECEIVER_FOREGROUND işaretini ekleyin.

Dinamik öğeler içeren doğru önizlemeler oluşturun

Şekil 1: Liste öğesi içermeyen bir widget önizlemesi.

Bu bölümde, aynı reklamda birden fazla öğe görüntülemek için önerilen yaklaşım koleksiyonu olan bir widget'ın widget önizlemesi görünüm: yani bir widget kullanan bir widget ListView, GridView veya StackView.

Widget'ınız bu görünümlerden birini kullanıyorsa doğrudan widget'ın kendisini sunmak düzen, önizlemede hiçbir öğe görüntülenmediğinde yeni bir deneyim yaşayabilirsiniz. Bunun nedeni, koleksiyon görünümü verileri çalışma zamanında dinamik olarak ayarlanır ve bu veriler ilgili resim gösterilmektedir.

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, bir Çok sayıda sahte liste içeren LinearLayout yer tutucusu sağlayarak ListView öğeler.

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ımlanmış ve şunlardan oluşan bir liste öğesini düşünün iki TextView nesnesi var:

<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 fazla kez ekleyebilirsiniz, ancak her liste öğesinin aynı olmasına neden olur. Benzersiz liste öğeleri sağlamak için aşağıdaki adımları uygulayın:

  1. Metin değerleri için bir özellik grubu oluşturun:

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. 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>
    
  3. Ö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>
    
  4. Ö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>