AppWidgetProvider的本质是一个广播接收者,如下:
public class AppWidgetProvider extends BroadcastReceiver
说道广播接收者,那么它的工作原理应该是接收到对应的广播后会去调用其onReceive方法。接下来就来看它的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);
}
}
}
}
从上述源码中可以看出其逻辑近似于switch,APPWidgetProvider 会自动比对广播的 Action,从而分发广播,也就是分情况调用 onUpdate,onEnabled,onDisabled,onDeleted等方法。而这几种方法的调用时机如下:
1.定义小工具的界面
和创建布局文件一样,在res/layout/目录下新建一个xml文件即可,名称和内容均可自定义。这里只是简单的添加了一个ImageView.
2.定义小工具的配置信息
在res/xml/目录下新建一个xml文件,名称可以自定义,这里新建了一个appwidget_info.xml:
这里只用到了最基本的最小宽高属性以及刷新频率,其中86400000单位是ms即24小时,也就是一天一次。除此之外,它还支持一些其他的属性,如下:
Widget
的一些配置,该 Activity 是可选的,如果不需要可以不进行声明3. 定义小工具的实现类
这个类需要继承AppWidge Provider,代码如下:
public class MyAppWidgetProvider extends AppWidgetProvider {
private static final String TAG = "MyAppWidgetProvider";
public static final String CLICK_ACTION = "com.appwidget.action.CLICK";
public MyAppWidgetProvider() {
super();
}
@Override
public void onReceive(final Context context, Intent intent) {
super.onReceive(context, intent);
Log.d(TAG, "onReceive: ");
if(intent.getAction().equals(CLICK_ACTION)){//如果是自己的Action
new Thread(new Runnable() {
@Override
public void run() {
Bitmap srcBitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.timg);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
//旋转
for(int i=0;i<37;i++){
float degree = (i*10)%360;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget);
//设置旋转后的图片
remoteViews.setImageViewBitmap(R.id.iv_icon,rotateBitmap(srcBitmap,degree));
Intent intentClick = new Intent();
intentClick.setAction(CLICK_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0,intentClick,0);
remoteViews.setOnClickPendingIntent(R.id.iv_icon,pendingIntent);//设置点击事件监听
appWidgetManager.updateAppWidget(new ComponentName(context,MyAppWidgetProvider.class),remoteViews);
SystemClock.sleep(30);
}
}
}).start();
}
}
/**
* 每次桌面小工具更新时都会调用一次该方法
* */
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
final int counter = appWidgetIds.length;
for(int i = 0;i
上面的代码实现了一个简单的桌面小工具,该小工具展示一张图片,并且点击它之后,这个图片会旋转一周。当这个桌面小工具被添加到桌面后,会通过 RemoteViews 来加载布局文件,而当桌面小工具被单击之后的旋转效果则是通过不断的更新RemoteViews 来实现的。
4.在AndroidManifest.xml文件中声明该桌面小工具、然后动态注册小工具的实现类(广播接收者)
MyAppWidgetProvider appWidgetProvider = new MyAppWidgetProvider();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MyAppWidgetProvider.CLICK_ACTION);
registerReceiver(appWidgetProvider,intentFilter);
其中 AndroidManifest 中的 action 是桌面小工具的标识,是系统规范,如果不加那么这个 receiver 则不是一个桌面小工具,无法在手机的小工具列表中找到它。