استفاده از ابزاره‌های مجموعه

امتحان کردن روش Compose
Jetpack Compose جعبه‌ابزار واسط کاربر توصیه‌شده برای Android است. با نحوه ساختن ابزاره بااستفاده از میاناهای برنامه‌سازی کاربردی سبک Compose آشنا شوید.

ابزارک‌های «مجموعه» در نمایش عناصر متعدد از یک نوع تخصص دارند، مانند مجموعه‌ای از تصاویر از یک برنامه گالری، مقاله‌هایی از یک برنامه خبری، یا پیام‌هایی از یک برنامه ارتباطی. ابزارک‌های «مجموعه» معمولاً بر دو مورد استفاده تمرکز دارند: مرور مجموعه و باز کردن یک عنصر از مجموعه برای مشاهده جزئیات آن. ابزاره‌های «مجموعه» می‌توانند به‌صورت عمودی پیمایش شوند.

این ابزاره‌ها از RemoteViewsService برای نمایش مجموعه‌هایی استفاده می‌کنند که با داده‌های ازراه‌دور پشتیبانی می‌شوند، مثلاً از ارائه‌دهنده محتوا. ابزاره داده‌ها را بااستفاده از یکی از انواع نمای زیر ارائه می‌کند که به‌عنوان نماهای مجموعه شناخته می‌شوند:

ListView: نمایی که موارد را در فهرستی با پیمایش عمودی نشان می‌دهد.

GridView: نمایی که موارد را در جدولی پیمایشی و دوبعدی نشان می‌دهد.

StackView: نمای کارت پشته‌ای—شبیه به رولودکس—که در آن کاربر می‌تواند کارت جلویی را به‌سمت بالا یا پایین بکشد تا به‌ترتیب کارت قبلی یا بعدی را ببیند.

AdapterViewFlipper: ViewAnimator با پشتیبانی آداپتور که بین دو یا چند نما پویانمایی می‌کند. هربار فقط یک فرزند نشان داده می‌شود.

چون این نماهای مجموعه، مجموعه‌هایی را نمایش می‌دهند که با داده‌های راه دور پشتیبانی می‌شوند، از Adapter برای مقید کردن میانای کاربر به داده‌هایشان استفاده می‌کنند. Adapter موارد تکی را از مجموعه‌ای از داده‌ها به اشیای View تکی متصل می‌کند.

و چون این نماهای مجموعه با آداپتورها پشتیبانی می‌شوند، چارچوب Android باید شامل معماری اضافی برای پشتیبانی از استفاده آن‌ها در ابزاره‌ها باشد. در بافت ابزاره، Adapter با RemoteViewsFactory جایگزین می‌شود، که پوشش نازکی در اطراف میانای Adapter است. وقتی برای مورد خاصی در مجموعه درخواست می‌شود، RemoteViewsFactory مورد را برای مجموعه به‌عنوان شیء RemoteViews ایجاد می‌کند و برمی‌گرداند. برای گنجاندن نمای مجموعه در ابزاره‌تان، RemoteViewsService و RemoteViewsFactory را پیاده‌سازی کنید.

RemoteViewsService سرویسی است که به آداپتور راه دور اجازه می‌دهد اشیاء RemoteViews را درخواست کند. ‫RemoteViewsFactory میانایی برای آداپتور بین نمای مجموعه (مثل ListView، GridView، و StackView) و داده‌های اساسی آن نما است. از StackWidget نمونه، در اینجا نمونه‌ای از کد متن استاندارد برای پیاده‌سازی این سرویس و میانای آن آورده شده است:

class StackWidgetService : RemoteViewsService() {
    override fun onGetViewFactory(intent: Intent): RemoteViewsFactory =
        StackRemoteViewsFactory(this.applicationContext, intent)
}

class StackRemoteViewsFactory(
    private val context: Context, intent: Intent
) : RemoteViewsService.RemoteViewsFactory {

    // See the RemoteViewsFactory API reference for the full list of methods to implement.

}

برنامه نمونه

گزیده‌های کد در این بخش نیز از نمونه StackWidget گرفته شده است:

StackWidget که نماهای پشته‌ای را نمایش می‌دهد
شکل ۱. ‫StackWidget.

این نمونه شامل پشته‌ای از ده نما است که مقادیر صفر تا نه را نمایش می‌دهد. ابزاره نمونه این رفتارهای اصلی را دارد:

  • کاربر می‌تواند نمای بالا را در ابزاره به‌صورت عمودی بکشد تا نمای بعدی یا قبلی نمایش داده شود. این رفتار داخلی StackView است.

  • بدون هیچ‌گونه تعامل کاربر، ابزاره به‌طور خودکار در نماهای خود به‌ترتیب پیش می‌رود، مانند نمایش اسلاید. این به‌دلیل تنظیم android:autoAdvanceViewId="@id/stack_view" در فایل res/xml/stackwidgetinfo.xml است. این تنظیم برای شناسه نما اعمال می‌شود، که در این مورد شناسه نمای پشته است.

  • اگر کاربر نمای بالا را لمس کند، ابزاره پیام Toast «نمای n لمس شد» را نمایش می‌دهد، که در آن n نمایه (موقعیت) نمای لمس‌شده است. برای بحث بیشتر درباره نحوه پیاده‌سازی رفتارها، به بخش افزودن رفتار به موارد جداگانه مراجعه کنید.

پیاده‌سازی ابزاره‌ها با مجموعه‌ها

برای پیاده‌سازی ابزاره با مجموعه‌ها، روال پیاده‌سازی هر ابزاره را دنبال کنید و سپس چند مرحله دیگر را انجام دهید: مانیفست را اصلاح کنید، نمای مجموعه را به چیدمان ابزاره اضافه کنید، و زیرکلاس AppWidgetProvider خود را اصلاح کنید.

مانیفست برای ابزاره‌های دارای مجموعه

علاوه‌بر الزامات فهرست‌شده در اعلام ابزاره در مانیفست، باید امکان اتصال ابزاره‌های دارای مجموعه به RemoteViewsService را فراهم کنید. برای انجام این کار، سرویس را در فایل مانیفست خود با اجازه BIND_REMOTEVIEWS اعلام کنید. این کار مانع می‌شود برنامه‌های دیگر آزادانه به داده‌های ابزاره شما دسترسی پیدا کنند.

برای مثال، هنگام ایجاد ابزاره‌ای که از RemoteViewsService برای پر کردن نمای مجموعه استفاده می‌کند، ورودی مانیفست ممکن است به این شکل باشد:

<service android:name="MyWidgetService"
    android:permission="android.permission.BIND_REMOTEVIEWS" />

در این مثال، android:name="MyWidgetService" به زیرکلاس شما از RemoteViewsService اشاره دارد.

چیدمان ابزاره‌های دارای مجموعه

الزامات اصلی برای فایل XML چیدمان ابزاره شما این است که یکی از نماهای مجموعه را دربرداشته باشد: ListView، GridView، StackView، یا AdapterViewFlipper. این فایل widget_layout.xml برای StackWidget نمونه است:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <StackView
        android:id="@+id/stack_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:loopViews="true" />
    <TextView
        android:id="@+id/empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:background="@drawable/widget_item_background"
        android:textColor="#ffffff"
        android:textStyle="bold"
        android:text="@string/empty_view_text"
        android:textSize="20sp" />
</FrameLayout>

توجه داشته باشید که نماهای خالی باید هم‌نیاهای نمای مجموعه‌ای باشند که نمای خالی نشان‌دهنده وضعیت خالی آن است.

علاوه‌بر فایل چیدمان برای کل ابزاره، فایل چیدمان دیگری ایجاد کنید که چیدمان هر مورد را در مجموعه تعریف کند—برای مثال، چیدمانی برای هر کتاب در مجموعه‌ای از کتاب‌ها. نمونه StackWidget فقط یک فایل چیدمان مورد (widget_item.xml) دارد، زیرا همه موارد از یک چیدمان استفاده می‌کنند.

کلاس AppWidgetProvider برای ابزاره‌های دارای مجموعه

همانند ابزاره‌های معمولی، بخش عمده کد در AppWidgetProvider زیرکلاس معمولاً در onUpdate() قرار می‌گیرد. تفاوت اصلی در پیاده‌سازی شما برای onUpdate() هنگام ایجاد ابزاره با مجموعه‌ها این است که باید setRemoteAdapter() را فراخوانی کنید. این کار به نمای مجموعه می‌گوید که داده‌هایش را از کجا دریافت کند. سپس RemoteViewsService می‌تواند پیاده‌سازی شما از RemoteViewsFactory را برگرداند و ابزاره می‌تواند داده‌های مناسب را ارائه دهد. وقتی این روش را فراخوانی می‌کنید، قصدی را ارسال کنید که به پیاده‌سازی شما از RemoteViewsService و شناسه ابزاره‌ای که ابزاره را برای به‌روزرسانی مشخص می‌کند اشاره کند.

برای مثال، در اینجا نحوه پیاده‌سازی روش فراخوانی onUpdate() توسط نمونه StackWidget برای تنظیم RemoteViewsService به‌عنوان آداپتور ازراه‌دور برای مجموعه ابزاره آورده شده است:

override fun onUpdate(
    context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray
) {
    // Update each of the widgets with the remote adapter.
    appWidgetIds.forEach { appWidgetId ->

        // Set up the intent that starts the StackViewService, which
        // provides the views for this collection.
        val intent = Intent(context, StackWidgetService::class.java).apply {
            // Add the widget ID to the intent extras.
            putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
            data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
        }
        // Instantiate the RemoteViews object for the widget layout.
        val views = RemoteViews(context.packageName, R.layout.widget_layout).apply {
            // Set up the RemoteViews object to use a RemoteViews adapter.
            // This adapter connects to a RemoteViewsService through the
            // specified intent.
            // This is how you populate the data.
            setRemoteAdapter(R.id.stack_view, intent)

            // The empty view is displayed when the collection has no items.
            // It must be in the same layout used to instantiate the
            // RemoteViews object.
            setEmptyView(R.id.stack_view, R.id.empty_view)
        }

        // Do additional processing specific to this widget.

        appWidgetManager.updateAppWidget(appWidgetId, views)
    }
    super.onUpdate(context, appWidgetManager, appWidgetIds)
}

ماندگار کردن داده‌ها

همان‌طور که در این صفحه توضیح داده شده است، زیرکلاس RemoteViewsService RemoteViewsFactory را ارائه می‌دهد که برای پر کردن نمای مجموعه راه دور استفاده می‌شود.

به‌طور دقیق، این مراحل را انجام دهید:

  1. زیرکلاس RemoteViewsService. RemoteViewsService سرویسی است که ازطریق آن آداپتور ازراه‌دور می‌تواند RemoteViews را درخواست کند.

  2. در زیرکلاس RemoteViewsService، کلاسی را اضافه کنید که میانای RemoteViewsFactory را پیاده‌سازی می‌کند. ‫RemoteViewsFactory میانایی برای یک آداپتور بین نمای مجموعه ازراه‌دور (مانند ListView، GridView، StackView) و داده‌های اساسی برای آن نما است. پیاده‌سازی شما مسئول ایجاد شیء RemoteViews برای هر مورد در مجموعه داده است. این میانای کاربری یک پوشش نازک در اطراف Adapter است.

نمی‌توانید به یک نمونه از سرویس خود یا هر داده‌ای که در آن وجود دارد برای ماندگاری تکیه کنید. داده‌ها را در RemoteViewsService ذخیره نکنید، مگراینکه ثابت باشند. اگر می‌خواهید داده‌های ابزاره‌تان پایدار بماند، بهترین رویکرد استفاده از ContentProvider است که داده‌های آن فراتر از چرخه حیات فرایند پایدار می‌ماند. برای مثال، ابزاره فهرست خواربار می‌تواند وضعیت هر مورد فهرست خواربار را در مکانی پایدار، مانند پایگاه داده SQL، ذخیره کند.

محتوای اصلی پیاده‌سازی RemoteViewsService عبارت است از RemoteViewsFactory، که در بخش زیر شرح داده شده است.

میانای RemoteViewsFactory

کلاس سفارشی شما که میانای RemoteViewsFactory را پیاده‌سازی می‌کند، داده‌های مربوط به موارد موجود در مجموعه ابزاره را ارائه می‌دهد. برای انجام این کار، فایل چیدمان XML مورد ابزارک را با منبع داده ترکیب می‌کند. این منبع داده می‌تواند هر چیزی از پایگاه داده تا آرایه باشد. در StackWidget نمونه، منبع داده آرایه‌ای از WidgetItems است. RemoteViewsFactory به‌عنوان آداپتور برای چسباندن داده‌ها به نمای مجموعه راه دور عمل می‌کند.

دو روش مهمی که باید برای زیرکلاس RemoteViewsFactory پیاده‌سازی کنید عبارتند از onCreate() و getViewAt().

سیستم هنگام ایجاد کارخانه شما برای اولین‌بار، onCreate() را فراخوانی می‌کند. اینجا جایی است که هرگونه اتصال یا مکان‌نما را به منبع داده خود راه‌اندازی می‌کنید. برای مثال، نمونه StackWidget از onCreate() برای مقداردهی اولیه آرایه‌ای از اشیای WidgetItem استفاده می‌کند. وقتی ابزاره شما فعال است، سیستم بااستفاده از موقعیت نمایه این اشیاء در آرایه به آن‌ها دسترسی پیدا می‌کند و نوشتار موجود در آن‌ها را نمایش می‌دهد.

در اینجا گزیده‌ای از پیاده‌سازی نمونه StackWidget RemoteViewsFactory آورده شده است که بخش‌هایی از روش onCreate() را نشان می‌دهد:

private const val REMOTE_VIEW_COUNT: Int = 10

class StackRemoteViewsFactory(
    private val context: Context
) : RemoteViewsService.RemoteViewsFactory {

    private lateinit var widgetItems: List<WidgetItem>

    override fun onCreate() {
        // In onCreate(), set up any connections or cursors to your data
        // source. Heavy lifting, such as downloading or creating content,
        // must be deferred to onDataSetChanged() or getViewAt(). Taking
        // more than 20 seconds on this call results in an ANR.
        widgetItems = List(REMOTE_VIEW_COUNT) { index -> WidgetItem("$index!") }
    }

}

روش RemoteViewsFactory getViewAt() یک شیء RemoteViews را برمی‌گرداند که با داده‌های موجود در position مشخص‌شده در مجموعه داده مطابقت دارد. در اینجا گزیده‌ای از پیاده‌سازی RemoteViewsFactory نمونه StackWidget آورده شده است:

override fun getViewAt(position: Int): RemoteViews {
    // Construct a remote views item based on the widget item XML file
    // and set the text based on the position.
    return RemoteViews(context.packageName, R.layout.widget_item).apply {
        setTextViewText(R.id.widget_item, widgetItems[position].text)
    }
}

افزودن رفتار به موارد جداگانه

بخش‌های قبلی نشان می‌دهد چگونه داده‌هایتان را به مجموعه ابزارهایتان متصل کنید. اما اگر بخواهید رفتار پویا به موارد جداگانه در نمای مجموعه خود اضافه کنید، چه؟

همان‌طور که در مدیریت رویدادها با کلاس onUpdate() شرح داده شده است، معمولاً از setOnClickPendingIntent() برای تنظیم رفتار کلیک شیء استفاده می‌کنید—مثلاً برای اینکه دکمه‌ای باعث راه‌اندازی Activity شود. اما این رویکرد برای نماهای فرزند در یک مورد مجموعه مجاز نیست. برای مثال، می‌توانید از setOnClickPendingIntent() برای راه‌اندازی دکمه‌ای سراسری در ابزاره Gmail استفاده کنید که برنامه را راه‌اندازی می‌کند، اما نه در موارد فهرست جداگانه.

درعوض، برای افزودن رفتار کلیک به موارد جداگانه در مجموعه، از setOnClickFillInIntent() استفاده کنید. الگوی قصد معوقی برای نمای مجموعه‌تان راه‌اندازی کنید و بااستفاده از RemoteViewsFactory، قصد تکمیل‌کننده‌ای برای هر مورد در مجموعه تنظیم کنید.

این بخش از نمونه StackWidget برای شرح نحوه افزودن رفتار به موارد جداگانه استفاده می‌کند. در نمونه StackWidget، اگر کاربر نمای بالا را لمس کند، ابزاره پیام Toast «نمای n لمس شد» را نمایش می‌دهد که در آن n نمایه (موقعیت) نمای لمس‌شده است. نحوه کار به این صورت است:

  • StackWidgetProvider—یک زیرکلاس AppWidgetProvider—یک قصد معوق با کنش سفارشی به نام TOAST_ACTION ایجاد می‌کند.

  • وقتی کاربر نمایی را لمس می‌کند، هدف فعال می‌شود و TOAST_ACTION را همه‌فرستی می‌کند.

  • این پخش توسط روش onReceive() کلاس StackWidgetProvider رهگیری می‌شود و ابزاره پیام Toast را برای نمای لمس‌شده نمایش می‌دهد. داده‌های موارد مجموعه را RemoteViewsFactory ازطریق RemoteViewsService ارائه می‌کند.

الگوی قصد معوق راه‌اندازی شد

‫StackWidgetProvider (یک زیرکلاس AppWidgetProvider) یک قصد معوق را راه‌اندازی می‌کند. موارد جداگانه یک مجموعه نمی‌توانند قصد معوق خودشان را راه‌اندازی کنند. درعوض، مجموعه به‌عنوان یک کل، الگوی قصد معوقی را راه‌اندازی می‌کند و موارد تکی قصد تکمیل‌کننده‌ای را برای ایجاد رفتار منحصربه‌فرد به‌صورت موردبه‌مورد تنظیم می‌کنند.

این کلاس همچنین همه‌فرستی‌ای را که هنگام لمس کردن نمای توسط کاربر ارسال می‌شود دریافت می‌کند. این رویداد را در روش onReceive() خود پردازش می‌کند. اگر کنش هدف TOAST_ACTION باشد، ابزاره پیام Toast را برای نمای فعلی نمایش می‌دهد.

const val TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION"
const val EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM"

class StackWidgetProvider : AppWidgetProvider() {

    // ...

    // Called when the BroadcastReceiver receives an Intent broadcast.
    // Checks whether the intent's action is TOAST_ACTION. If it is, the
    // widget displays a Toast message for the current item.
    override fun onReceive(context: Context, intent: Intent) {
        val mgr: AppWidgetManager = AppWidgetManager.getInstance(context)
        if (intent.action == TOAST_ACTION) {
            val appWidgetId: Int = intent.getIntExtra(
                AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID
            )
            // EXTRA_ITEM represents a custom value provided by the Intent
            // passed to the setOnClickFillInIntent() method to indicate the
            // position of the clicked item. See StackRemoteViewsFactory in
            // Set the fill-in Intent for details.
            val viewIndex: Int = intent.getIntExtra(EXTRA_ITEM, 0)
            Toast.makeText(context, "Touched view $viewIndex", Toast.LENGTH_SHORT).show()
        }
        super.onReceive(context, intent)
    }

    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        // Update each of the widgets with the remote adapter.
        appWidgetIds.forEach { appWidgetId ->

            // Sets up the intent that points to the StackViewService that
            // provides the views for this collection.
            val intent = Intent(context, StackWidgetService::class.java).apply {
                putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
                // When intents are compared, the extras are ignored, so embed
                // the extra sinto the data so that the extras are not ignored.
                data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
            }
            val rv = RemoteViews(context.packageName, R.layout.widget_layout).apply {
                setRemoteAdapter(R.id.stack_view, intent)

                // The empty view is displayed when the collection has no items.
                // It must be a sibling of the collection view.
                setEmptyView(R.id.stack_view, R.id.empty_view)
            }

            // This section makes it possible for items to have individualized
            // behavior. It does this by setting up a pending intent template.
            // Individuals items of a collection can't set up their own pending
            // intents. Instead, the collection as a whole sets up a pending
            // intent template, and the individual items set a fillInIntent
            // to create unique behavior on an item-by-item basis.
            val toastPendingIntent: PendingIntent = Intent(
                context,
                StackWidgetProvider::class.java
            ).run {
                // Set the action for the intent.
                // When the user touches a particular view, it has the effect of
                // broadcasting TOAST_ACTION.
                action = TOAST_ACTION
                putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
                data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))

                // The template must be mutable, because each item fills in its
                // own extras through setOnClickFillInIntent().
                PendingIntent.getBroadcast(
                    context, 0, this,
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
                )
            }
            rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent)

            appWidgetManager.updateAppWidget(appWidgetId, rv)
        }
        super.onUpdate(context, appWidgetManager, appWidgetIds)
    }
}

قصد پر کردن را تنظیم کنید

RemoteViewsFactory شما باید برای هر مورد در مجموعه، قصد پر کردن تنظیم کند. این کار باعث می‌شود بتوان کنش کلیک کردن تکی یک مورد خاص را تشخیص داد. سپس قصد پر کردن با الگوی PendingIntent ترکیب می‌شود تا قصد نهایی که هنگام تک‌ضرب زدن روی مورد اجرا می‌شود تعیین شود.

private const val REMOTE_VIEW_COUNT: Int = 10

class StackRemoteViewsFactory(
    private val context: Context,
    intent: Intent
) : RemoteViewsService.RemoteViewsFactory {

    private lateinit var widgetItems: List<WidgetItem>
    private val appWidgetId: Int = intent.getIntExtra(
        AppWidgetManager.EXTRA_APPWIDGET_ID,
        AppWidgetManager.INVALID_APPWIDGET_ID
    )

    override fun onCreate() {
        // In onCreate(), set up any connections or cursors to your data source.
        // Heavy lifting, such as downloading or creating content, must be
        // deferred to onDataSetChanged() or getViewAt(). Taking more than 20
        // seconds on this call results in an ANR.
        widgetItems = List(REMOTE_VIEW_COUNT) { index -> WidgetItem("$index!") }
        // ...
    }

    // ...

    override fun getViewAt(position: Int): RemoteViews {
        // Construct a remote views item based on the widget item XML file
        // and set the text based on the position.
        return RemoteViews(context.packageName, R.layout.widget_item).apply {
            setTextViewText(R.id.widget_item, widgetItems[position].text)

            // Set a fill-intent to fill in the pending intent template.
            // that is set on the collection view in StackWidgetProvider.
            val fillInIntent = Intent().apply {
                Bundle().also { extras ->
                    extras.putInt(EXTRA_ITEM, position)
                    putExtras(extras)
                }
            }
            // Make it possible to distinguish the individual on-click
            // action of a given item.
            setOnClickFillInIntent(R.id.widget_item, fillInIntent)
            // ...
        }
    }
    // ...
}

به‌روز نگه داشتن داده‌های مجموعه

شکل ۲ جریان به‌روزرسانی را در ابزارکی که از مجموعه‌ها استفاده می‌کند نشان می‌دهد. این کد نشان می‌دهد چگونه کد ابزاره با RemoteViewsFactory تعامل می‌کند و چگونه می‌توانید به‌روزرسانی‌ها را راه‌اندازی کنید:

تعامل با RemoteViewsFactory درطول به‌روزرسانی‌ها
شکل ۲. تعامل با RemoteViewsFactory درطول به‌روزرسانی‌ها.

ابزارهایی که از مجموعه‌ها استفاده می‌کنند می‌توانند محتوای به‌روز دراختیار کاربران قرار دهند. برای مثال، ابزاره Gmail به کاربران نمایی از صندوق ورودی‌شان می‌دهد. برای ممکن کردن این امر، RemoteViewsFactory و نمای مجموعه خود را راه‌اندازی کنید تا داده‌های جدید را واکشی و نمایش دهد.

برای انجام این کار، از AppWidgetManager برای تماس با notifyAppWidgetViewDataChanged() استفاده کنید. این فراخوانی منجر به فراخوانی برگشتی به روش onDataSetChanged() شیء RemoteViewsFactory شما می‌شود که به شما امکان می‌دهد هر داده جدیدی را واکشی کنید.

می‌توانید عملیات پردازش فشرده را به‌طور هم‌زمان در onDataSetChanged() callback انجام دهید. این فراخوانی پیش‌از واکشی فراداده یا داده‌های نما از RemoteViewsFactory تکمیل می‌شود. همچنین می‌توانید عملیات‌های پردازش‌محور را در روش getViewAt() انجام دهید. اگر این فراخوانی طول بکشد، نمای بارگیری (که توسط متد getLoadingView() شیء RemoteViewsFactory مشخص شده است) در موقعیت مربوطه نمای مجموعه نمایش داده می‌شود تا زمانی که برگردد.

از RemoteCollectionItems برای ارسال مستقیم مجموعه استفاده کنید

Android 12 (سطح API‏ ۳۱) روش setRemoteAdapter(int viewId, RemoteViews.RemoteCollectionItems items) را اضافه می‌کند که به برنامه شما اجازه می‌دهد هنگام پر کردن نمای مجموعه، مستقیماً یک مجموعه را ارسال کند. اگر آداپتور را بااستفاده از این روش تنظیم کنید، نیازی به پیاده‌سازی RemoteViewsFactory و فراخوانی notifyAppWidgetViewDataChanged() ندارید.

این رویکرد علاوه‌بر اینکه پر کردن آداپتور را آسان‌تر می‌کند، تأخیر در پر کردن موارد جدید را نیز هنگام پیمایش کاربران در فهرست برای آشکار کردن مورد جدید ازبین می‌برد. این رویکرد برای تنظیم آداپتور تا زمانی ترجیح داده می‌شود که مجموعه موارد کلکسیون شما نسبتاً کوچک باشد. بااین‌حال، برای مثال، اگر مجموعه شما حاوی تعداد زیادی Bitmaps باشد که به setImageViewBitmap منتقل می‌شود، این رویکرد به‌خوبی کار نمی‌کند.

اگر مجموعه از مجموعه ثابتی از چیدمان‌ها استفاده نمی‌کند—یعنی اگر برخی از موارد فقط گاهی وجود دارند—از setViewTypeCount برای مشخص کردن حداکثر تعداد چیدمان‌های منحصربه‌فردی که مجموعه می‌تواند داشته باشد استفاده کنید. این کار باعث می‌شود که آداپتور بتواند در به‌روزرسانی‌های ابزاره برنامه شما دوباره استفاده شود.

در اینجا مثالی از نحوه پیاده‌سازی مجموعه‌های ساده‌شده RemoteViews آورده شده است.

val itemLayouts = listOf(
    R.layout.item_type_1,
    R.layout.item_type_2,
    // ...
)

remoteView.setRemoteAdapter(
    R.id.list_view,
    RemoteViews.RemoteCollectionItems.Builder()
        .addItem(/* id= */ ID_1, RemoteViews(context.packageName, R.layout.item_type_1))
        .addItem(/* id= */ ID_2, RemoteViews(context.packageName, R.layout.item_type_2))
        // ...
        .setViewTypeCount(itemLayouts.count())
        .build()
)