AppWidget

Android中的AppWidget也就是“窗口小部件”,实现了桌面(Launcher)上显示控件的机制,并能响应用户的点击操作。而实际上,提供显示的UI元素和对点击事件的响应是由Remote端的AppWidgetProvider实现;具体显示是Local的AppWidgetHost通过AppWidgetHostView实现。AppWidgetHost、AppWidgetProvider与AppWidgetService和AppWidgetManager按照特有的机制组合在一起,才能完整的实现AppWidget机制。本文简要描述AppWidget系统框架,并对这里的组成元素做简要的阐述。后续的文章会结合关键典型场景,对其中的具体角色着重描述。

AppWidget实现Remote端提供UI元素;Local端具体显示。AppWidgetHost在AppWidget系统中是Local端;AppWidgetProvider端是Remote端。AppWidgetHost和AppWidgetProvider直接或通过IAppWidgetService或间接的通过AppWidgetManager,与AppWidgetService实现交互。AppWidgetService是所有元素的总管,负责协调其他各个部分。


AppWidgetHost通过IAppWidgetService利用Binder机制实现与系统进程中的AppWidgetService通信;
AppWidgetHost有IAppWidgetHost(通过Callbacks)的实现,并在AppWidgetHost.startListening()中注册到AppWidgetService中,实现当Remote端的数据有更新时,通过IAppWidgetHost.updateAppWidget()通知AppWidgetHost更新本地的显示;或者当Remote端的Provider改变时通知AppWidgetHost。
AppWidgetHost创建本地AppWidgetHostView时,会以AppWidgetId和AppWidgetHostView加入mViews: HashMap<Interger,AppWidgetHostView>
 
AppWidgetProvider是AppWidget的Remote端内容提供方,并能注册响应其所提供内容的某个View被点击时,响应的Intent。
AppWidgetProvider是一个抽象类,实现类需要实现抽象方法onUpdate() / onDeleted()/ onEnabled()和onDisabled()。这是AppWidgetProvider的一个模板模式实现,要求AppWidgetProvider的实现者:
 在AndroidManefest.xml中声明这个AppWidgetProvider是"android.appwidget.action.APPWIDGET_UPDATE"的Receiver,这样AppWidgetProvider作为一个BroardcastReceiver才能接收到AppWidgetService发出的消息。而AppWidgetService查询系统中已经安装了哪些AppWidgetProvider也是通过查询这个接收者的Intent来的实现。所以如果没有这个Receiver,安装的Provider里就没有这个Provider,亦即,未加入到AppWidget系统中。
 另外,这个Receiver的meta-data的name指定为“android.appwidget.provider”;resource中用xml定义appwidget-provider内的各种属性。这些属性按包被安装时,检索出来赋给AppWidgetProviderInfo。


三、AppWidget各个角色的部署

AppWidgetService运行于三个各自不同的进程空间:
 AppWidgetService运行于system_process进程;
 AppWidgetHost运行于自己的进程空间,典型的桌面上的AppWidgetHost运行于Launcher中;
 AppWidgetProvider也是运行于自己的进程空间,典型的如“电量控制”这个AppWidgetProvider运行于Settings中。
AppWidgetHost和AppWidgetProvider要用到AppWidgetService的服务时,用Binder机制通过IAppWidgetService实现。AppWidgetService通过IAppWidgetHost通知AppWidgetHost;AppWidgetService通过发Broadcast通知AppWidgetProvider。

要实现一个AppWidgetProvider,需要:
实现AppWidgetProvider的子类,并至少override onUpdate()方法[非必须,但是如果不这样做,该AppWidgetProvider就没有提供任何内容,也就不是AppWidgetProvider了];
在AndroidManifest.xml中,声明上述的AppWidgetProvider的子类是一个Receiver,并且:
该Receiver的intent-filter的Action必须包含“android.appwidget.action.APPWIDGET_UPDATE”;
该Receiver的meta-data为“android.appwidget.provider”,并用一个xml文件来描述布局属性。


RemoteViews中保存Remote端的mPackage和mLayoutId;并用mActions:ArrayList<RemoteViews.Action>保存各种Action。
mPackage和mLayoutId是在构造RemoteViews时传进去的[上文图中的seq#1];
mActions是设置各种Remote端的响应Intent以及图形元素的时候,保存到相应的Action中,然后把Action加入到这里保存的;
mLayoutId里的各种控件通过setTextViewText()/ setImageViewResource() / setProgressBar(),等函数在remote端设置的。这些方法再调用setType() [Type可为Boolean / Byte / Short / Int/ Long / Char / String / Uri / Bitmap/ Bundle, etc]保存到ReflectionAction中。
SetOnClickPendingIntent是用来在local端用户点击viewId时,发出pendingIntent通知的。在SetOnClickPendingIntent的构造方法中保存viewId和pendingIntent。
ReflectionAction用来在local端显示时,通过Reflect机制执行获得Remote端资源的。在ReflectionAction的构造方法中保存viewId,methodName,type以及value。
ViewGroupAction和SetDrawableParameters也是RemoteViews.Action的子类,在这个场景中并未用到,基本原理相似,读者可自行分析。


.      获取RemoteViews里Remote端(AppWidgetProvider)的packageName和layoutId,通过packageName创建远端的context——remoteContext。[Seq#1~ 6]
2.      通过RemoteViews的apply()方法,真正开始执行侦听Click操作的动作;通过远端Layout获得本地使用的View。[Seq#7~ 20]
2.1.  克隆一个本地的LayoutInflater;[Seq#8]
2.2.  用克隆出的LayoutInflater对remote端的layoutId执行Inflate,获得Layout所描述的View的Hierarchy,亦即后面用到的rootView;[Seq#9~ 10]
2.3.  对2.2中获得的view执行performApply。[Seq#11~ 19]
performApply()对所有mActions中的Action都执行apply()操作。这样,
2.3.1 对于setOnClickPendingIntent来说,[Seq#12~ 15]
 通过rootView(2.2获得的Remote端的Layout的总的View)的findViewById(viewId),找到要侦听的View;[Seq#13]
 对找到的要侦听的View设置Click的Listener。[Seq#14]
2.3.2对于ReflectionAction来说,[Seq#16~ 19]
 通过rootView(2.2获得的Remote端的Layout的总的View)的findViewById(viewId),找到要设置内容的对象View;[Seq#17]
 然后通过Reflect机制,执行View实现类里的方法(比如这里是setImageResource()),把相应的资源的Id设置给它. [Seq#18]
3.      把获得的View加入到本地的View系统中。[Seq#21]
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值