2011.8.19----(android中桌面widget的后台管理服务AppWidgetService初探)

来源:互联网 发布:淘宝评论福利怎么领取 编辑:程序博客网 时间:2024/06/08 09:38

最近在看一些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<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
                PackageManager.GET_META_DATA);

        final int N = broadcastReceivers.size();
        for (int i=0; i<N; i++) {
            ResolveInfo ri = broadcastReceivers.get(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<N; i++) {
                Provider p = mInstalledProviders.get(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的广播。

流程很简单,不过如果深入,细节还是比较繁琐的。

 

 


 

 

原创粉丝点击