ऐडवांस विजेट बनाएं

इस पेज पर, बेहतर उपयोगकर्ता अनुभव के लिए ज़्यादा बेहतर विजेट बनाने के सुझाए गए तरीकों के बारे में बताया गया है.

विजेट के कॉन्टेंट को अपडेट करने के लिए ऑप्टिमाइज़ेशन

विजेट का कॉन्टेंट अपडेट करना, कंप्यूटर की मदद से महंगा हो सकता है. बैटरी की खपत कम करने के लिए, अपडेट टाइप, फ़्रीक्वेंसी, और समय को ऑप्टिमाइज़ करें.

विजेट अपडेट के टाइप

विजेट को अपडेट करने के तीन तरीके हैं: पूरा अपडेट, कुछ हिस्से का अपडेट, और कलेक्शन विजेट के मामले में, डेटा रीफ़्रेश करना. हर मॉडल के लिए, कैलकुलेशन की लागत और नतीजे अलग-अलग होते हैं.

यहां हर तरह के अपडेट के बारे में बताया गया है. साथ ही, हर अपडेट के लिए कोड स्निपेट भी दिए गए हैं.

  • पूरी तरह से अपडेट करना: विजेट को पूरी तरह से अपडेट करने के लिए, AppWidgetManager.updateAppWidget(int, android.widget.RemoteViews) को कॉल करें. यह पहले दिए गए RemoteViews को नए RemoteViews से बदल देता है. यह अपडेट, कैलकुलेशन के हिसाब से सबसे महंगा होता है.

    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);
  • कुछ हिस्सों को अपडेट करना: विजेट के कुछ हिस्सों को अपडेट करने के लिए, AppWidgetManager.partiallyUpdateAppWidget को कॉल करें. इससे, नए RemoteViews को पहले दिए गए RemoteViews के साथ मर्ज कर दिया जाता है. अगर किसी विजेट को 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);
  • कलेक्शन डेटा रीफ़्रेश: अपने विजेट में, कलेक्शन व्यू के डेटा को अमान्य करने के लिए, AppWidgetManager.notifyAppWidgetViewDataChanged को कॉल करें. इससे RemoteViewsFactory.onDataSetChanged ट्रिगर हो जाता है. इस दौरान, विजेट में पुराना डेटा दिखता है. इस तरीके से, महंगे टास्क को एक साथ सुरक्षित तरीके से किया जा सकता है.

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

इन तरीकों को अपने ऐप्लिकेशन में कहीं से भी कॉल किया जा सकता है. हालांकि, इसके लिए ज़रूरी है कि ऐप्लिकेशन में उस AppWidgetProvider क्लास का वही यूआईडी हो जिससे इन तरीकों को कॉल किया जा रहा है.

तय करें कि किसी विजेट को कितनी बार अपडेट करना है

विजेट समय-समय पर अपडेट होते रहते हैं. यह अपडेट, updatePeriodMillis एट्रिब्यूट के लिए दी गई वैल्यू के आधार पर होता है. विजेट, उपयोगकर्ता के इंटरैक्शन, ब्रॉडकास्ट अपडेट या दोनों के जवाब में अपडेट हो सकता है.

समय-समय पर अपडेट करना

appwidget-provider एक्सएमएल में AppWidgetProviderInfo.updatePeriodMillis के लिए कोई वैल्यू तय करके, समय-समय पर होने वाले अपडेट की फ़्रीक्वेंसी को कंट्रोल किया जा सकता है. हर अपडेट, AppWidgetProvider.onUpdate() तरीके को ट्रिगर करता है. यहां कोड डालकर विजेट को अपडेट किया जा सकता है. हालांकि, अगर आपके विजेट को एसिंक्रोनस रूप से डेटा लोड करना है या अपडेट होने में 10 सेकंड से ज़्यादा समय लगता है, तो नीचे दिए गए सेक्शन में बताए गए ब्रॉडकास्ट रिसीवर अपडेट के लिए विकल्पों पर विचार करें. ऐसा इसलिए, क्योंकि 10 सेकंड के बाद, सिस्टम किसी BroadcastReceiver को रिस्पॉन्सिव नहीं मानता.

updatePeriodMillis में 30 मिनट से कम की वैल्यू काम नहीं करती. हालांकि, अगर आपको समय-समय पर होने वाले अपडेट बंद करने हैं, तो 0 डालें.

उपयोगकर्ताओं को कॉन्फ़िगरेशन में, अपडेट की फ़्रीक्वेंसी में बदलाव करने की अनुमति दी जा सकती है. उदाहरण के लिए, शायद वे चाहें कि स्टॉक टिकर हर 15 मिनट में या दिन में सिर्फ़ चार बार अपडेट हो. इस मामले में, updatePeriodMillis को 0 पर सेट करें और इसके बजाय WorkManager का इस्तेमाल करें.

उपयोगकर्ता के इंटरैक्शन के जवाब में अपडेट

उपयोगकर्ता के इंटरैक्शन के आधार पर विजेट को अपडेट करने के लिए, यहां कुछ सुझाए गए तरीके दिए गए हैं:

  • ऐप्लिकेशन की किसी गतिविधि से: उपयोगकर्ता के इंटरैक्शन के जवाब में, AppWidgetManager.updateAppWidget को सीधे तौर पर कॉल करें. जैसे, उपयोगकर्ता के टैप करने पर.

  • सूचना या ऐप्लिकेशन विजेट जैसे रिमोट इंटरैक्शन से: PendingIntent बनाएं. इसके बाद, शुरू किए गए Activity, Broadcast या Service से विजेट को अपडेट करें. अपने हिसाब से प्राथमिकता चुनी जा सकती है. उदाहरण के लिए, अगर आपने PendingIntent के लिए Broadcast चुना है, तो BroadcastReceiver को प्राथमिकता देने के लिए, फ़ोरग्राउंड ब्रॉडकास्ट चुना जा सकता है.

ब्रॉडकास्ट इवेंट के जवाब में अपडेट करना

जब उपयोगकर्ता कोई फ़ोटो लेता है, तो उसे ब्रॉडकास्ट इवेंट के तौर पर सेट किया जा सकता है. इस इवेंट के होने पर, विजेट को अपडेट करना ज़रूरी होता है. इस मामले में, आपको नई फ़ोटो का पता चलने पर विजेट अपडेट करना है.

JobScheduler का इस्तेमाल करके कोई जॉब शेड्यूल किया जा सकता है. साथ ही, JobInfo.Builder.addTriggerContentUri तरीके का इस्तेमाल करके, ट्रिगर के तौर पर ब्रॉडकास्ट तय किया जा सकता है.

ब्रॉडकास्ट के लिए भी BroadcastReceiver रजिस्टर किया जा सकता है. उदाहरण के लिए, ACTION_LOCALE_CHANGED सुनने के लिए. हालांकि, यह डिवाइस के संसाधनों का इस्तेमाल करता है. इसलिए, इसका इस्तेमाल सावधानी से करें और सिर्फ़ उस ब्रॉडकास्ट को सुनें. Android 7.0 (एपीआई लेवल 24) और Android 8.0 (एपीआई लेवल 26) में ब्रॉडकास्ट से जुड़ी पाबंदियां लागू होने के बाद, ऐप्लिकेशन अपने मेनिफ़ेस्ट में, कुछ अपवादों के साथ, इंप्लिसिट ब्रॉडकास्ट रजिस्टर नहीं कर सकते.

BroadcastReceiver से विजेट अपडेट करते समय ध्यान रखने वाली बातें

अगर विजेट को BroadcastReceiver से अपडेट किया जाता है, जिसमें AppWidgetProvider भी शामिल है, तो विजेट के अपडेट होने में लगने वाले समय और प्राथमिकता के बारे में इन बातों का ध्यान रखें.

अपडेट होने में लगने वाला समय

आम तौर पर, सिस्टम ऐप्लिकेशन की मुख्य थ्रेड में चलने वाले ब्रॉडकास्ट रिसीवर को 10 सेकंड तक चलने देता है. इसके बाद, उन्हें रिस्पॉन्स न देने वाला माना जाता है और ऐप्लिकेशन में कोई समस्या होने (ANR) वाली गड़बड़ी ट्रिगर होती है. अगर विजेट को अपडेट होने में ज़्यादा समय लगता है, तो इन विकल्पों को आज़माएं:

  • WorkManager का इस्तेमाल करके कोई टास्क शेड्यूल करें.

  • goAsync तरीके का इस्तेमाल करके, ईमेल पाने वाले व्यक्ति को ज़्यादा समय दें. इससे, रिसीवर 30 सेकंड तक एक्सीक्यूट कर पाते हैं.

ज़्यादा जानकारी के लिए, सुरक्षा से जुड़ी बातें और सबसे सही तरीके देखें.

अपडेट की प्राथमिकता

डिफ़ॉल्ट रूप से, ब्रॉडकास्ट बैकग्राउंड प्रोसेस के तौर पर चलते हैं. इनमें AppWidgetProvider.onUpdate का इस्तेमाल करके बनाए गए ब्रॉडकास्ट भी शामिल हैं. इसका मतलब है कि सिस्टम के संसाधनों के ज़्यादा इस्तेमाल की वजह से, ब्रॉडकास्ट रिसीवर को शुरू करने में देरी हो सकती है. ब्रॉडकास्ट को प्राथमिकता देने के लिए, उसे फ़ोरग्राउंड प्रोसेस बनाएं.

उदाहरण के लिए, जब उपयोगकर्ता विजेट के किसी हिस्से पर टैप करता है, तो PendingIntent.getBroadcast को पास किए गए Intent में Intent.FLAG_RECEIVER_FOREGROUND फ़्लैग जोड़ें.

ऐसी सटीक झलक बनाएं जिनमें डाइनैमिक आइटम शामिल हों

पहली इमेज: विजेट की झलक, जिसमें सूची के कोई आइटम नहीं दिख रहे हैं.

इस सेक्शन में, कलेक्शन व्यू वाले विजेट के लिए, विजेट की झलक में एक से ज़्यादा आइटम दिखाने का सुझाव दिया गया है. इसका मतलब है कि ऐसा विजेट जो ListView, GridView या StackView का इस्तेमाल करता है.

अगर आपका विजेट इनमें से किसी एक व्यू का इस्तेमाल करता है, तो विजेट का असल लेआउट देकर स्केलेबल झलक बनाने पर, विजेट की झलक में कोई आइटम न दिखने पर, अनुभव खराब हो जाता है. ऐसा इसलिए होता है, क्योंकि कलेक्शन व्यू का डेटा रनटाइम के दौरान डाइनैमिक तौर पर सेट होता है. यह पहली इमेज में दिखाई गई इमेज से मिलता-जुलता दिखता है.

हमारा सुझाव है कि कलेक्शन व्यू वाले विजेट की झलक को विजेट पिकर में सही तरीके से दिखाने के लिए, सिर्फ़ झलक के लिए एक अलग लेआउट फ़ाइल बनाएं. इस अलग लेआउट फ़ाइल में, विजेट का असल लेआउट और झूठे आइटम के साथ प्लेसहोल्डर कलेक्शन व्यू शामिल होता है. उदाहरण के लिए, कई फ़र्ज़ी सूची आइटम के साथ प्लेसहोल्डर LinearLayout देकर, ListView की नकल की जा सकती है.

ListView का उदाहरण देने के लिए, किसी अलग लेआउट फ़ाइल से शुरू करें:

// 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 मेटाडेटा का previewLayout एट्रिब्यूट देते समय, प्रीव्यू लेआउट फ़ाइल की जानकारी दें. initialLayout एट्रिब्यूट के लिए, अब भी विजेट का असल लेआउट तय किया जा सकता है. साथ ही, रनटाइम के दौरान RemoteViews बनाते समय, विजेट का असल लेआउट इस्तेमाल किया जा सकता है.

<appwidget-provider
    previewLayout="@layout/widget_previe"
    initialLayout="@layout/widget_view" />

सूची के कॉम्प्लेक्स आइटम

पिछले सेक्शन में दिए गए उदाहरण में, सूची के आइटम नकली हैं, क्योंकि सूची के आइटम TextView ऑब्जेक्ट होते हैं. अगर आइटम के लेआउट मुश्किल हैं, तो नकली आइटम उपलब्ध कराना ज़्यादा मुश्किल हो सकता है.

widget_list_item.xml में दिए गए सूची आइटम पर विचार करें. इसमें दो TextView ऑब्जेक्ट हैं:

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

नकली सूची आइटम देने के लिए, लेआउट को कई बार शामिल किया जा सकता है. हालांकि, इससे हर सूची आइटम एक जैसा हो जाता है. सूची में यूनीक आइटम जोड़ने के लिए, यह तरीका अपनाएं:

  1. टेक्स्ट वैल्यू के लिए एट्रिब्यूट का सेट बनाएं:

    <resources>
        <attr name="widgetTitle" format="string" />
        <attr name="widgetContent" format="string" />
    </resources>
    
  2. टेक्स्ट सेट करने के लिए, इन एट्रिब्यूट का इस्तेमाल करें:

    <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. झलक के लिए ज़रूरत के मुताबिक स्टाइल बनाएं. हर स्टाइल में वैल्यू फिर से तय करें:

    <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. झलक वाले लेआउट में, नकली आइटम पर स्टाइल लागू करें:

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