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

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

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

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

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

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

يوضّح ما يلي كل نوع من أنواع التعديلات ويقدّم مقتطفات رمز لكل منها.

  • تحديث كامل: أريد الاتصال بالرقم 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 لا يستجيب.

لا تتيح الدالة 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>