前言
欢迎大家我分享和推荐好用的代码段~~
声明
欢迎转载,但请保留文章原始出处:
CSDN:http://www.csdn.net
雨季o莫忧离:http://blog.csdn.net/luckkof
正文
本文讲述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的外部接口
AppWidgetService通过IAppWidgetService这个标准的AIDL方式向外界提供服务。
AppWidgetHost提供了Host端操作所需要的方法,而这些方式实际是通过AIDL方式调用IAppWidgetService实现的;AppWidgetManager提供了Host端和Provider端操作所需要的方法,而这些方式也是通过AIDL方式调用IAppWidgetService实现的。
二、AppWidgetService的内部数据结构——静态分析
下图是AppWidgetService中的数据结构。
图二、AppWidgetService内部数据结构
mInstalledProviders:ArrayList<AppWidgetService.Provider>记录所有已经安装的AppWidgetProvider【《Android中AppWidget的分析与应用:AppWidgetProvider》中已经描述了单个AppWidgetProvider被AppWidget系统所识别的过程;本文Section#3.1 (1)会描述加载所有系统中的AppWidgetProvider的过程】。其中,
- uid: int记录该AppWidgetProvider运行所在进程的uid;
- info: AppWidgetProviderInfo记录AppWidgetProvider的信息;
- instances: ArrayList<AppWidgetId>记录与该AppWidgetProvider绑定的信息(可与多个Host绑定);
- broadcast: PendingIntent该Provider需要被周期性刷新时(updatePeriodMillis属性值大于0),周期性产生AppWidgetManager.ACTION_APPWIDGET_UPDATE来更新Provider;
- zombie记录该AppWidgetProvider状态是否僵死,因为是管理多个进程的,如果Provider所在的进程僵死,对与之绑定的Host也要做处理。
- tag: int保存状态时记录index值。
mHosts: ArrayList<AppWidgetService.Host>记录AppWidgetHost信息。其中,
- uid: int记录该AppWidgetHost运行所在进程的uid;
- hostId: int记录AppWidgetHost的Id,由AppWidgetHost注册时指定;
- packageName: String记录
- instances: ArrayList<AppWidgetId>记录与该AppWidgetHost绑定的信息(可与多个Provider绑定);
- callbacks: IAppWidgetHost用来在与该Host绑定的Provider变化时候通知Host。
- zombie记录该AppWidgetHost状态是否僵死,因为是管理多个进程的,如果Host所在的进程僵死,对与之绑定的Provider也要做处理。
- tag: int保存状态时记录index值。
mAppWidgetIds:ArrayList<AppWidgetService.AppWidgetId>记录所有Provider与Host绑定的信息。其中,
- appWidgetId: int记录绑定好的id,由allocateAppWidgetId()申请;
- provider: AppWidgetService.Provider绑定的Provider端;
- host: AppWidgetService.Host绑定的Host 端;
- views: RemoteViews 记录Provider端创建的RemoteViews,会用之通知Host端显示Provider端提供的内容。
现在看这些属性可能比较空泛,在后续的分析过程中再回头看这些属性的才能充分理解其含义。
三、AppWidgetService初始化
AppWidgetService运行于system_process进程中,其初始化有两个过程:
- systemReady时的初始化;
- 收到ACTION_BOOT_COMPLETED之后的初始化。
3.1 AppWidgetService.systemReady()初始化
在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>
- <ppkgppkg="com.android.settings"
- cl="com.android.settings.widget.SettingsAppWidgetProvider"/>
- <hpkghpkg="com.android.launcher" id="400" />
- <gidgid="1" h="0" p="0" />
- </gs>
其中的,
- 节点p对应AppWidgetProvider。pkg和cl分别是packageName和className。
- 节点h对应AppWidgetHost。pkg是packageName;id是HostId。
- 节点g是Provider和Host的绑定关系。id是其标志,在绑定之前通过allocateAppWidgetId时申请;h对应AppWidgetHost的index;p对应AppWidgetProvider的index。
下面看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的安装与缷载
3.2 系统启动完成之后AppWidgetService的初始化工作
Android系统启动完成之后,会发出Intent.ACTION_BOOT_COMPLETED广播。
AppWidgetService在Intent.ACTION_BOOT_COMPLETED广播的Receiver中sendInitialBroadcasts()内处理下列事项:
检索mInstalledProviders获取所有的Provider,通过Provider.instances获得已经绑定的那些AppWidgetProvider。
对这些Provider,
- 发出AppWidgetManager.ACTION_APPWIDGET_ENABLED广播。
- 发出AppWidgetManager.ACTION_APPWIDGET_UPDATE广播。
- 根据Provider的配置如果updatePeriodMillis大于0,注册定时更新广播。会向该Provider周期性发送AppWidgetManager.ACTION_APPWIDGET_UPDATE广播。
3.3 整个初始化过程
上述的AppWidgetService的初始化工作是AppWidget系统初始化的一部分,还有AppWidgetHost和AppWidgetProvider的参与的初始化过程。
下面是完整的过程:
(1)AppWidgetService.systemReady()初始化
本文Section#3.1,完成:
- 从PackageManager获取所有系统中所有的AppWidgetProvider,初始化mInstalledProviders;
- 从文件/data/system/appwidgets.xml中读取已经绑定的AppWidget,初始化mHosts和mAppWidgetIds;
- 注册所需的Broadcast Receivers。
(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;
- }
- }
- 通过lookupOrAddHostLocked()检索mHosts:ArrayList<AppWidgetService.Host>中是否已经有Host对象。如果不存在则创建新的Host对象,并加入到mHosts中;[Line#5]
- 把AppWidgetHost的Callback保存到Host.callbacks里。这里只是AppWidgetHost在Service的远端代理;[Line#6]
- Host.instances里保存的是与Host绑定关系,从中:
- 获得AppWidgetId;
- 把已经存在的RemoteViews加入到AppWidgetHost端的RemoteViews的List中。
返回所有与该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》中具体描述里这一过程。
- 在onEnabled()方法中进行一些初始化操作;
- 在onUpdate()方法中创建RemoteViews布局对象;并通过AppWidgetManager.updateAppWidget(intappWidgetId, RemoteViews remoteViews)方法通知AppWidgetService用RemoteViews对象更新appWidgetId所对应的AppWidgetHost.
AppWidgetService接收到了appWidgetId和RemoteViews后,通过appWidgetId查找Provider与Host的绑定关系,并通过IAppWidgetHost的Callback通知Host用RemoteViews中的布局更新到AppWidgetHostView布局对象中。
这样,AppWidget就显示在了Launcher中。
四、AppWidgetService的实现
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中的实现。
4.1 AppWidgetHost的注册
原型: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。
4.2 申请AppWidgetId
原型:publicint allocateAppWidgetId(String packageName, int hostId)
实现:
生成一个Id:int;
通过packageName和hostId检索mHosts中的AppWidgetService.Host对象;
创建AppWidgetId对象,把appWidgetId和hostId保存起来,并把它加入到Host的instances中以及mAppWidgetIds: AppWidgetService.AppWidgetId中。
4.3 获得所有的AppWidgetProvider列表
原型:publicList<AppWidgetProviderInfo> getInstalledProviders()
实现:系统初始化时,所有的AppWidgetProvider的信息都已经被检索出来并放入了mInstalledProviders:AppWidgetService.Provider。这里直接把mInstalledProviders里的info组成链表即可。
4.4 绑定AppWidget
原型: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广播。
4.5 获取指定的AppWidgetProviderInfo
原型:publicAppWidgetProviderInfo getAppWidgetInfo(int appWidgetId)
实现:
通过appWidgetId检索mAppWidgetIds: AppWidgetService.AppWidgetId中的AppWidgetId对象;
把AppWidgetId对象provider里的info返回。
4.6 获取RemoteViews
原型:publicRemoteViews getAppWidgetViews(int appWidgetId)
实现:
通过appWidgetId检索mAppWidgetIds: AppWidgetService.AppWidgetId中的AppWidgetId对象;
把AppWidgetId对象里的views:RemoteViews返回。
4.7 提供RemoteViews
原型:publicvoid updateAppWidgetProvider(ComponentName provider, RemoteViews views)
通过参数<provider>检索mInstalledProviders:AppWidgetService.Provider中的Provider对象;
通过Provider对象的instances得到ArrayList<AppWidgetId>,也就是所有与该Provider关联的对象;
对ArrayList<AppWidgetId>里所有的对象,通过host的callback接口,通知AppWidgetHost,用RemoteViews更新AppWidgetHostView。