杀手的方式显示一个列表的项目在Android收集小部件

    在早期版本的Android中,应用程序小部件只能显示像TextViewImageView等。但是,如果我们想在小部件中显示项目列表,该怎么办呢?例如,显示整个下周的温度信息列表。Android 3.0中引入的集合小部件提供了额外的好处。集合小部件支持列表视图显示数据表格而且StackView布局。

    今天,我将帮助您理解收集小部件是如何工作的。我们将为Todo应用程序构建一个应用程序小部件。集合小部件将用于显示待处理任务的列表。

    我假设你已经知道如何制作一个基本的应用程序小部件。如果没有,请参考<一个href="//www.shaoxingby.com/how-to-code-an-android-widget/">这篇文章当您准备好构建自己的集合小部件时再回来。

    开始

    请下载启动器项目代码<一个href="https://github.com/indiandollar/CollectionWidgetTutorial-Starter">在这里我们将以此为基础。

    代码已经实现了一个基本的小部件,我们将在同一个项目中创建一个集合小部件。基本小部件显示挂起任务的数量,集合小部件将显示完整的列表。要创建一个集合小部件,除了基本组件外,还需要两个主要组件:

    • RemoteViewsService
    • RemoteViewsFactory

    让我们来了解这些组件的作用。

    使用RemoteViewsFactory

    RemoteViewsFactory在小部件的上下文中充当适配器。适配器用于将集合项(例如,ListView项或GridView项)与数据集连接起来。
    让我们将这个类添加到项目中。创建一个新的Java类,并命名它MyWidgetRemoteViewsFactory,并将其设置为实现该类RemoteViewsService。RemoteViewsFactory

    公共MyWidgetRemoteViewsFactory实现了RemoteViewsServiceRemoteViewsFactory私人上下文mContext私人光标mCursor公共MyWidgetRemoteViewsFactory上下文applicationContext意图意图mContextapplicationContext@Override公共无效onCreate@Override公共无效onDataSetChanged如果mCursor! =mCursor关闭最后identityToken粘结剂clearCallingIdentityUriuri合同PATH_TODOS_URImCursormContextgetContentResolver查询uri合同_ID+“DESC”粘结剂restoreCallingIdentityidentityToken@Override公共无效onDestroy如果mCursor! =mCursor关闭@Override公共intgetCount返回mCursor= =?0mCursorgetCount@Override公共RemoteViewsgetViewAtint位置如果位置= =AdapterViewINVALID_POSITION||mCursor= =||mCursormoveToPosition位置返回RemoteViews房车RemoteViewsmContextgetPackageNameR布局collection_widget_list_item房车setTextViewTextRidwidgetItemTaskNameLabelmCursorgetString1返回房车@Override公共RemoteViewsgetLoadingView返回@Override公共intgetViewTypeCount返回1@Override公共getItemIdint位置返回mCursormoveToPosition位置?mCursorgetLong0位置@Override公共布尔hasStableIds返回真正的

    在上面的代码中,MyWidgetRemoteViewsFactory方法中的一些方法RemoteViewsFactory类:

    • onCreate在第一次创建应用程序小部件时调用。
    • onDataSetChanged每当应用程序小部件更新时调用。
    • getCount返回游标中的记录数。(在本例中,需要在应用程序小部件中显示的任务项的数量)
    • getViewAt处理所有的处理工作。它返回一个RemoteViews对象,在我们的例子中是单个列表项。
    • getViewTypeCount返回视图类型的数量列表视图.在本例中,每个视图中都有相同的视图类型列表视图所以我们返回1在那里。

    使用RemoteViewsService

    的主要目的RemoteViewsService返回一个RemoteViewsFactory对象,该对象进一步处理用适当的数据填充小部件的任务。这门课没有太多内容。

    创建一个名为MyWidgetRemoteViewsService扩展类RemoteViewsService

    公共MyWidgetRemoteViewsService扩展RemoteViewsService@Override公共RemoteViewsFactoryonGetViewFactory意图意图返回MyWidgetRemoteViewsFactorygetApplicationContext意图

    与android中的所有其他服务一样,我们必须在manifest文件中注册这个服务。

    <服务android:的名字.AppWidget.MyWidgetRemoteViewsServiceandroid:许可android.permission.BIND_REMOTEVIEWS>服务>

    注意特殊权限android.permission.BIND_REMOTEVIEWS.这让系统绑定你的服务,为每一行创建小部件视图,并防止其他应用程序访问小部件的数据。

    启动RemoteViewsService

    既然我们已经设置了附加组件,现在是时候创建WidgetProvider打电话给RemoteViewsService

    在AppWidget包中创建一个新类并命名它CollectionAppWidgetProvider

    @Override公共无效onUpdate上下文上下文AppWidgetManagerappWidgetManagerintappWidgetIdsintappWidgetIdappWidgetIdsRemoteViews的观点RemoteViews上下文getPackageNameR布局collection_widget意图意图意图上下文MyWidgetRemoteViewsService的观点setRemoteAdapterRidwidgetListView意图appWidgetManagerupdateAppWidgetappWidgetId的观点

    创建小部件布局

    现在在中创建一个新的资源文件res / xml给它命名collection_widget.xml

    在这个文件中,我们定义小部件设置,比如小部件应该使用哪个布局文件,并添加预览图像以获得更好的用户体验。

    <appwidget-providerxmlns:安卓http://schemas.android.com/apk/res/androidandroid:minWidth40 dpandroid:minHeight40 dpandroid:updatePeriodMillis864000android:previewImage@drawable / simple_widget_previewandroid:initialLayout@layout / collection_widgetandroid:resizeMode水平|垂直android:widgetCategoryhome_screen>appwidget-provider>

    再创建一个资源文件,但这次在res /布局给它命名collection_widget.xml
    在这个文件中,我们定义了要在集合小部件中显示的内容的布局。我们会在上面有一个标题,然后列表视图在底部显示任务列表。

    <LinearLayoutxmlns:安卓http://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:背景@color / colorWhitexmlns:工具http://schemas.android.com/toolsandroid:取向垂直><FrameLayoutandroid:layout_widthmatch_parentandroid:layout_heightwrap_content><TextViewandroid:layout_widthmatch_parentandroid:id@ + id / widgetTitleLabelandroid:文本@string / title_collection_widgetandroid:输入textColor@color / colorWhiteandroid:背景@color / colorPrimaryandroid:textSize18 dpandroid:重力中心android:textAllCaps真正的android:layout_height@dimen / widget_title_min_height>TextView>FrameLayout><LinearLayoutandroid:layout_widthmatch_parentandroid:layout_heightwrap_content><列表视图android:id@ + id / widgetListViewandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:背景@color / colorWhiteandroid:dividerHeight1 dpandroid:分频器继续工具:@layout / collection_widget_list_item>列表视图>LinearLayout>LinearLayout>

    我们需要再创建一个文件res /布局定义每个列表项的布局。

    创建这个文件并命名它collection_widget_list_item.xml

    <LinearLayoutxmlns:安卓http://schemas.android.com/apk/res/androidandroid:取向水平android:layout_widthmatch_parentandroid:paddingLeft@dimen / widget_listview_padding_xandroid:paddingRight@dimen / widget_listview_padding_xandroid:paddingStart@dimen / widget_listview_padding_xandroid:paddingEnd@dimen / widget_listview_padding_xandroid:minHeight@dimen / widget_listview_item_heightandroid:weightSum2android:id@ + id / widgetItemContainerandroid:layout_heightwrap_content><TextViewandroid:id@ + id / widgetItemTaskNameLabelandroid:layout_widthwrap_contentandroid:重力开始android:layout_weight1android:输入textColor@color /文本android:layout_gravitycenter_verticalandroid:layout_heightwrap_content>TextView>LinearLayout>

    现在运行应用程序,您应该能够看到小部件中填充了待办事项。(请确保重新安装应用程序以查看更改。你也可以禁用Android Studio中的即时运行选项)。

    手动更新小部件

    逻辑是这样的:每当您创建一个新的todo项时,您必须发送一个Broadcast到WidgetProvider
    中定义一个新方法CollectionAppWidgetProvider类。

    公共静态无效sendRefreshBroadcast上下文上下文意图意图意图AppWidgetManagerACTION_APPWIDGET_UPDATE意图setComponentComponentName上下文CollectionAppWidgetProvider上下文sendBroadcast意图

    然后重写onReceive方法中的CollectionAppWidgetProvider类,

    @Override公共无效onReceive最后上下文上下文意图意图最后字符串行动意图getAction如果行动=AppWidgetManagerACTION_APPWIDGET_UPDATE//刷新所有小部件AppWidgetManagerAppWidgetManagergetInstance上下文ComponentNamecnComponentName上下文CollectionAppWidgetProvidernotifyAppWidgetViewDataChangedgetAppWidgetIdscnRidwidgetListView超级onReceive上下文意图

    创建新的todo任务时,调用sendRefreshBroadcast中定义的方法CollectionAppWidgetProvider类。

    MainActivity,修改addTodoItem相应的方法。

    一个runOnUiThread可运行的@Override公共无效运行烤面包makeTextmContext“新任务创建”烤面包LENGTH_LONG显示getTodoList//这将发送广播来更新应用程序小部件CollectionAppWidgetProvidersendRefreshBroadcastmContext

    小部件中的事件处理

    在小部件中,顶部有一个标题,底部有一个列表视图。因此,当用户单击标题时,我们启动应用程序。当在列表视图中单击单个项目时,我们启动details活动。在我们的todo应用中,细节活动可能没有那么有用,但让我们做它来理解这个概念。

    在单个视图上单击事件

    将单击事件添加到视图,如TextViewImageView等都很简单。的更新代码onUpdate方法。

    @Override公共无效onUpdate上下文上下文AppWidgetManagerappWidgetManagerintappWidgetIdsintappWidgetIdappWidgetIdsRemoteViews的观点RemoteViews上下文getPackageNameR布局collection_widget//点击事件处理程序的标题,启动应用程序时,用户点击标题意图titleIntent意图上下文MainActivityPendingIntenttitlePendingIntentPendingIntentgetActivity上下文0titleIntent0的观点setOnClickPendingIntentRidwidgetTitleLabeltitlePendingIntent意图意图意图上下文MyWidgetRemoteViewsService的观点setRemoteAdapterRidwidgetListView意图appWidgetManagerupdateAppWidgetappWidgetId的观点

    这里的想法类似于我们如何在应用程序中添加点击事件。但是由于小部件在不同的上下文中运行,我们需要通过PendingIntent

    点击事件列表视图项目

    添加点击事件列表视图项目并不像设置那么简单setOnItemClickListener列表视图对象。它需要一些额外的步骤。

    首先,您需要为PendingIntent.将以下代码添加到onUpdate方法CollectionAppWidgetProvider类后views.setRemoteAdapter (R.id。widgetListView,意图);

    //模板处理每个项目的点击监听器意图clickIntentTemplate意图上下文DetailsActivityPendingIntentclickPendingIntentTemplateTaskStackBuilder创建上下文addNextIntentWithParentStackclickIntentTemplategetPendingIntent0PendingIntentFLAG_UPDATE_CURRENT的观点setPendingIntentTemplateRidwidgetListViewclickPendingIntentTemplate

    为每一个列表视图我们正在推出的项目DetailsActivity它将简单地显示作为额外内容发送的任务描述。

    然后每次填写这个模板一个新的RemoteViews对象创建的RemoteViewsFactory
    将以下代码添加到getViewAt方法MyWidgetRemoteViewsFactory类。

    意图fillInIntent意图fillInIntentputExtraCollectionAppWidgetProviderEXTRA_LABELmCursorgetString1房车setOnClickFillInIntentRidwidgetItemContainerfillInIntent

    中定义的挂起意图模板CollectionAppWidgetProvider类。注意,我们想让整行都是可点击的,所以我们在根元素上设置了click监听器collection_widget_list_item.xml

    结论

    在本文中,我试图帮助解决初学者通常面临的最常见问题。如果你有任何问题,或者任何方法不适合你,请在下面的评论中告诉我。

    您可以下载完整的工作代码<一个href="https://github.com/indiandollar/CollectionWidgetTutorial-TodoApp">在这里

    可访问的拖放与多个项目"></一个><div class= 可访问的拖放与多个项目<一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/brothercake/">詹姆斯•爱德华兹
    jQuery选择器首先选择x个特定类的项"></一个><div class= jQuery选择器首先选择x个特定类的项<一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/sdeering/">山姆-迪尔岭
    自动内存管理器:Android智能任务杀手"></一个><div class= 自动内存管理器:Android智能任务杀手<一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/mkwan/">迈克尔关颖珊
    如何编写Android小部件代码"></一个><div class= 如何编写Android小部件代码<一个类="文本-sm text-gray-400" href="//www.shaoxingby.com/author/bcooper/">布鲁斯·库珀
    Baidu