توضّح هذه الصفحة الممارسات المقترَحة لإنشاء أداة أكثر تقدّمًا من أجل تقديم تجربة أفضل للمستخدم.
تحسينات لتحديث محتوى الأدوات
قد يكون تعديل محتوى التطبيق المصغّر مكلفًا من الناحية الحسابية. ولتوفير استهلاك البطارية، يمكنك تحسين نوع التحديث ومعدّل تكراره وتوقيته.
أنواع تعديلات الأدوات
وهناك ثلاث طرق لتحديث التطبيق المصغّر: التحديث الكامل، والتحديث الجزئي، وتحديث البيانات في حال استخدام التطبيق المصغّر للجمع. ولكل منها تكاليف وتشعّبات مختلفة للحساب.
في ما يلي شرح لكل نوع من أنواع التعديل، بالإضافة إلى مقتطفات رموز لكل نوع.
التحديث الكامل: يمكنك الاتصال بالرقم
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
. يمكن تحديث الأداة استجابة لتفاعل المستخدم أو بث التحديثات أو كليهما.
التحديث بشكل دوري
يمكنك التحكّم في معدّل تكرار التحديث الدوري من خلال تحديد قيمة للسمة AppWidgetProviderInfo.updatePeriodMillis
في ملف XML الخاص appwidget-provider
. ويؤدي كل تعديل إلى تفعيل طريقة AppWidgetProvider.onUpdate()
، وهي المكان الذي يمكنك فيه وضع الرمز لتعديل التطبيق المصغّر. ومع ذلك، يجب مراعاة بدائل
تحديثات جهاز استقبال البث الموضَّحة في القسم التالي، وذلك إذا كانت الأداة بحاجة إلى تحميل البيانات بشكل غير متزامن أو تستغرق أكثر من 10 ثوانٍ للتحديث، لأنّه بعد 10 ثوانٍ، يعتبر النظام
BroadcastReceiver
غير مستجيب.
لا يمكن استخدام قيم تقل عن 30 دقيقة في updatePeriodMillis
. ومع ذلك، إذا كنت تريد إيقاف التحديثات الدورية، يمكنك تحديد 0.
ويمكنك السماح للمستخدمين بضبط معدّل التحديثات من خلال الإعدادات. على سبيل المثال، قد يرغبون في تحديث مؤشر الأسهم كل 15 دقيقة أو أربع مرات فقط في اليوم. في هذه الحالة، اضبط السمة updatePeriodMillis
على 0 واستخدِم WorkManager
بدلاً من ذلك.
التعديل استجابةً لتفاعل المستخدم
في ما يلي بعض الطُرق المقترَحة لتعديل التطبيق المصغّر استنادًا إلى تفاعل المستخدم:
من نشاط في التطبيق: الاتصال مباشرةً بـ
AppWidgetManager.updateAppWidget
ردًا على تفاعل أحد المستخدمين، مثل نقرة أحد المستخدمين.من التفاعلات عن بُعد، مثل الإشعارات أو التطبيقات المصغّرة، أنشِئ
PendingIntent
، ثم عدِّل التطبيق المصغّر منActivity
أوBroadcast
أوService
التي تم استدعائها. يمكنك اختيار أولويتك. على سبيل المثال، إذا اخترتBroadcast
لـPendingIntent
، يمكنك اختيار بث في المقدّمة لمنح الأولويةBroadcastReceiver
.
التحديث استجابةً لحدث بث
من الأمثلة على حدث بث يتطلّب تحديث تطبيق مصغّر، ما يحدث عندما يلتقط المستخدم صورة. في هذه الحالة، ستحتاج إلى تحديث التطبيق المصغّر عند اكتشاف صورة جديدة.
يمكنك جدولة مهمة باستخدام JobScheduler
وتحديد البث
كعامل تشغيل باستخدام الطريقة
JobInfo.Builder.addTriggerContentUri
.
يمكنك أيضًا تسجيل BroadcastReceiver
للبث، مثلاً من خلال الاستماع إلى ACTION_LOCALE_CHANGED
.
ومع ذلك، وبما أنّ هذا الجهاز يستهلك موارد الجهاز، عليك استخدامه بحرص واستمِع فقط إلى البث المحدّد. مع إطلاق قيود على البث في Android
7.0 (المستوى 24 من واجهة برمجة التطبيقات) وAndroid 8.0 (المستوى 26 من واجهة برمجة التطبيقات)، لا يمكن للتطبيقات تسجيل
عمليات البث الضمني في بياناتها، مع بعض
الاستثناءات.
الاعتبارات الواجب مراعاتها عند تعديل تطبيق مصغّر من BroadcastReceivedr
إذا تم تعديل التطبيق المصغّر من خلال BroadcastReceiver
، بما في ذلك AppWidgetProvider
، يُرجى مراعاة الاعتبارات التالية في ما يتعلّق بمدة تحديث الأداة وأولوية التحديث.
مدة التحديث
كقاعدة، يسمح النظام لأجهزة استقبال البث، التي تعمل عادةً في سلسلة التعليمات الرئيسية للتطبيق، بالتشغيل لمدة تصل إلى 10 ثوانٍ قبل اعتبارها غير مستجيبة وظهور خطأ التطبيق لا يستجيب (ANR). إذا استغرق تحديث الأداة وقتًا أطول، فكر في البدائل التالية:
يمكنك جدولة مهمة باستخدام
WorkManager
.امنح المتلقّي وقتًا إضافيًا من خلال استخدام طريقة
goAsync
. يسمح هذا الإجراء لأجهزة الاستقبال بالتنفيذ لمدة 30 ثانية.
راجع اعتبارات الأمان وأفضل الممارسات للحصول على مزيد من المعلومات.
أولوية التحديث
يتم تلقائيًا تشغيل عمليات البث، بما في ذلك تلك التي يتم إجراؤها باستخدام AppWidgetProvider.onUpdate
، كعمليات في الخلفية. ويعني هذا أنّ التحميل الزائد لموارد النظام قد يؤدي إلى تأخير استدعاء مستقبِل البث. لمنح الأولوية للبث، اجعله عملية في المقدّمة.
على سبيل المثال، أضِف العلامة Intent.FLAG_RECEIVER_FOREGROUND
إلى Intent
الذي تم تمريره إلى PendingIntent.getBroadcast
عندما ينقر المستخدم على جزء معيّن من التطبيق المصغّر.
إنشاء معاينات دقيقة تتضمّن عناصر ديناميكية
![](https://developer.android.com/static/images/appwidgets/missing-list.png?authuser=5&hl=ar)
يشرح هذا القسم الأسلوب الموصى به لعرض عناصر متعددة في معاينة أداة باستخدام عرض المجموعة، أي تطبيق مصغّر يستخدم ListView
أو GridView
أو StackView
.
وإذا كان التطبيق المصغّر يستخدم إحدى طرق العرض هذه، سيؤدي إنشاء معاينة قابلة للتوسّع من خلال توفير التنسيق الفعلي للأداة بشكل مباشر إلى خفض مستوى التجربة عندما لا تعرض معاينة الأداة أي عناصر. يحدث هذا بسبب تعيين بيانات عرض المجموعة ديناميكيًا في وقت التشغيل، وتبدو مشابهة للصورة المعروضة في الشكل 1.
لعرض معاينات التطبيقات المصغّرة ذات طرق عرض المجموعة بشكل صحيح في منتقي التطبيقات المصغّرة،
ننصحك بالحفاظ على ملف تنسيق منفصل مخصّص للمعاينة فقط. يتضمن ملف التخطيط المنفصل هذا تخطيط الأداة الفعلي
وعرض مجموعة العناصر النائبة مع عناصر مزيفة. على سبيل المثال، يمكنك تقليد ListView
من خلال توفير عنصر نائب LinearLayout
يحتوي على عدة عناصر قائمة مزيفة.
لتوضيح مثال عن 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>
حدِّد ملف تنسيق المعاينة عند توفير السمة previewLayout
للبيانات الوصفية AppWidgetProviderInfo
. سيكون عليك تحديد التنسيق الفعلي للتطبيق المصغّر للسمة 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>
لتقديم عناصر قائمة مزيفة، يمكنك تضمين التخطيط عدة مرات، ولكن هذا يؤدي إلى تطابق كل عنصر من عناصر القائمة. لتوفير عناصر قائمة فريدة، اتّبِع الخطوات التالية:
أنشئ مجموعة من السمات للقيم النصية:
<resources> <attr name="widgetTitle" format="string" /> <attr name="widgetContent" format="string" /> </resources>
استخدِم السمات التالية لضبط النص:
<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>
يمكنك إنشاء العدد المطلوب من الأنماط للمعاينة. أعد تحديد القيم في كل نمط:
<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>
طبِّق الأنماط على العناصر الزائفة في تنسيق المعاينة:
<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>