开发 AppWidget
迪丽瓦拉
2024-02-06 16:39:43
0

参考 https://www.cnblogs.com/joy99/p/6346829.html

AppWidgetProvider

AppWidgetProvider,其本质 BroadcastReceiver。用户用这个类去创建自己的 widget AppWidgetProvider 除构造方法外,总共只有下面这些方法:

AppWidgetProvider::onEnable

当小部件第一次被添加到桌面时回调该方法,可添加多次,但只在第一次调用。对用广播的 Action 为 ACTION_APPWIDGET_ENABLE。

AppWidgetProvider::onUpdate

当小部件被添加时或者每次小部件更新时都会调用一次该方法,配置文件中配置小部件的更新周期 updatePeriodMillis,每次更新都会调用。对应广播 Action 为:ACTION_APPWIDGET_UPDATE 和 ACTION_APPWIDGET_RESTORED 。

AppWidgetProvider::onDisabled

当最后一个该类型的小部件从桌面移除时调用,对应的广播的 Action 为 ACTION_APPWIDGET_DISABLED。

AppWidgetProvider::onDeleted

每删除一个小部件就调用一次。对应的广播的 Action 为: ACTION_APPWIDGET_DELETED 。
AppWidgetProvider::onRestored : 当小部件从备份中还原,或者恢复设置的时候,会调用,实际用的比较少。对应广播的 Action 为 ACTION_APPWIDGET_RESTORED。
AppWidgetProvider::onAppWidgetOptionsChanged
当小部件布局发生更改的时候调用。对应广播的 Action 为 ACTION_APPWIDGET_OPTIONS_CHANGED。
在 onReceive() 方法中,对上述事件进行分发

public void onReceive(Context context, Intent intent) {// Protect against rogue update broadcasts (not really a security issue,// just filter bad broacasts out so subclasses are less likely to crash).String action = intent.getAction();if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {Bundle extras = intent.getExtras();if (extras != null) {int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);if (appWidgetIds != null && appWidgetIds.length > 0) {this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);}}} else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {Bundle extras = intent.getExtras();if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) {final int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);this.onDeleted(context, new int[] { appWidgetId });}} else if (AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED.equals(action)) {Bundle extras = intent.getExtras();if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)&& extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS)) {int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);Bundle widgetExtras = extras.getBundle(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);this.onAppWidgetOptionsChanged(context, AppWidgetManager.getInstance(context),appWidgetId, widgetExtras);}} else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {this.onEnabled(context);} else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {this.onDisabled(context);} else if (AppWidgetManager.ACTION_APPWIDGET_RESTORED.equals(action)) {Bundle extras = intent.getExtras();if (extras != null) {int[] oldIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);int[] newIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);if (oldIds != null && oldIds.length > 0) {this.onRestored(context, oldIds, newIds);this.onUpdate(context, AppWidgetManager.getInstance(context), newIds);}}}
}

继承 AppWidgetProvider 对 AppWidget 进行定制

用户可以通过继承 AppwidgetProvider 的一个或者几个方法来定义自己的 widget 以及控制 widget 的更新

package com.example.joy.remoteviewstest;import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.widget.RemoteViews;/*** Implementation of App Widget functionality.*/
public class MyAppWidgetProvider extends AppWidgetProvider {static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,int appWidgetId) {CharSequence widgetText = context.getString(R.string.appwidget_text);  // Construct the RemoteViews objectRemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_app_widget_provider);views.setTextViewText(R.id.appwidget_text, widgetText);// Instruct the widget manager to update the widgetappWidgetManager.updateAppWidget(appWidgetId, views);}@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {// There may be multiple widgets active, so update all of themfor (int appWidgetId : appWidgetIds) {updateAppWidget(context, appWidgetManager, appWidgetId);}}@Overridepublic void onEnabled(Context context) {// Enter relevant functionality for when the first widget is created}@Overridepublic void onDisabled(Context context) {// Enter relevant functionality for when the last widget is disabled}
}

重写 AppWidgetProvider::onUpdate 方法的逻辑,对 AppWidget 的样式进行定义,具体实现思路如下:

  1. 新建一个 RemoteViews 对象,为其绑定对应布局文件
  2. 通过 AppWidgetProvider::updateAppWidget 方法将一个 RemoteViews 对象传递给 AppWidgetProvider,由 AppWidgetProvider 实现后续的逻辑
    在 AndroidManifest 中注册 AppWidgetProvider

AppWidgetProvider,其本质 BroadcastReceiver,需要在 AndroidManifest 中注册



名为 android.appwidget.action.APPWIDGET_UPDATE 的 action 将作为系统识别的表示,系统将通过 PackageManager 扫描该 action,并根据 meta-data 中 android.appwidget.provider 指定的 xml 文件里的配置去生成 AppWidget
该配置形如




这里配置了一些小部件的基本信息,常用的属性有 initialLayout 就是小部件的初始化布局, minHeight 定义了小部件的最小高度,previewImage 指定了小部件在小部件列表里的预览图,updatePeriodMillis 指定了小部件更新周期,单位为毫秒。更多属性,可以查看API文档。

RemoteViews

下面简单说说 RemoteViews 相关的几个类。

RemoteViews

RemoteViews,从字面意思理解为它是一个远程视图。是一种远程的 View,它在其它进程中显示,却可以在另一个进程中更新。RemoteViews 在 Android 中的使用场景主要有:自定义通知栏和桌面小部件。
在RemoteViews 的构造函数中,第二个参数接收一个 layout 文件来确定 RemoteViews 的视图;然后,我们调用RemoteViews 中的 set 方法对 layout 中的各个组件进行设置,例如,可以调用 setTextViewText() 来设置 TextView 组件的文本。
前面提到,小部件布局文件可以添加的组件是有限制的,它可以支持的 View 类型包括四种布局:FrameLayout、LinearLayout、RelativeLayout、GridLayout 和 13 种View: AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper、ViewSub。注意:RemoteViews 也并不支持上述 View 的子类。
RemoteViews 提供了一系列 setXXX() 方法来为小部件的子视图设置属性。具体可以参考 API 文档。

RemoteViewsService

RemoteViewsService,是管理 RemoteViews 的服务。一般,当 AppWidget 中包含 GridView、ListView、StackView 等集合视图时,才需要使用 RemoteViewsService 来进行更新、管理。RemoteViewsService 更新集合视图的一般步骤是:

  1. 通过 setRemoteAdapter() 方法来设置 RemoteViews 对应 RemoteViewsService 。
  2. 之后在 RemoteViewsService 中,实现 RemoteViewsFactory 接口。然后,在 RemoteViewsFactory 接口中对集合视图的各个子项进行设置,例如 ListView 中的每一Item。

RemoteViewsFactory

通过RemoteViewsService中的介绍,我们知道 RemoteViewsService 是通过 RemoteViewsFactory 来具体管理 layout 中集合视图的,RemoteViewsFactory 是 RemoteViewsService 中的一个内部接口。RemoteViewsFactory 提供了一系列的方法管理集合视图中的每一项。例如:
RemoteViews getViewAt(int position)
通过getViewAt()来获取“集合视图”中的第position项的视图,视图是以RemoteViews的对象返回的。
int getCount()
通过getCount()来获取“集合视图”中所有子项的总数。

相关内容