androidappwidget开发总结
Android AppWidget开发
从MVC结构上来说,AppWidget是Launcher上的⼀个View,AppWidgetManager 是它的controller,client package(如com.baidu.searchbox)是它的model。
在client package中,AppWidgetProvider⽤来提供AppWidget的⽣命周期响应事件,AppWidgetProviderInfo⽤来提供AppWidget的初始layout id等信息,AppWidget Configuration⽤来提供AppWidget的配置界⾯。
AppWidgetManager通过它的updateAppWidget⽅法驱动AppWidget的View进⾏UI更新。⽽AppWidget⼜通过RemoteViews 来获取client package提供的UI更新信息。
中国电信网上营业厅缴费由于Launcher与client package通讯属于IPC,所以,⼀般都使⽤AlarmManager 来实现AppWidget的定期更新。
1AppWidgetProvider
1.1本质:
⼀个可以接收ACTION_APPWIDGET_UPDATE、ACTION_APPWIDGET_ENABLED、ACTION_APPWIDGET_DELETED 、以及ACTION_APPWIDGET_DISABLED的broadcast receiver。这些action对应了AppWidget的更新通知和⽣命周期,即onUpdate、onEnabled、onDeleted、onDisabled。
使⽤⽅法:
与其它静态静态注册的receiver⼀样,在manifest中添加声明,并在代码中定义。
1.2注意事项:
1.manifest声明处必须显式添加接收ACTION_APPWIDGET_UPDATE的intent
filter,否则⽆法在widget列表中到该widget。
2.由于它是个broadcast receiver,所以只在onReceive⽅法中才被视为
foreground组件(被系统杀死的可能性最⼩的组件),离开了该⽅法,就
相当于onDestroy后的Activity,是个空组件,所以不要在其中执⾏异步
操作,如sendMessage或者另开线程。
的。如果需要执⾏耗时的操作,最好使⽤service来另开线程执⾏。
4.⽣命周期(onEnabled、onUpdate、onDeleted、onDisabled)其实都是在
onReceive中执⾏。
系统设置改变等场景触发。它的本质是将widget的UI重置为初始状态
后(AppWidgetProviderInfo中的initialLayout),提供给应⽤程序⼀个更新
UI的机会(调⽤AppWidgetManager的updateAppWidget⽅法)。
2AppWidgetProviderInfo
2.1本质:
Widget的基本设置信息,包括区域⼤⼩、initialLayout以及配置界⾯等,与AppWidgetProvider⼀⼀对应。Android3.0后增加了previewImage项(此项必须设置,否则在3.0以上系统上看不到预览图)。
使⽤⽅法:
定义成⼀个xml,放在res/xml⽬录中,并在manifest中以meta的形式声明在AppWidgetProvider⾥,否则widget列表中也⽆法到该widget。
2.2注意事项:
1.Widget执⾏onUpdate之前,都会根据AppWidgetProviderInfo中的
initialLayout来重置UI。因此,尤其在有AppWidget Configuration的widget
中,initialLayout最好使⽤另⼀种UI形式。如时钟widget,initialLayout
设为“正在加载中”的界⾯,⽽不是默认为模拟时钟或者数字时钟,以
免在widget触发onUpdate时,出现数字时钟变为模拟时钟(或者模拟
时钟变为数字时钟)的情况,造成短暂的混乱。
2.AppWidgetProviderInfo由launcher解析后放⼊⾃⼰的进程中,并只能在
重新安装应⽤程序后根据AppWidgetProvider的meta重新解析并更新(参
考AppWidgetService.java中的updateProvidersForPackageLocked⽅法)。
如果该AppWidgetProvider在新版中不复存在,那么
AppWidgetProviderInfo中的layout id就不会更新,如果在新版中不将该
id值固定(在l中声明,使ADT编译资源时避开使⽤该id值),很可能会与另⼀个layout id重合,造成UI混乱。
3AppWidget Configuration
3.1本质:
⼀个Activity,⽤来给同类widget(即AppWidgetProvider相同)的不同实例
国庆节的来历和习俗(appWidgetId不同)配置不同的UI。原理是在widget添加时,放弃执⾏本次onUpdate,⽽是执⾏startActivityForResult,将更新UI的机会交给Activity (调⽤AppWidgetManager的updateAppWidget
⽅法即可)。
使⽤⽅法:
2022年立春是几点
在AppWidgetProviderInfo中加⼊configure声明,并在manifest声明该activity 处加上
android.appwidget.action.APPWIDGET_CONFIGURE动作。
3.2注意事项:
返回RESULT_OK并在intent中设置EXTRA_APPWIDGET_ID,才能通知系统哪个widget配置成功。如果取消配置(如按back键),则返回RESULT_CANCELED。
4RemoteViews
4.1本质:
⼀个Parcelable,⽤来将UI信息从本地应⽤程序传送到launcher中,与实体View可⼀⼀对应,但⽀持的种类不全,参考API⽂档。
使⽤⽅法:
直接根据AppWidgetProvider和AppWidgetId来构造⼀个属于某个widget的RemoteViews对象。通过AppWidgetManager的updateAppWidget,并传⼊该RemoteViews对象,即可完成对该widget的UI更新。
4.2注意事项:
1.在Android3.0以前,widget更新⽅法会缓存UI,所以,如果想让同类
widget的不同的实例显⽰不同的内容,最好对该RemoteViews上的所有
subViews全部进⾏更新,否则会导致混乱。Android3.0以后,提供了⼀
种不缓存UI的更新⽅法。
2.Widget上的动画效果,可以⽤viewgroup的layoutAnimation属性来实现。
如果想多次使⽤动画,可以借助RemoteViews的removeAllViews和
addViews⽅法,使得新加⼊的viewgroup执⾏layout,从⽽触发动画。
3.如果想实现更复杂的UI效果,但是RemoteViews中未提供该⽅法(⽐如
使⽤个性字体),不妨将view换成ImageView,在将复杂的UI内容以
Bitmap的形式传给RemoteViews。RemoteViews size有限,如果Bitmap
超⼤,则可使⽤setImageViewUri,以contentProvider URI的形式传给
RemoteViews。
5AlarmManager
5.1本质:
系统的⼀个常驻Service,应⽤程序使⽤PendingIntent向它发起注册,之后它会在规定的时间投递PendingIntent中指定的broadcast。由于它是系统的进程,并常驻内存,所以可⽆视应⽤进程的存活状态,通过投递broadcast 消息激活receiver。
池子退出吐槽大会使⽤⽅法:
参考API⽂档。
5.2注意事项:
1.向AlarmManager发起注册时,AlarmManager会通过intent的filterEquals
规则来⽐对已有注册的PendingIntent,如果和某PendingIntent⽐对返回
结果为相同,则只是改变该PendingIntent注册的schedule,并丢弃新的
PendingIntent。⽽filterEquals⽐对是⽆视extras的,所以会导致新的extras
被丢弃。因此,如果想覆盖原有注册的PendingIntent,并传递新的数据,
可使⽤intent的data来解决。
2.AlarmManager Service监听了PACKAGE_RESTART的⼴播,在接收到该⼴
播的时候会清楚该package注册的所有AlarmManger PendingIntent。⽽在
奋不顾身到全身而退应⽤程序的清除数据操作时,也会发送该⼴播,从⽽导致执⾏完清除数
据的操作后,该程序注册的所有AlarmManager都停⽌运作。
6Sprint22总结注意事项:复仇者联盟巴顿
1.安装到sd卡的应⽤⽆法加载widget
因为widget是在启动的时候加载的,⽽SD卡是在启动以后加载的,有可能导致widget需要加载的时候SD卡还没有载⼊系统,这样就会导致widget的加载失败,⽽widget的机制导致其不会再次加载,所以禁⽌安装到SD卡上的应⽤开启widget功能。
2.Widget的刷新
最好不使⽤android:updatePeriodMillions,因为1:这个时间间隔有最⼤1⼩时的限制2:不能保证系统⼀定能按照设定的时间进⾏onUpdate的调⽤,因为系统要考虑到电量、资源等问题。因此⼀定要实现⾃⼰的刷新机制,使⽤AlarmManager⾃⼰定更新逻辑。
3.widget布局原始⼤⼩minWidth、minHeight的设置
主要⽤于launcher计算显⽰⼏个cell,如果此⼤⼩设置超出luancher的显⽰范围,会导致⽆法加载widget。关于launcher的每个cell的宽⾼没有⼀个标准,每个rom 都可能不⼀样,适配有难度,⽆法根据分辨率进⾏。最⼤范围的适配⽅式是计算已知的luancher cell的Size,假设widget为4X2,launcher cell⼤⼩见下表,则width
应该取⼀个⼤于3个cell⼩于4个cell的值,这样launcher在计算的时候会⾃动
那么launcher2在计算的时候会认为是5个cell,超出laundher横向的最⼤cell 数,那么该widget会被系统认为是错误的,⽆法加载。⽬前适配最好的cell Size 是72.5dp×59.5dp(经验值,综合了较多的奇葩launcher)