2012-9-12
本文讲述Android中AppWidget系统的核心AppWidgetService。从AppWidgetService提供的外部接口、内部数据结构、初始化过程以及典型场景的实现等几方面来阐述。
前面讲述AppWidget的诸文中已经讲到,AndroidAppWidget系统里的Host角色和Provider角色的实例通过AppwidgetHost/ AppWidgetManager组件提供的方法参与AppWidget系统。实际AppwidgetHost/ AppWidgetManager采用AndroidAIDL方式通过IAppWidgetService与AppWidgetService交互,从而实现了运行于不同进程中的Host/Provider/Service协同运作。另外,AppWidgetHost通过实现IAppWidgetHost提供Callback给AppWidgetService,实现Provider更新时通知Host;而对Provider的通知是直接向Provider定向发广播消息[7]。
下图描述了AppWidgetService的外部接口。
图一、AppWidgetService的外部接口
AppWidgetService通过IAppWidgetService这个标准的AIDL方式向外界提供服务。
AppWidgetHost提供了Host端操作所需要的方法,而这些方式实际是通过AIDL方式调用IAppWidgetService实现的;AppWidgetManager提供了Host端和Provider端操作所需要的方法,而这些方式也是通过AIDL方式调用IAppWidgetService实现的。
下图是AppWidgetService中的数据结构。
图二、AppWidgetService内部数据结构
mInstalledProviders:ArrayList<AppWidgetService.Provider>记录所有已经安装的AppWidgetProvider【《Android中AppWidget的分析与应用:AppWidgetProvider》中已经描述了单个AppWidgetProvider被AppWidget系统所识别的过程;本文Section#3.1 (1)会描述加载所有系统中的AppWidgetProvider的过程】。其中,
mHosts: ArrayList<AppWidgetService.Host>记录AppWidgetHost信息。其中,
mAppWidgetIds:ArrayList<AppWidgetService.AppWidgetId>记录所有Provider与Host绑定的信息。其中,
现在看这些属性可能比较空泛,在后续的分析过程中再回头看这些属性的才能充分理解其含义。
AppWidgetService运行于system_process进程中,其初始化有两个过程:
在SystemServer的init2()阶段,启动ServerThread。ServerThread线程中,创建AppWidgetService实例,并加入ServiceManager中,然后执行AppWidgetService.systemReady()。
AppWidgetService.systemReady()中,执行下面三个操作:
(1)执行loadAppWidgetList(),从Android系统中查找所有已经被安装的AppWidgetProvider,解析其中的信息放到AppWidgetService.Provider中,再添加到mInstalledProviders:ArrayList<Provider>中。
void loadAppWidgetList() { PackageManager pm = mPackageManager; Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); List<ResolveInfo> broadcastReceivers =pm.queryBroadcastReceivers(intent, PackageManager.GET_META_DATA); final int N = broadcastReceivers == null ? 0 :broadcastReceivers.size(); for (int i=0; i<N; i++) { ResolveInfo ri = broadcastReceivers.get(i); addProviderLocked(ri); } }
1.检索系统中所有Intent-filter的action为AppWidgetManager.ACTION_APPWIDGET_UPDATE的Receiver,并放入broadcastReceivers:List<ResolveInfo>;[Line#2~ 6]
2.对每一个这样的Broadcast Receiver,加入到已安装AppWidgetProvider列表mInstalledProviders:ArrayList<Provider>中。[Line#8~ 12]
加入到AppWidgetProvider列表是通过addProviderLocked()实现:
boolean addProviderLocked(ResolveInfo ri) { Provider p = parseProviderInfoXml(newComponentName(ri.activityInfo.packageName, ri.activityInfo.name), ri); if(p != null) { mInstalledProviders.add(p); return true; }else { return false; } }
parseProviderInfoXml()解析meta-data中AppWidgetManager.META_DATA_APPWIDGET_PROVIDER("android.appwidget.provider")指向的xml文件所配置的Provider的配置信息,放到Provider的info:AppWidgetProviderInfo中。另外,Provider的UID也会被检索出来。
Provider被加入到mInstalledProviders:ArrayList<Provider>中。
具体AppWidgetProvider如何配置,可参看《Android中AppWidget的分析与应用:AppWidgetProvider》
(2)执行loadStateLocked(),从/data/system/appwidgets.xml文件中读取Provider、Host与Provider绑定的信息,把这些信息放入中mInstalledProviders, mHosts和mAppWidgetIds中。
下面是系统中只有Launcher上放置了一个“电量控制”AppWidget的对应的appwidgets.xml文件
<gs> <ppkg="com.android.settings" cl="com.android.settings.widget.SettingsAppWidgetProvider"/> <hpkg="com.android.launcher" id="400" /> <gid="1" h="0" p="0" /> </gs>
其中的,
下面看Section#2图二中的数据结构如何建立起来的:
对于p节点,通过packageName和className,检索步骤(1)中获得的mInstalledProviders:ArrayList<Provider>可得到具体的Provider信息。Provider暂时保存;
对于h节点,创建AppWidgetService.Host对象,并通过packageName获得uid,通过解析id获得的hostId是16进制的。Host对象加入到mHosts: ArrayList<Host>中;
对于g节点,创建AppWidgetId对象,xml解析出的id也是十六进制的,赋值给appWidgetId。通过p指向Provider的index(16进制),找到Provider,赋值给AppWidgetId.provider。通过h指向Host的index(16进制),找到Host,赋值给AppWidgetId.host。provider和host的instances都指向本AppWidgetId对象。然后把该AppWidgetId对象加入到mAppWidgetIds: ArrayList<AppWidgetId>中。
这样Provider对象、Host对象,以及与Provider的绑定关系也就分别利用mInstalledProviders:ArrayList<AppWidgetService.Provider>, mHosts: ArrayList<AppWidgetService.Host>, 和mAppWidgetIds: ArrayList<AppWidgetService.AppWidgetId>建立起来了。
(3)注册四个BroadcastReceiver:
1) Intent.ACTION_BOOT_COMPLETED
Android系统启动完成之后,AppWidgetService还需要一些初始化工作
2) Intent.ACTION_CONFIGURATION_CHANGED
Android配置信息改变
3) Intent.ACTION_PACKAGE_ADDED/Intent.ACTION_PACKAGE_REMOVED
应用被添加/删除
4) Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE / Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE
sdcard的安装与缷载
Android系统启动完成之后,会发出Intent.ACTION_BOOT_COMPLETED广播。
AppWidgetService在Intent.ACTION_BOOT_COMPLETED广播的Receiver中sendInitialBroadcasts()内处理下列事项:
检索mInstalledProviders获取所有的Provider,通过Provider.instances获得已经绑定的那些AppWidgetProvider。
对这些Provider,
上述的AppWidgetService的初始化工作是AppWidget系统初始化的一部分,还有AppWidgetHost和AppWidgetProvider的参与的初始化过程。
下面是完整的过程:
(1)AppWidgetService.systemReady()初始化
本文Section#3.1,完成:
(2)Launcher利用AppWidgetHost的startListening()注册。
AppWidgetHost构造了IAppWidgetHost对象,并通过IAppWidgetService的startListening()把Callback,HostId和RemoteViews的List传递给Service。AppWidgetService中的实现如下:
public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId, List<RemoteViews> updatedViews) { int callingUid = enforceCallingUid(packageName); synchronized (mAppWidgetIds) { Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); host.callbacks = callbacks; updatedViews.clear(); ArrayList<AppWidgetId> instances = host.instances; int N = instances.size(); int[] updatedIds = new int[N]; for (int i=0; i<N; i++) { AppWidgetId id = instances.get(i); updatedIds[i] = id.appWidgetId; updatedViews.add(id.views); } return updatedIds; } }
返回所有与该Host已经发生绑定关系的AppWidgetId。
(3)Launcher正常启动加载数据库中的AppWidget
《Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色》#3中具体描述里这一过程。
第一次开机,从default_workspace.xml中加载初始化AppWidget,并加入到数据模型中;
从数据库中读取AppWidget信息,并创建AppWidgetHostView本地显示。
(4)系统启动之后,AppWidgetService的初始化
本文Section#3.2
对所有有绑定关系的AppWidgetProvider发送Enable和Update广播,并根据配置建立周期性刷新机制。
(5)AppWidgetProvider接收到广播后都会调用onEnabled()方法和onUpdate()方法执行操作。
《Android中AppWidget的分析与应用:AppWidgetProvider》中具体描述里这一过程。
AppWidgetService接收到了appWidgetId和RemoteViews后,通过appWidgetId查找Provider与Host的绑定关系,并通过IAppWidgetHost的Callback通知Host用RemoteViews中的布局更新到AppWidgetHostView布局对象中。
这样,AppWidget就显示在了Launcher中。
AppWidgetService通过IAppWidgetService提供各种服务;AppWidgetHost和AppWidgetManager封装了这个方法的使用。AppWidgetHost角色通过AppWidgetHost和AppWidgetManager使用AppWidgetService的服务;AppWidgetProvider角色通过AppWidgetManager使用AppWidgetService的服务,AppWidgetService直接操作或通知AppWidgetProvider。
Section#2中的内部数据结构mInstalledProviders, mHosts和mAppWidgetIds对于处理这些机制至关重要。
本章结合典型场景来看AppWidgetService通过AppWidgetHost和AppWidgetManager提供的各种功能的实现。
看AppWidgetService提供的服务的实现,可以从前面所有本系列文章中的时序图中,沿着所有AppWidgetManager和AppWidgetHost对象生命线的看。主要有:
AppWidgetHost.startListening()
AppWidgetHost向AppWidget系统中注册。
AppWidgetHost.allocateAppWidgetId()
AppWidgetHost申请AppWidgetId。AppWidgetHost(e.g.Launcher)选取AppWidgetProvider之前,先向AppWidget系统申请,《Android中选取并绑定AppWidget》#1中描述这一场景。Launcher中第一次从配置中读取AppWidget信息,也要先申请AppWidgetId,《Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色》#2中描述这一场景。实现在AppWidgetService中,本文4.2讲述。
AppWidgetManager.getInstalledProviders()
获得系统中所有的AppWidgetProvider。AppWidgetPicker列举系统中所有的AppWidgetProvider,《Android中选取并绑定AppWidget》#3中描述这一场景。实现在AppWidgetService中,本文4.3讲述。
AppWidgetManager.bindAppWidgetId()
绑定AppWidgetId与AppWidgetProvider。AppWidgetPicker中用户选择了某个AppWidgetProvider,用申请到的AppWidgetId与之绑定。《Android中选取并绑定AppWidget》#4中描述这一场景。Launcher中第一次从配置中读取AppWidget信息,也要先申请AppWidgetId,《Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色》#2中描述这一场景。实现在AppWidgetService中,本文4.4讲述。
AppWidgetManager.getAppWidgetInfo()
通过AppWidgetId获取与之绑定的AppWidgetProviderInfo。Android中选取并绑定AppWidget之后,通过AppWidgetId就可以获取与之绑定的AppWidgetProviderInfo。选取之后的Launcher中有使用的示例,《Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色》#1和#3.4中描述这一场景。本文4.5讲述AppWidgetService中的实现。
IAppWidgetService.getAppWidgetViews()
获得AppWidgetProvider提供的RemoteViews。AppWidgetHost创建AppWidgetHostView之后,如果AppWidgetProvider已经提供了RemoteViews,这里可以获取出来,设置给AppWidgetHostView。《Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色》#1图二中描述这一场景。本文4.6讲述AppWidgetService中的实现。
AppWidgetManager.updateAppWidget()
设置AppWidgetProvider提供的RemoteViews。AppWidgetProvider创建了RemoteViews之后,通过这个接口告知AppWidgetServic,《Android中AppWidget的分析与应用:AppWidgetProvider》#5图三中描述这一场景。本文4.7讲述AppWidgetService中的实现。
原型:publicint[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,List<RemoteViews> updatedViews)
AppWidgetHost有IAppWidgetHost(通过Callbacks)的实现mCallbacks:AppWidgetHost.Callbacks。在AppWidgetHost.startListening()中,AppWidgetHost通过IAppWidgetService把IAppWidgetHost,HostId等信息注册到AppWidgetService中。
从3.3(2)可以看具体实现。mHosts里面存放注册的AppWidgetHost;mHosts.instances里存放的是与该Host绑定的信息:AppWidgetId。AppWidgetId的views存储的是Provider创建并提供的RemoteViews,此时可能已经有内容,把它加入到AppWidgetHost传入的参数中。AppWidgetHostView如果已经存在,AppWidgetHost会通过AppWidgetHostView.updateAppWidget()用RemoteViews更新AppWidgetHostView。
原型:publicint allocateAppWidgetId(String packageName, int hostId)
实现:
生成一个Id:int;
通过packageName和hostId检索mHosts中的AppWidgetService.Host对象;
创建AppWidgetId对象,把appWidgetId和hostId保存起来,并把它加入到Host的instances中以及mAppWidgetIds: AppWidgetService.AppWidgetId中。
原型:publicList<AppWidgetProviderInfo> getInstalledProviders()
实现:系统初始化时,所有的AppWidgetProvider的信息都已经被检索出来并放入了mInstalledProviders:AppWidgetService.Provider。这里直接把mInstalledProviders里的info组成链表即可。
原型:publicvoid bindAppWidgetId(int appWidgetId, ComponentName provider)
实现:
通过appWidgetId检索mAppWidgetIds: AppWidgetService.AppWidgetId中的AppWidgetId对象;
通过provider检索mInstalledProviders:AppWidgetService.Provider中的Provider对象;
通过AppWidgetId的provider和Provider的instances,把Provider对象和AppWidgetId对象关联起来;
向AppWidgetProvider发送Enable和Update广播。
原型:publicAppWidgetProviderInfo getAppWidgetInfo(int appWidgetId)
实现:
通过appWidgetId检索mAppWidgetIds: AppWidgetService.AppWidgetId中的AppWidgetId对象;
把AppWidgetId对象provider里的info返回。
原型:publicRemoteViews getAppWidgetViews(int appWidgetId)
实现:
通过appWidgetId检索mAppWidgetIds: AppWidgetService.AppWidgetId中的AppWidgetId对象;
把AppWidgetId对象里的views:RemoteViews返回。
原型:publicvoid updateAppWidgetProvider(ComponentName provider, RemoteViews views)
通过参数<provider>检索mInstalledProviders:AppWidgetService.Provider中的Provider对象;
通过Provider对象的instances得到ArrayList<AppWidgetId>,也就是所有与该Provider关联的对象;
对ArrayList<AppWidgetId>里所有的对象,通过host的callback接口,通知AppWidgetHost,用RemoteViews更新AppWidgetHostView。
通过这一系列的相关文章,可获得与本文关联的信息:
简要描述AppWidget系统框架,并对这里的组成元素做简要的阐述。
描述由Launcher作为AppWidgetHost发起,Settings中AppWidgetPickActivity实现的选取并绑定AppWidgetProvider的过程。
Android中AppWidget的分析与应用:AppWidgetProvider
以SettingsAppWidgetProvider为例,通过对AppWidgetProvider内部实现机制的描述,使读者深刻理解开发AppWidgetProvider所要注意的地方。
Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色
以Launcher为例,通过它作为AppWidgetHost角色所参与AppWidget实现过程的描述,使读者理解AppWidgetHost如何实现。
结合AppWidget的应用场景,分析Android中RemoteViews的内部具体实现。
Android AppWidget的核心之AppWidgetService
AppWidgetService提供的服务,以及内部实现。