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

امتحان کردن روش «نوشتن»
‫Jetpack Compose جعبه‌ابزار واسط کاربر توصیه‌شده برای Android است. با نحوه ساختن ابزارک بااستفاده از APIهای سبک 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 اشاره دارد.

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

مورد اصلی موردنیاز برای فایل زبان نشانه‌گذاری توسعه‌پذیر چیدمان ابزاره شما این است که یکی از نماهای مجموعه را داشته باشد: 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 استفاده می‌کند. وقتی ابزاره فعال باشد، سیستم بااستفاده از موقعیت نمایه‌ای این اشیا در آرایه به آن‌ها دسترسی پیدا می‌کند و نوشتاری را که حاوی آن است نمایش می‌دهد.

در اینجا گزیده‌ای از پیاده‌سازی RemoteViewsFactory نمونه StackWidget آمده است که بخش‌هایی از روش 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() برگشتی انجام دهید. این تماس قبل‌از واکشی فراداده یا داده‌های بازدید از RemoteViewsFactory تکمیل می‌شود. همچنین می‌توانید عملیات پردازش‌محور را در روش getViewAt() انجام دهید. اگر این تماس طول بکشد، نمای بارگیری—که با روش RemoteViewsFactory شیء getLoadingView() مشخص شده است—در موقعیت مربوطه نمای مجموعه تا زمانی که برگردد نمایش داده می‌شود.

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

‫Android 12 (میانای برنامه‌سازی کاربردی سطح ۳۱) روش 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()
)