最近在看一些widget的东西,发现很是郁闷,只看sdk,都一些介绍性的东西,怎么配置,建什么provider,providerinfo,remoteviews,之类,越看感觉越不爽,没有掌控权,所以决定看看框架是怎么组织widget的。废话少说,从源码看起。
和大多数后台服务一样,AppWidgetService也是在SystemServer中初始化的,代码片段如下:
public class SystemServer
{
/**
* This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);
public static void main(String[] args) {
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server");
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
System.loadLibrary("android_servers");
init1(args);
}
public static final void init2() {
Log.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}
由于这篇不是介绍android的启动过程,故简单地说:
Zygote 会调用init1()来初始化系统,init1()主要是启动一些本地服务,例如surfaceflinger,AudioFlinger之类比较底层的服务
然后会调用init2()来启动一些android特有的一些服务。红色已经标出,init2()开启了一个叫做ServerThread的线程。
在ServerThread的run方法中可以找到AppwidgetService的初始化过程,代码片段如下:
appWidget = new AppWidgetService(context);
ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
--------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
// started launching the initial applications), for us to complete our
// initialization.
((ActivityManagerService)ActivityManagerNative.getDefault())
.systemReady(new Runnable() {
public void run() {
Log.i(TAG, "Making services ready");
if (batteryF != null) batteryF.systemReady();
if (connectivityF != null) connectivityF.systemReady();
if (dockF != null) dockF.systemReady();
Watchdog.getInstance().start();
// It is now okay to let the various system services start their
// third party code...
if (appWidgetF != null) appWidgetF.systemReady(safeMode);
if (wallpaperF != null) wallpaperF.systemReady();
if (immF != null) immF.systemReady();
}
});
--------------------------------------------------------------------------------------------
if (appWidgetF != null) appWidgetF.systemReady(safeMode);
这段代码的执行时在所有的apk都加载到系统中以后才触发的。下面是systemReady()的代码:
public void systemReady(boolean safeMode) {
mSafeMode = safeMode;
loadAppWidgetList();
loadStateLocked();
// Register for the boot completed broadcast, so we can send the
// ENABLE broacasts. If we try to send them now, they time out,
// because the system isn't ready to handle them yet.
mContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
// Register for configuration changes so we can update the names
// of the widgets when the locale changes.
mContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
// Register for broadcasts about package install, etc., so we can
// update the provider list.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
}
AppWidgetService的systemReady()过程很简单,就是把符合条件的widget的信息通过PackageManager加载进来,然后再通过AlarmManager定时地更新widget。
具体过程来看代码,首先是loadAppWidgetList()方法:
void loadAppWidgetList() {
PackageManager pm = mPackageManager;
//创建ACTION_APPWIDGET_UPDATE类型的intent
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
//根据intent来查询到与之匹配的broadcastReceivers,其实也就是AppWidgetProvider,查询方法queryBroadcastReceivers比较复杂,这里不再讨论,主要就是去读manefest文件,将信息记录到ResolveInfo中
List
PackageManager.GET_META_DATA);
final int N = broadcastReceivers.size();
for (int i=0; i
//将信息记录到mInstalledProviders中,以便后面的操作
addProviderLocked(ri);
}
}
下面来看mBroadcastReceiver,它注册了四个相关的IntentFilter ,初始化的时候只看.ACTION_BOOT_COMPLETED,具体代码如下:
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//Log.d(TAG, "received " + action);
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
sendInitialBroadcasts();
} else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-------------------------------------------------------------------------------------------------------
void sendInitialBroadcasts() {
synchronized (mAppWidgetIds) {
final int N = mInstalledProviders.size();
for (int i=0; i
if (p.instances.size() > 0) {
sendEnableIntentLocked(p);
int[] appWidgetIds = getAppWidgetIds(p);
sendUpdateIntentLocked(p, appWidgetIds);
registerForBroadcastsLocked(p, appWidgetIds);
}
}
}
}
------------------------------------------------------------------------------------------------
可以很清楚地看到在这个sendInitialBroadcasts中依次遍历mInstalledProviders,对其调用了三个方法,sendEnableIntentLocked发送了ACTION_APPWIDGET_ENABLED的广播,sendUpdateIntentLocked发送了ACTION_APPWIDGET_UPDATE的广播,registerForBroadcastsLocked则根据用户在manifest中设置的updatePeriodMillis时间定时更新(也是通过intent的方式)
到此框架层关于AppWidgetService的初始化过程就结束了,已经很好地解析了为什么会桌面widget会定时收到ACTION_APPWIDGET_UPDATE的广播。
流程很简单,不过如果深入,细节还是比较繁琐的。