توضّح هذه الصفحة الممارسات المقترَحة لإنشاء تطبيق مصغّر أكثر تقدّمًا لتوفير تجربة أفضل للمستخدم.
تحسينات لتعديل محتوى التطبيقات المصغّرة
قد يكون تعديل محتوى التطبيقات المصغّرة ذا تكلفة حسابية عالية. ولتوفير استهلاك البطارية، عليك تحسين نوع التحديث ومعدّل تكراره وتوقيته.
أنواع تحديثات التطبيقات المصغّرة
هناك ثلاث طرق لتعديل التطبيق المصغّر: تعديل كامل وتعديل جزئي، وفي حال تطبيق مصغّر للمجموعة، تحديث البيانات. ولكل منها تكاليف حسابية ونتائج مختلفة.
في ما يلي وصف لكل نوع تحديث، كما يوفر مقتطفات رمز لكل نوع.
التحديث الكامل: اتصل على
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);
يمكنك استدعاء هذه الطرق من أي مكان في تطبيقك، شرط أن يكون للتطبيق UID مماثل لـ
AppWidgetProvider
.
تحديد عدد مرات تحديث التطبيق المصغّر
يتم تعديل التطبيقات المصغّرة بشكل دوري استنادًا إلى القيمة المقدَّمة لسمة
updatePeriodMillis
. ويمكن تحديث الأداة استجابةً لتفاعل المستخدم أو لبث التحديثات أو لكليهما.
التحديث بصفة دورية
يمكنك التحكّم في معدّل تكرار التحديث الدوري من خلال تحديد قيمة لسمة
AppWidgetProviderInfo.updatePeriodMillis
في ملف XML الخاص بـ appwidget-provider
. يؤدي كل
تعديل إلى تنشيط الطريقة AppWidgetProvider.onUpdate()
، وهي الطريقة التي
يمكنك من خلالها وضع الرمز لتحديث التطبيق المصغّر. ومع ذلك، ننصحك بالاطّلاع على البدائل ل
تحديثات مستقبلي البث الموضّحة في القسم التالي إذا كان التطبيق المصغّر يحتاج إلى تحميل البيانات بشكل غير متزامن أو يستغرق أكثر من
10 ثوانٍ لإجراء التحديث، لأنّ النظام يعتبر بعد 10 ثوانٍ أنّه
BroadcastReceiver
لا يستجيب.
لا يسمح updatePeriodMillis
باستخدام القيم التي تقلّ عن 30 دقيقة. ومع ذلك، إذا
أردت إيقاف التحديثات الدورية، يمكنك تحديد 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 لواجهة برمجة التطبيقات)، لن تتمكّن التطبيقات من تسجيل عمليات البث الضمنية في بياناتها، مع بعض الاستثناءات.
الاعتبارات الواجب مراعاتها عند تعديل تطبيق مصغّر من BroadcastReceiver
إذا تم تعديل التطبيق المصغّر من BroadcastReceiver
، بما في ذلك
AppWidgetProvider
، يجب مراعاة النقاط التالية بشأن
مدة تعديل التطبيق المصغّر وأولويته.
مدة التحديث
وكقاعدة عامة، يسمح النظام لأجهزة استقبال البث، التي تعمل عادةً في سلسلت الرسائل الأساسية للتطبيق، بالعمل لمدة تصل إلى 10 ثوانٍ قبل اعتبارها غير مستجيبة والتسبب في خطأ "التطبيق لا يستجيب". إذا استغرق تعديل التطبيق المصغّر وقتًا أطول، ننصحك باتّباع الخطوات التالية:
حدِّد موعدًا لمهمة باستخدام
WorkManager
.يمكنك منح المستلِم المزيد من الوقت باستخدام الطريقة
goAsync
. يتيح ذلك للمستلمين تنفيذ الإجراء لمدة 30 ثانية.
راجِع اعتبارات الأمان وأفضل الممارسات للحصول على مزيد من المعلومات.
أولوية التحديث
يتم تشغيل عمليات البث، بما في ذلك تلك التي يتم إجراؤها باستخدام
AppWidgetProvider.onUpdate
، كعمليات في الخلفية تلقائيًا. وهذا يعني أنّه
يمكن أن تؤدي موارد النظام المثقلة بالتحميل إلى تأخير في استدعاء معالج
البث. لمنح البث الأولوية، اجعله عملية في المقدّمة.
على سبيل المثال، يمكنك إضافة علامة
Intent.FLAG_RECEIVER_FOREGROUND
إلى Intent
الذي تم ضبطه على PendingIntent.getBroadcast
عندما ينقر المستخدم
على جزء معيّن من الأداة.
إنشاء معاينات دقيقة تتضمّن عناصر ديناميكية
يوضّح هذا القسم النهج الموصى به لعرض عناصر متعددة في معاينة تطبيق مصغّر لأداة تتضمن طريقة عرض
المجموعة، وهي أداة تستخدم
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>