运行结果:
左边的图是将小部件添加到桌面后,google天气中获取数据后显示出来。
中间的图是点击小部件后,显示的透明的Activity,也就是下文就所提到的相应的点击事件。
右边的图是在点击发送按钮后,刷新Widget的结果。使用的刷新方法是下文中提到的直接在外部Activity中刷新。
Widget简介
桌面部件是一种利用AppWidget框架将应用程序的某个部件放在桌面上,以便于用户快速了解信息以及操作应用程序的桌面组件,如显示天气,日历等等。
要为应用程序定义桌面部件,首先要在应用程序项目的res/xml目录下新建一个XML文件来对桌面部件进行描述,其描述的信息包括了桌面部件的桌面上所占的空间、更新的周期时间以及部件的布局文件。由于在桌面上所有组件的大小均以单元格为单位,所以这里我们要对桌面部件的最小宽度和最小高度进行描述,然后当桌面部件最终被添加到桌面上时,其大小会被设定为最接近的所占单元格数大小。
AppWidget框架是通过广播Intent的方式来对桌面部件进行控制的,所以每个桌面部件的XML文件都有一个对应的广播接收器。为了针对桌面部件不同的状态执行不同的操作,AppWidget框架提供了一个集成自BroadcastReceiver的AppWidgetProvider类。这样我们只需要在应用程序中创建一个AppWidgetProvider的子类,然后重新实现不同状态下的回调方法就可以响应AppWidget框架的控制了。
可以在AppWidgetProvider的回调方法onDeleted,onUpdate, onEnabled, onDisabled, onReceive中加入Log信息来查看调用顺序。
添加一个Widget到桌面上:
onEnabled被呼叫:按照说明,当桌面上出现第一个此Widget的实例时,此函数被呼叫。
onReceive被呼叫:onReceive,Action:android.appwidget.action.APPWIDGET_ENABLED
onUpdate被呼叫:onUpdate,Count:1,并且待更新的AppWidget数量为1
onReceive被呼叫:onReceive,Action:android.appwidget.action.APPWIDGET_UPDATE
再添加一个Widget到桌面上:
onUpdate被呼叫:onUpdate,Count:1,并且待更新的AppWidget数量仍然为1,而不是2。
onReceive被呼叫:onReceive,Action:android.appwidget.action.APPWIDGET_UPDATE
从桌面上移除一个Widget:
onDeleted:每个实例被移除时都会被呼叫
onReceive,Action:android.appwidget.action.APPWIDGET_DELETED
再从桌面上移除一个Widget:
onDeleted:仍然执行
onReceive,Action:android.appwidget.action.APPWIDGET_DELETED
onDisabled:因为是最后一个活动的实例被移除了,所以被呼叫。
onReceive,Action:android.appwidget.action.APPWIDGET_DISABLED
刷新AppWidget
1 在onUpdate()中刷新
在上述方法的实现中,如果我们要对已经添加到桌面部件进行修改,如桌面部件的周期性跟新,首先要根据桌面部件的部件文件构造一个RemoteViews对象。RemoteViews是一个描述可在其他进程运行的部件的类,其构造方法需要传入部件的布局文件以及其所在包的包名,构造好了后就可以利用RemoteViews对象对桌面部件进行修改了。桌面部件修改完毕后,最后需要利用一个AppWidgetManager对象调用updateAppWidget方法来传入修改好的RemoteViews对象。
2 直接在外部Activity中刷新
btnRefresh.setOnClickListener(new OnClickListener() {
String value =teInput.getText().toString();
RemoteViews appWidgetView = new RemoteViews(SendMsgActivity.this.getPackageName(),R.layout.widget_layout_demo);
appWidgetView.setTextViewText(R.id.tv1,value);
appWidgetView.setTextViewText(R.id.tv2,value);
AppWidgetManager.getInstance(SendMsgActivity.this)
.updateAppWidget(newComponentName(SendMsgActivity.this, AppWidgetDemo.class), appWidgetView);
});
上述代码可以直接刷新AppWidget的内容,不会触发其onUpdate().
相应点击事件
因为onUpdate是每个AppWidget被放置到桌面上时都会被呼叫的函数,所以在此函数中完成事件的关联:
Intent intent = new Intent(context,SendMsgActivity.class);
PendingIntent pendingIntent =PendingIntent.getActivity(context, 0, intent, 0);
appWidgetView.setOnClickPendingIntent(R.id.tv1,pendingIntent);
另外要注意此段代码必须要在appWidgetManager.updateAppWidget()之前,否则是不会生效的。 运行后可以点击AppWidget的第一个控件,就能呼叫指定的Activity了。
参考资料:
http://developer.android.com/guide/practices/ui_guidelines/widget_design.html
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
http://mypyg.iteye.com/blog/930072
http://ssd910.blog.163.com/blog/static/238767972010613257484/