集合微件专门用于显示多个相同类型的元素,例如 作为图库应用中的图片集合、新闻应用中的文章,或 从通信应用获取消息集合 widget 通常侧重于两种用途 案例:浏览集合并打开集合的某个元素, 详情视图。集合微件可以垂直滚动。
这些微件使用
要显示的内容数量:RemoteViewsService
由远程数据(如来自
provider。该微件会显示
数据使用以下视图类型之一,这些视图类型称为集合
观看次数:
ListView
- 以视图形式显示内容 垂直滚动列表。
GridView
- 以视图形式显示内容 二维滚动网格。
StackView
- 一张堆叠的卡片 分别查看上一张或下一张卡片。
AdapterViewFlipper
-
适配器支持简单
具有动画效果的
ViewAnimator
在两个或更多视图之间来回切换一次只能显示一个子级。
由于这些集合视图显示由远程数据支持的集合,
使用 Adapter
绑定其用户
与其数据的接口Adapter
绑定了一组数据中的各个项
单个 View
对象。
由于这些集合视图由适配器提供支持,因此 Android 框架
必须包含额外的架构来支持在 widget 中使用它们。在上下文中
时,Adapter
会替换为
RemoteViewsFactory
,
它是 Adapter
接口的瘦封装容器。收到请求后,
集合中的特定项时,RemoteViewsFactory
会创建并返回
作为集合中的项
RemoteViews
对象。要加入
在 widget 中实现集合视图,实现 RemoteViewsService
并
RemoteViewsFactory
。
RemoteViewsService
是一项服务,可让遥控器适配器请求
RemoteViews
对象。RemoteViewsFactory
是适配器的接口
(例如 ListView
、GridView
和
StackView
)以及该视图的底层数据。来源:StackWidget
示例,
这是实现此服务的样板代码示例
接口:
Kotlin
class StackWidgetService : RemoteViewsService() { override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { return 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. }
Java
public class StackWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory(this.getApplicationContext(), intent); } } class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { // See the RemoteViewsFactory API reference for the full list of methods to // implement. }
示例应用
本部分中的代码段也从 StackWidget
示例:
此示例包含 10 个视图的堆栈,这些视图显示值 0 一直到九点为止示例 widget 具有以下主要行为:
用户可以垂直滑动 widget 中的顶部视图,以显示下一个 还是上一视图这是内置的
StackView
行为。在没有任何用户互动的情况下,该微件会自动推进到 按顺序观看,就像幻灯片一样。这是因为
android:autoAdvanceViewId="@id/stack_view"
在res/xml/stackwidgetinfo.xml
文件。此设置适用于数据视图 ID 在本例中为堆栈视图的视图 ID。如果用户轻触顶部视图,该微件会显示
Toast
消息“触摸视图 n”,其中 n 是触摸视图的索引(位置)。想要详细了解 请参阅为单个用户添加行为 items 部分。
通过集合实现 widget
要实现包含集合的微件,请按照在
widget,然后执行几个额外的步骤:
修改清单,向微件布局添加集合视图,
AppWidgetProvider
子类。
包含集合的微件的清单
除了在
清单,您需要让
绑定到您的RemoteViewsService
。为此,请将
具有 此权限的清单文件
BIND_REMOTEVIEWS
。
这可以防止其他应用自由访问微件的数据。
例如,创建一个使用 RemoteViewsService
填充
集合视图中,清单条目可能如下所示:
<service android:name="MyWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
在此示例中,android:name="MyWidgetService"
引用了
RemoteViewsService
。
包含集合的 widget 的布局
微件布局 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>
请注意,空视图必须是 空视图表示空状态。
除了整个 widget 的布局文件之外,还要创建另一个布局
文件,用于定义集合中每一项的布局,例如,
为图书集合中的每本图书设置布局。StackWidget
示例具有
只有一个项布局文件 widget_item.xml
,因为所有项都使用相同的
布局。
适用于包含集合的微件的 AppWidgetProvider 类
与常规微件一样,
AppWidgetProvider
子类
通常会
onUpdate()
。
在创建onUpdate()
具有集合的微件是您必须调用
setRemoteAdapter()
。这会告知集合视图从何处获取其数据。
然后,RemoteViewsService
可以返回您对
RemoteViewsFactory
,并且 widget 可以提供适当的数据。当您
调用此方法,然后传递一个指向您的
RemoteViewsService
和指定要更新的 widget 的 ID。
以下示例展示了 StackWidget
示例如何实现 onUpdate()
将 RemoteViewsService
设置为
微件集合:
Kotlin
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) }
Java
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Update each of the widgets with the remote adapter. for (int i = 0; i < appWidgetIds.length; ++i) { // Set up the intent that starts the StackViewService, which // provides the views for this collection. Intent intent = new Intent(context, StackWidgetService.class); // Add the widget ID to the intent extras. intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); // Instantiate the RemoteViews object for the widget layout. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); // 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. views.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. views.setEmptyView(R.id.stack_view, R.id.empty_view); // Do additional processing specific to this widget. appWidgetManager.updateAppWidget(appWidgetIds[i], views); } super.onUpdate(context, appWidgetManager, appWidgetIds); }
保留数据
如本页所述,RemoteViewsService
子类提供
用于填充远程集合视图的 RemoteViewsFactory
。
具体来说,请执行以下步骤:
RemoteViewsService
子类。RemoteViewsService
是通过 远程适配器可以请求RemoteViews
。在
RemoteViewsService
子类中,添加一个用于实现RemoteViewsFactory
接口。RemoteViewsFactory
是 适配器视图之间的适配器,例如ListView
、GridView
、StackView
以及该视图的底层数据。您的 实现负责为每个容器创建一个RemoteViews
对象 数据集中。此接口是Adapter
的瘦封装容器。
您不得依赖服务的单个实例或其包含的任何数据
持久保留。除非是静态的,否则不要将数据存储在 RemoteViewsService
中。如果
如果您想保留 widget 的数据,最好的方法是使用
ContentProvider
,其数据
会持续超过进程生命周期例如,杂货店微件可以
将每个购物清单项的状态存储在一个永久性位置,例如
SQL 数据库。
RemoteViewsService
实现的主要内容是
RemoteViewsFactory
(如下一部分中所述)。
RemoteViewsFactory 接口
实现 RemoteViewsFactory
接口的自定义类提供了以下功能:
具有其集合中项的数据的 widget。为此,
将 widget 项 XML 布局文件与数据源合并。此来源
数据可以是数据库、简单数组等任何内容。在StackWidget
中
则该数据源为 WidgetItems
的数组。RemoteViewsFactory
用作适配器,将数据粘合到远程集合视图中。
您需要为自己的代码实现的两个最重要的方法
RemoteViewsFactory
子类是
onCreate()
和
getViewAt()
。
首次创建工厂时,系统会调用 onCreate()
。
您可以在此处设置与数据源的任何连接或游标。对于
例如,StackWidget
示例使用 onCreate()
来初始化
WidgetItem
对象。当微件处于活动状态时,系统会访问这些
对象使用其在数组中的索引位置,并显示相应的文本。
包含。
以下是摘录自StackWidget
示例的RemoteViewsFactory
显示 onCreate()
方法各个部分的实现:
Kotlin
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!") } ... } ... }
Java
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private static final int REMOTE_VIEW_COUNT = 10; private List<WidgetItem> widgetItems = new ArrayList<WidgetItem>(); public void onCreate() { // In onCreate(), setup 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. for (int i = 0; i < REMOTE_VIEW_COUNT; i++) { widgetItems.add(new WidgetItem(i + "!")); } ... } ...
RemoteViewsFactory
方法 getViewAt()
会返回 RemoteViews
对象
对应于数据集中指定 position
的数据。以下是
摘录自 StackWidget
示例的 RemoteViewsFactory
实现:
Kotlin
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) } }
Java
public RemoteViews getViewAt(int position) { // Construct a remote views item based on the widget item XML file // and set the text based on the position. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_item); views.setTextViewText(R.id.widget_item, widgetItems.get(position).text); return views; }
为各个项添加行为
前面的部分介绍了如何将数据绑定到 widget 集合。但是 如果您希望为广告系列中的各个项目添加动态行为, 集合视图?
如使用 onUpdate()
处理事件中所述
类,通常使用
setOnClickPendingIntent()
,用于设置对象的点击行为,例如
使按钮启动 Activity
。但是
不允许对单个集合项中的子视图使用此方法。
例如,您可以使用 setOnClickPendingIntent()
设置全局按钮
例如,在用于启动应用的 Gmail 小组件中,而不是在
。
而是要向集合中的各个项添加点击行为,请使用
setOnClickFillInIntent()
。这需要设置待处理 intent 模板,
然后在集合视图中
通过RemoteViewsFactory
收集。
本部分使用 StackWidget
示例来说明如何将行为添加到
单个项。在 StackWidget
示例中,如果用户轻触顶部视图,
该 widget 会显示 Toast
消息“Touched view n”,其中,n 是
被触摸视图的索引(位置)。其工作原理如下:
StackWidgetProvider
-AppWidgetProvider
子类 - 使用名为TOAST_ACTION
。当用户触摸视图时,会触发 intent 并广播
TOAST_ACTION
。此广播会被
StackWidgetProvider
类的onReceive()
方法,并且该 widget 会显示Toast
消息 使用触摸视图合集项的数据由RemoteViewsFactory
到RemoteViewsService
。
设置待处理 intent 模板
StackWidgetProvider
(
AppWidgetProvider
子类)
设置待定 intent集合中的个别项无法设置其
自己的待处理 intent。相反,整个集合会设置一个待定 intent
各个项设置填充 intent 来创建唯一
对每件商品的行为进行针对性的处理。
该类还会接收在用户触摸
视图。它在自己的 onReceive()
方法中处理此事件。如果意图的
操作为 TOAST_ACTION
时,该 widget 会针对当前的Toast
视图。
Kotlin
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)) PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT) } rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent) appWidgetManager.updateAppWidget(appWidgetId, rv) } super.onUpdate(context, appWidgetManager, appWidgetIds) } }
Java
public class StackWidgetProvider extends AppWidgetProvider { public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION"; public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM"; ... // 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 public void onReceive(Context context, Intent intent) { AppWidgetManager mgr = AppWidgetManager.getInstance(context); if (intent.getAction().equals(TOAST_ACTION)) { int appWidgetId = 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. int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0); Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show(); } super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Update each of the widgets with the remote adapter. for (int i = 0; i < appWidgetIds.length; ++i) { // Sets up the intent that points to the StackViewService that // provides the views for this collection. Intent intent = new Intent(context, StackWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); // When intents are compared, the extras are ignored, so embed // the extras into the data so that the extras are not // ignored. intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); rv.setRemoteAdapter(appWidgetIds[i], 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. rv.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. Intent toastIntent = new Intent(context, StackWidgetProvider.class); // Set the action for the intent. // When the user touches a particular view, it has the effect of // broadcasting TOAST_ACTION. toastIntent.setAction(StackWidgetProvider.TOAST_ACTION); toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent); appWidgetManager.updateAppWidget(appWidgetIds[i], rv); } super.onUpdate(context, appWidgetManager, appWidgetIds); } }
设置填充 intent
您的 RemoteViewsFactory
必须在
。这样就可以区分每个点击操作
属性。填充 intent 随后会与
PendingIntent
模板以确定
点按项目时执行的最终 intent。
Kotlin
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) ... } } ... }
Java
public class StackWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory(this.getApplicationContext(), intent); } } class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private static final int count = 10; private List<WidgetItem> widgetItems = new ArrayList<WidgetItem>(); private Context context; private int appWidgetId; public StackRemoteViewsFactory(Context context, Intent intent) { this.context = context; appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } // Initialize the data set. public void 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. for (int i = 0; i < count; i++) { widgetItems.add(new WidgetItem(i + "!")); } ... } // Given the position (index) of a WidgetItem in the array, use the // item's text value in combination with the widget item XML file to // construct a RemoteViews object. public RemoteViews getViewAt(int position) { // Position always ranges from 0 to getCount() - 1. // Construct a RemoteViews item based on the widget item XML // file and set the text based on the position. RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_item); rv.setTextViewText(R.id.widget_item, widgetItems.get(position).text); // Set a fill-intent to fill in the pending // intent template that is set on the collection view in // StackWidgetProvider. Bundle extras = new Bundle(); extras.putInt(StackWidgetProvider.EXTRA_ITEM, position); Intent fillInIntent = new Intent(); fillInIntent.putExtras(extras); // Make it possible to distinguish the individual on-click // action of a given item. rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); // Return the RemoteViews object. return rv; } ... }
使集合数据保持最新状态
图 2 展示了使用集合的 widget 中的更新流程。它会显示
widget 代码如何与 RemoteViewsFactory
交互,以及如何
触发器更新:
使用集合的微件可以为用户提供最新内容。对于
例如,Gmail 微件可为用户提供收件箱的快照。要使
触发 RemoteViewsFactory
和集合视图来获取和
显示新数据。
为此,请使用
AppWidgetManager
可呼叫
notifyAppWidgetViewDataChanged()
。此调用会导致对 RemoteViewsFactory
对象的
onDataSetChanged()
方法,这样您便可以提取任何新数据。
您可以在
onDataSetChanged()
回调。我们保证会完成此次通话
然后再从 RemoteViewsFactory
提取元数据或视图数据。您
还可以在 getViewAt()
内执行处理密集型操作,
方法。如果此调用需要很长时间,则加载视图(由
RemoteViewsFactory
对象的
getLoadingView()
方法 - 显示在集合视图的相应位置
直到返回结果。
使用 RemoteCollectionItems 直接传递集合
Android 12(API 级别 31)添加了 setRemoteAdapter(int viewId,
RemoteViews.RemoteCollectionItems
items)
方法,这样您的应用就可以在填充
集合视图如果您使用此方法设置适配器,则无需
实现 RemoteViewsFactory
,并且无需调用
notifyAppWidgetViewDataChanged()
。
除了让您更轻松地填充适配器外,此方法还可
消除了在用户向下滚动列表以填充新项时出现的延迟
显示一个新项只要满足以下条件,最好使用这种方法设置适配器
您的集合项集合相对较小。不过,举个例子,
如果您的集合包含大量 Bitmaps
,则此方法将不太奏效
传递给 setImageViewBitmap
。
如果集合没有使用一组固定的布局(也就是说,
项只是偶尔存在,请使用 setViewTypeCount
指定
集合可以包含的唯一布局的最大数量。这样,
适配器在应用微件的更新间重复使用。
以下示例说明了如何实现简化的 RemoteViews
集合。
Kotlin
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() )
Java
List<Integer> itemLayouts = Arrays.asList( R.layout.item_type_1, R.layout.item_type_2, ... ); remoteView.setRemoteAdapter( R.id.list_view, new RemoteViews.RemoteCollectionItems.Builder() .addItem(/* id= */ ID_1, new RemoteViews(context.getPackageName(), R.layout.item_type_1)) .addItem(/* id= */ ID_2, new RemoteViews(context.getPackageName(), R.layout.item_type_2)) ... .setViewTypeCount(itemLayouts.size()) .build() );