إنشاء تطبيق مصغّر متقدّم

توضح هذه الصفحة الممارسات الموصى بها لإنشاء أداة أكثر تقدمًا تجربة مستخدم أفضل.

تحسينات لتحديث محتوى التطبيق المصغّر

قد يكون تحديث محتوى التطبيق المصغّر مُكلفًا من الناحية الحسابية. لتوفير طاقة البطارية تحسين نوع التحديث وتكراره وتوقيته.

أنواع تحديثات التطبيقات المصغّرة

هناك ثلاث طرق لتحديث التطبيق المصغَّر: تحديث كامل، وتحديث جزئي، وهو إعادة تحميل البيانات في حال استخدام أداة جمع. ولكلٍّ من هذه المستويات التكاليف الحاسوبية والتداعيات.

في ما يلي وصف لكل نوع تحديث، كما يوفر مقتطفات رمز لكل نوع.

  • تحديث كامل: أريد الاتصال بالرقم 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 في appwidget-provider XML. على كل يؤدي هذا التحديث إلى تشغيل طريقة 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)، لا يمكن للتطبيقات تسجيل البيانات الضمنية عمليات البث في بياناتها، مع بعض الاستثناءات:

نقاط يجب أخذها في الاعتبار عند تحديث تطبيق مصغّر من جهاز BroadcastRecipient.

إذا تم تحديث التطبيق المصغّر من BroadcastReceiver، بما في ذلك AppWidgetProvider، يُرجى الانتباه إلى الاعتبارات التالية بشأن مدة وأولوية تحديث التطبيق المصغّر.

مدة التحديث

كقاعدة عامة، يتيح النظام لأجهزة استقبال البث، التي تعمل عادةً في السلسلة الرئيسية، يتم تشغيلها لمدة تصل إلى 10 ثوانٍ قبل اعتبارها غير مستجيبة تشغيل رسالة Application Not جارٍ الاستجابة (ANR). إذا استغرقت وقتًا أطول تحديث الأداة، فيمكنك تجربة البدائل التالية:

  • جدولة مهمة باستخدام WorkManager

  • منح المستلِم المزيد من الوقت من خلال goAsync. يتيح ذلك تنفيذ أجهزة الاستقبال لمدة 30 ثانية.

راجع اعتبارات الأمان وأفضل الممارسات الممارسات لمزيد من المعلومات.

أولوية التحديث

تشمل عمليات البث التي يتم إجراؤها باستخدام AppWidgetProvider.onUpdate: يتم تشغيلها كعمليات في الخلفية. يعني ذلك قد تؤدي زيادة تحميل موارد النظام إلى تأخير في استدعاء البث. المستلم. لمنح الأولوية للبث، اجعله عملية تعمل في المقدّمة.

على سبيل المثال، أضف السمة Intent.FLAG_RECEIVER_FOREGROUND وضع علامة على Intent يتم تمريره إلى PendingIntent.getBroadcast عندما يمر المستخدم ينقر على جزء معين من الأداة.

إنشاء معاينات دقيقة تتضمن عناصر ديناميكية

الشكل 1: معاينة أداة لا تعرض أي عناصر قائمة

يشرح هذا القسم الطريقة الموصى بها لعرض عناصر متعددة في معاينة أداة بها مجموعة view - وهو تطبيق مصغّر يستخدم 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>

لتوفير عناصر قائمة مزيفة، يمكنك تضمين التخطيط عدة مرات، ولكن هذا إلى أن يكون جميع عناصر القائمة متطابقًا. لتوفير عناصر قائمة فريدة، يُرجى اتباع الخطوات التالية:

  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>