集合微件专门用于显示多个相同类型的元素,例如 作为图库应用中的图片集合、新闻应用中的文章,或 从通信应用获取消息集合 widget 通常侧重于两种用途 案例:浏览集合并打开集合的某个元素, 详情视图。集合微件可以垂直滚动。
这些微件使用 RemoteViewsService
来显示由远程数据(如来自内容提供程序的数据)支持的集合。该微件将使用以下某种视图类型(称为集合视图)呈现数据:
ListView
- 一种在垂直滚动列表中显示项目的视图。
GridView
- 以视图形式显示内容 二维滚动网格。
StackView
- 一张堆叠的卡片 分别查看上一张或下一张卡片。
AdapterViewFlipper
- 一种由适配器支持的简单
ViewAnimator
,可以在两个或更多视图之间呈现动画效果。一次只显示一个子级。
由于这些集合视图显示由远程数据支持的集合,因此它们使用 Adapter
将其界面绑定到其数据。Adapter
将一组数据中的各个项绑定到各个 View
对象。
由于这些集合视图由适配器支持,因此 Android 框架必须包含额外的架构来支持它们在微件中的使用。在上下文中
时,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 到 9。示例 widget 具有以下主要行为:
用户可以垂直滑动 widget 中的顶部视图,以显示下一个 还是上一视图这是内置的
StackView
行为。如果没有任何用户交互,则该微件会自动按顺序显示其视图,就像播放幻灯片一样。这是因为在
res/xml/stackwidgetinfo.xml
文件中设置了android:autoAdvanceViewId="@id/stack_view"
。此设置适用于数据视图 ID 在本例中为堆栈视图的视图 ID。如果用户触摸顶部视图,该微件会显示
Toast
消息“Touched view n”,其中 n 是触摸的视图的索引(位置)。想要详细了解 请参阅将行为添加到单个 items 部分。
通过集合实现 widget
如需实现包含集合的微件,请按照实现任何微件的步骤操作,然后再执行一些额外的步骤:修改清单、向微件布局添加集合视图,以及修改 AppWidgetProvider
子类。
包含集合的微件的清单
除了在清单中声明 widget 中列出的要求之外,您还需要使包含集合的 widget 能够绑定到 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>
请注意,空视图必须是 空视图表示空状态。
除了整个微件的布局文件之外,您还需要再创建一个布局文件,用来定义集合中每个项目的布局(例如,一套图书中每本图书的布局)。StackWidget
示例只有一个项布局文件 widget_item.xml
,因为所有项使用同一布局。
适用于包含集合的微件的 AppWidgetProvider 类
与常规微件一样,AppWidgetProvider
子类中的大部分代码通常都在 onUpdate()
中。在创建onUpdate()
具有集合的微件是您必须调用
setRemoteAdapter()
。这会告知集合视图从何处获取其数据。
然后,RemoteViewsService
可以返回您的 RemoteViewsFactory
实现,并且微件可以提供适当的数据。调用此方法时,请传递指向您的 RemoteViewsService
实现的 intent,以及指定要更新的微件的微件 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
中。如果您要保留微件的数据,最好的方法是使用 ContentProvider
,它的数据在进程生命周期过后持续存在。例如,杂货店微件可以
将每个购物清单项的状态存储在一个永久性位置,例如
SQL 数据库。
RemoteViewsService
实现的主要内容是它的 RemoteViewsFactory
,如下一部分所述。
RemoteViewsFactory 接口
实现 RemoteViewsFactory
接口的自定义类可以为微件包含的集合中的项目提供数据。为此,
将 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
示例中,如果用户触摸顶部视图,该微件会显示 Toast
消息“Touched view n”,其中 n 是触摸的视图的索引(位置)。其工作原理如下:
StackWidgetProvider
-AppWidgetProvider
子类 - 使用名为TOAST_ACTION
。当用户触摸视图时,会触发 intent 并广播
TOAST_ACTION
。此广播会被
StackWidgetProvider
类的onReceive()
方法拦截,并且微件会针对触摸的视图显示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 说明了使用集合的微件中的更新流程。图中显示了微件代码如何与 RemoteViewsFactory
交互,以及您如何触发更新:
使用集合的微件可以为用户提供最新内容。例如,Gmail 微件可为用户提供收件箱的快照。要做到这一点,请触发 RemoteViewsFactory
和集合视图以提取和显示新数据。
为此,请使用 AppWidgetManager
调用 notifyAppWidgetViewDataChanged()
。此调用会导致对 RemoteViewsFactory
对象的
onDataSetChanged()
方法,这样您便可以提取任何新数据。
您可以在 onDataSetChanged()
回调中同步执行处理密集型操作。可以保证您会在从 RemoteViewsFactory
获取元数据或视图数据之前完成此调用。您还可以在 getViewAt()
方法中执行处理密集型操作。如果此调用需要很长时间,则加载视图(由
RemoteViewsFactory
对象的
getLoadingView()
方法 - 显示在集合视图的相应位置
直到返回结果。
使用 RemoteCollectionItem 直接传递集合
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() );